Merge "MediaPlayer2: remove unused methods"
diff --git a/Android.bp b/Android.bp
index 704ec87..9645ba6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -113,6 +113,7 @@
         "core/java/android/content/IOnPrimaryClipChangedListener.aidl",
         "core/java/android/content/IRestrictionsManager.aidl",
         "core/java/android/content/ISyncAdapter.aidl",
+        "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",
         "core/java/android/content/ISyncContext.aidl",
         "core/java/android/content/ISyncServiceAdapter.aidl",
         "core/java/android/content/ISyncStatusObserver.aidl",
@@ -243,6 +244,7 @@
         "core/java/android/os/storage/IStorageEventListener.aidl",
         "core/java/android/os/storage/IStorageShutdownObserver.aidl",
         "core/java/android/os/storage/IObbActionListener.aidl",
+        "core/java/android/security/IConfirmationPromptCallback.aidl",
         "core/java/android/security/IKeystoreService.aidl",
         "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
         "core/java/android/service/autofill/IAutoFillService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 0035e22..70add65 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6938,7 +6938,7 @@
     ctor public BackupManager(android.content.Context);
     method public void dataChanged();
     method public static void dataChanged(java.lang.String);
-    method public int requestRestore(android.app.backup.RestoreObserver);
+    method public deprecated int requestRestore(android.app.backup.RestoreObserver);
   }
 
   public class FileBackupHelper implements android.app.backup.BackupHelper {
@@ -8767,6 +8767,7 @@
     method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
     method public void onSyncCanceled();
     method public void onSyncCanceled(java.lang.Thread);
+    method public boolean onUnsyncableAccount();
     field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
   }
 
@@ -11206,6 +11207,7 @@
     field public static final java.lang.String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
     field public static final java.lang.String FEATURE_SIP = "android.software.sip";
     field public static final java.lang.String FEATURE_SIP_VOIP = "android.software.sip.voip";
+    field public static final java.lang.String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
@@ -22100,6 +22102,7 @@
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
+    method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
     method public int getNotificationMarkerPosition();
     method public int getPositionNotificationPeriod();
@@ -22148,6 +22151,14 @@
     method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
   }
 
+  public static final class AudioRecord.MetricsConstants {
+    field public static final java.lang.String CHANNELS = "android.media.audiorecord.channels";
+    field public static final java.lang.String ENCODING = "android.media.audiorecord.encoding";
+    field public static final java.lang.String LATENCY = "android.media.audiorecord.latency";
+    field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
+    field public static final java.lang.String SOURCE = "android.media.audiorecord.source";
+  }
+
   public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
     method public abstract void onMarkerReached(android.media.AudioRecord);
     method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -22207,6 +22218,7 @@
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
     method public static float getMaxVolume();
+    method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
     method protected deprecated int getNativeFrameCount();
@@ -22287,6 +22299,14 @@
     method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
   }
 
+  public static final class AudioTrack.MetricsConstants {
+    field public static final java.lang.String CHANNELMASK = "android.media.audiorecord.channelmask";
+    field public static final java.lang.String CONTENTTYPE = "android.media.audiotrack.type";
+    field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
+    field public static final java.lang.String STREAMTYPE = "android.media.audiotrack.streamtype";
+    field public static final java.lang.String USAGE = "android.media.audiotrack.usage";
+  }
+
   public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
     method public abstract void onMarkerReached(android.media.AudioTrack);
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
@@ -23230,6 +23250,7 @@
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
     method public int getMaxHdcpLevel();
     method public int getMaxSessionCount();
+    method public android.os.PersistableBundle getMetrics();
     method public int getOpenSessionCount();
     method public byte[] getPropertyByteArray(java.lang.String);
     method public java.lang.String getPropertyString(java.lang.String);
@@ -23317,6 +23338,44 @@
     method public java.lang.String getDiagnosticInfo();
   }
 
+  public static final class MediaDrm.MetricsConstants {
+    field public static final java.lang.String CLOSE_SESSION_ERROR_COUNT = "drm.mediadrm.close_session.error.count";
+    field public static final java.lang.String CLOSE_SESSION_ERROR_LIST = "drm.mediadrm.close_session.error.list";
+    field public static final java.lang.String CLOSE_SESSION_OK_COUNT = "drm.mediadrm.close_session.ok.count";
+    field public static final java.lang.String EVENT_KEY_EXPIRED_COUNT = "drm.mediadrm.event.KEY_EXPIRED.count";
+    field public static final java.lang.String EVENT_KEY_NEEDED_COUNT = "drm.mediadrm.event.KEY_NEEDED.count";
+    field public static final java.lang.String EVENT_PROVISION_REQUIRED_COUNT = "drm.mediadrm.event.PROVISION_REQUIRED.count";
+    field public static final java.lang.String EVENT_SESSION_RECLAIMED_COUNT = "drm.mediadrm.event.SESSION_RECLAIMED.count";
+    field public static final java.lang.String EVENT_VENDOR_DEFINED_COUNT = "drm.mediadrm.event.VENDOR_DEFINED.count";
+    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_COUNT = "drm.mediadrm.get_device_unique_id.error.count";
+    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_LIST = "drm.mediadrm.get_device_unique_id.error.list";
+    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_OK_COUNT = "drm.mediadrm.get_device_unique_id.ok.count";
+    field public static final java.lang.String GET_KEY_REQUEST_ERROR_COUNT = "drm.mediadrm.get_key_request.error.count";
+    field public static final java.lang.String GET_KEY_REQUEST_ERROR_LIST = "drm.mediadrm.get_key_request.error.list";
+    field public static final java.lang.String GET_KEY_REQUEST_OK_COUNT = "drm.mediadrm.get_key_request.ok.count";
+    field public static final java.lang.String GET_KEY_REQUEST_OK_TIME_MICROS = "drm.mediadrm.get_key_request.ok.average_time_micros";
+    field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_COUNT = "drm.mediadrm.get_provision_request.error.count";
+    field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_LIST = "drm.mediadrm.get_provision_request.error.list";
+    field public static final java.lang.String GET_PROVISION_REQUEST_OK_COUNT = "drm.mediadrm.get_provision_request.ok.count";
+    field public static final java.lang.String KEY_STATUS_EXPIRED_COUNT = "drm.mediadrm.key_status.EXPIRED.count";
+    field public static final java.lang.String KEY_STATUS_INTERNAL_ERROR_COUNT = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
+    field public static final java.lang.String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
+    field public static final java.lang.String KEY_STATUS_PENDING_COUNT = "drm.mediadrm.key_status_change.PENDING.count";
+    field public static final java.lang.String KEY_STATUS_USABLE_COUNT = "drm.mediadrm.key_status_change.USABLE.count";
+    field public static final java.lang.String OPEN_SESSION_ERROR_COUNT = "drm.mediadrm.open_session.error.count";
+    field public static final java.lang.String OPEN_SESSION_ERROR_LIST = "drm.mediadrm.open_session.error.list";
+    field public static final java.lang.String OPEN_SESSION_OK_COUNT = "drm.mediadrm.open_session.ok.count";
+    field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_key_response.error.count";
+    field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_key_response.error.list";
+    field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_COUNT = "drm.mediadrm.provide_key_response.ok.count";
+    field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS = "drm.mediadrm.provide_key_response.ok.average_time_micros";
+    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_provision_response.error.count";
+    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_provision_response.error.list";
+    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_OK_COUNT = "drm.mediadrm.provide_provision_response.ok.count";
+    field public static final java.lang.String SESSION_END_TIMES_MS = "drm.mediadrm.session_end_times_ms";
+    field public static final java.lang.String SESSION_START_TIMES_MS = "drm.mediadrm.session_start_times_ms";
+  }
+
   public static abstract interface MediaDrm.OnEventListener {
     method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
   }
@@ -23356,6 +23415,7 @@
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
+    method public long getSampleSize();
     method public long getSampleTime();
     method public int getSampleTrackIndex();
     method public final int getTrackCount();
@@ -36459,6 +36519,18 @@
     field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
+  public class SettingsSlicesContract {
+    field public static final java.lang.String AUTHORITY = "android.settings.slices";
+    field public static final android.net.Uri BASE_URI;
+    field public static final java.lang.String KEY_AIRPLANE_MODE = "airplane_mode";
+    field public static final java.lang.String KEY_BATTERY_SAVER = "battery_saver";
+    field public static final java.lang.String KEY_BLUETOOTH = "bluetooth";
+    field public static final java.lang.String KEY_LOCATION = "location";
+    field public static final java.lang.String KEY_WIFI = "wifi";
+    field public static final java.lang.String PATH_SETTING_ACTION = "action";
+    field public static final java.lang.String PATH_SETTING_INTENT = "intent";
+  }
+
   public class SyncStateContract {
     ctor public SyncStateContract();
   }
@@ -38248,7 +38320,6 @@
   }
 
   public class StrongBoxUnavailableException extends java.security.ProviderException {
-    ctor public StrongBoxUnavailableException();
   }
 
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
@@ -49857,7 +49928,9 @@
     ctor public TextClassification.Options();
     method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
+    method public java.util.Calendar getReferenceTime();
     method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+    method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
   }
@@ -49882,7 +49955,10 @@
     field public static final int ENTITY_PRESET_NONE = 1; // 0x1
     field public static final android.view.textclassifier.TextClassifier NO_OP;
     field public static final java.lang.String TYPE_ADDRESS = "address";
+    field public static final java.lang.String TYPE_DATE = "date";
+    field public static final java.lang.String TYPE_DATE_TIME = "datetime";
     field public static final java.lang.String TYPE_EMAIL = "email";
+    field public static final java.lang.String TYPE_FLIGHT_NUMBER = "flight";
     field public static final java.lang.String TYPE_OTHER = "other";
     field public static final java.lang.String TYPE_PHONE = "phone";
     field public static final java.lang.String TYPE_UNKNOWN = "";
diff --git a/api/system-current.txt b/api/system-current.txt
index 10ce028..6be004c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -361,6 +361,7 @@
     method public byte[] getMetadata();
     method public boolean removeConfiguration(long);
     method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+    field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
     field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
     field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
@@ -450,7 +451,7 @@
     method public java.lang.String[] listAllTransports();
     method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
     method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int);
-    method public int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
+    method public deprecated int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
     method public deprecated java.lang.String selectBackupTransport(java.lang.String);
     method public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
     method public void setAutoRestore(boolean);
@@ -1043,8 +1044,10 @@
 package android.content.pm.dex {
 
   public class ArtManager {
-    method public boolean isRuntimeProfilingEnabled();
-    method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler);
+    method public boolean isRuntimeProfilingEnabled(int);
+    method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback);
+    field public static final int PROFILE_APPS = 0; // 0x0
+    field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1
     field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1
     field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2
     field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0
@@ -2074,21 +2077,21 @@
     method public abstract int cancel();
     method public abstract void cancelAnnouncement();
     method public abstract void close();
-    method public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
+    method public abstract deprecated int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
     method public android.hardware.radio.ProgramList getDynamicProgramList(android.hardware.radio.ProgramList.Filter);
     method public abstract boolean getMute();
     method public java.util.Map<java.lang.String, java.lang.String> getParameters(java.util.List<java.lang.String>);
-    method public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
+    method public abstract deprecated int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
     method public abstract deprecated java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
     method public abstract boolean hasControl();
     method public abstract deprecated boolean isAnalogForced();
-    method public abstract boolean isAntennaConnected();
+    method public abstract deprecated boolean isAntennaConnected();
     method public boolean isConfigFlagSet(int);
     method public boolean isConfigFlagSupported(int);
     method public abstract int scan(int, boolean);
     method public abstract deprecated void setAnalogForced(boolean);
     method public void setConfigFlag(int, boolean);
-    method public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
+    method public abstract deprecated int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
     method public abstract int setMute(boolean);
     method public java.util.Map<java.lang.String, java.lang.String> setParameters(java.util.Map<java.lang.String, java.lang.String>);
     method public abstract boolean startBackgroundScan();
@@ -2097,13 +2100,13 @@
     method public abstract void tune(android.hardware.radio.ProgramSelector);
     field public static final int DIRECTION_DOWN = 1; // 0x1
     field public static final int DIRECTION_UP = 0; // 0x0
-    field public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
-    field public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
-    field public static final int ERROR_CANCELLED = 2; // 0x2
-    field public static final int ERROR_CONFIG = 4; // 0x4
-    field public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0
-    field public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3
-    field public static final int ERROR_SERVER_DIED = 1; // 0x1
+    field public static final deprecated int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
+    field public static final deprecated int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
+    field public static final deprecated int ERROR_CANCELLED = 2; // 0x2
+    field public static final deprecated int ERROR_CONFIG = 4; // 0x4
+    field public static final deprecated int ERROR_HARDWARE_FAILURE = 0; // 0x0
+    field public static final deprecated int ERROR_SCAN_TIMEOUT = 3; // 0x3
+    field public static final deprecated int ERROR_SERVER_DIED = 1; // 0x1
   }
 
   public static abstract class RadioTuner.Callback {
@@ -2111,15 +2114,16 @@
     method public void onAntennaState(boolean);
     method public void onBackgroundScanAvailabilityChange(boolean);
     method public void onBackgroundScanComplete();
-    method public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
+    method public deprecated void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
     method public void onControlChanged(boolean);
     method public void onEmergencyAnnouncement(boolean);
-    method public void onError(int);
+    method public deprecated void onError(int);
     method public deprecated void onMetadataChanged(android.hardware.radio.RadioMetadata);
     method public void onParametersUpdated(java.util.Map<java.lang.String, java.lang.String>);
     method public void onProgramInfoChanged(android.hardware.radio.RadioManager.ProgramInfo);
     method public void onProgramListChanged();
     method public void onTrafficAnnouncement(boolean);
+    method public void onTuneFailed(int, android.hardware.radio.ProgramSelector);
   }
 
 }
@@ -5196,10 +5200,6 @@
 
 package android.view {
 
-  public abstract class Window {
-    method public void setDisableWallpaperTouchEvents(boolean);
-  }
-
   public abstract interface WindowManager implements android.view.ViewManager {
     method public abstract android.graphics.Region getCurrentImeTouchRegion();
   }
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index eabbb96..565b092 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -137,7 +137,7 @@
 
 LOCAL_MODULE_CLASS := EXECUTABLES
 
-LOCAL_INIT_RC := statsd.rc
+#LOCAL_INIT_RC := statsd.rc
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 77b156f8..c990296 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -21,7 +21,7 @@
 option java_package = "com.android.os";
 option java_outer_classname = "AtomsProto";
 
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
 
 /**
  * The master atom class. This message defines all of the available
@@ -44,7 +44,7 @@
         BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
         BleScanResultReceived ble_scan_result_received = 4;
         SensorStateChanged sensor_state_changed = 5;
-        GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested
+        GpsScanStateChanged gps_scan_state_changed = 6;
         SyncStateChanged sync_state_changed = 7;
         ScheduledJobStateChanged scheduled_job_state_changed = 8;
         ScreenBrightnessChanged screen_brightness_changed = 9;
@@ -185,9 +185,8 @@
 message UidProcessStateChanged {
     optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
 
-    // The state.
-    // TODO: Use the real (mapped) process states.
-    optional android.app.ProcessState state = 2;
+    // The state, from frameworks/base/core/proto/android/app/enums.proto.
+    optional android.app.ProcessStateEnum state = 2;
 }
 
 /**
diff --git a/core/java/Android.bp b/core/java/Android.bp
index afa08e6..f7c5c57 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -11,7 +11,8 @@
 // only used by key_store_service
 cc_library_shared {
     name: "libkeystore_aidl",
-    srcs: ["android/security/IKeystoreService.aidl"],
+    srcs: ["android/security/IKeystoreService.aidl",
+           "android/security/IConfirmationPromptCallback.aidl"],
     aidl: {
         export_aidl_headers: true,
         include_dirs: [
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f0ef49f..cd029c0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6330,8 +6330,6 @@
         } else {
             writer.print(prefix); writer.println("No AutofillManager");
         }
-
-        ResourcesManager.getInstance().dump(prefix, writer);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8035058..4d5ac6f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -28,7 +28,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.UriPermission;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -576,18 +575,68 @@
     /** @hide Process does not exist. */
     public static final int PROCESS_STATE_NONEXISTENT = 19;
 
-    // NOTE: If PROCESS_STATEs are added or changed, then new fields must be added
-    // to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must
+    // NOTE: If PROCESS_STATEs are added, then new fields must be added
+    // to frameworks/base/core/proto/android/app/enums.proto and the following method must
     // be updated to correctly map between them.
+    // However, if the current ActivityManager values are merely modified, no update should be made
+    // to enums.proto, to which values can only be added but never modified. Note that the proto
+    // versions do NOT have the ordering restrictions of the ActivityManager process state.
     /**
-     * Maps ActivityManager.PROCESS_STATE_ values to ProcessState enum.
+     * Maps ActivityManager.PROCESS_STATE_ values to enums.proto ProcessStateEnum value.
      *
      * @param amInt a process state of the form ActivityManager.PROCESS_STATE_
-     * @return the value of the corresponding ActivityManager's ProcessState enum.
+     * @return the value of the corresponding enums.proto ProcessStateEnum value.
      * @hide
      */
     public static final int processStateAmToProto(int amInt) {
-        return amInt * 100;
+        switch (amInt) {
+            case PROCESS_STATE_UNKNOWN:
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN;
+            case PROCESS_STATE_PERSISTENT:
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT;
+            case PROCESS_STATE_PERSISTENT_UI:
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
+            case PROCESS_STATE_TOP:
+                return AppProtoEnums.PROCESS_STATE_TOP;
+            case PROCESS_STATE_FOREGROUND_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
+            case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+            case PROCESS_STATE_IMPORTANT_FOREGROUND:
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            case PROCESS_STATE_IMPORTANT_BACKGROUND:
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
+            case PROCESS_STATE_TRANSIENT_BACKGROUND:
+                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
+            case PROCESS_STATE_BACKUP:
+                return AppProtoEnums.PROCESS_STATE_BACKUP;
+            case PROCESS_STATE_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_SERVICE;
+            case PROCESS_STATE_RECEIVER:
+                return AppProtoEnums.PROCESS_STATE_RECEIVER;
+            case PROCESS_STATE_TOP_SLEEPING:
+                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
+            case PROCESS_STATE_HEAVY_WEIGHT:
+                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
+            case PROCESS_STATE_HOME:
+                return AppProtoEnums.PROCESS_STATE_HOME;
+            case PROCESS_STATE_LAST_ACTIVITY:
+                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
+            case PROCESS_STATE_CACHED_ACTIVITY:
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
+            case PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+            case PROCESS_STATE_CACHED_RECENT:
+                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
+            case PROCESS_STATE_CACHED_EMPTY:
+                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
+            case PROCESS_STATE_NONEXISTENT:
+                return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+            default:
+                // ActivityManager process state (amInt)
+                // could not be mapped to an AppProtoEnums ProcessState state.
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
+        }
     }
 
     /** @hide The lowest process state number */
@@ -2686,17 +2735,22 @@
     /**
      * Permits an application to get the persistent URI permissions granted to another.
      *
-     * <p>Typically called by Settings.
+     * <p>Typically called by Settings or DocumentsUI, requires
+     * {@code GET_APP_GRANTED_URI_PERMISSIONS}.
      *
-     * @param packageName application to look for the granted permissions
+     * @param packageName application to look for the granted permissions, or {@code null} to get
+     * granted permissions for all applications
      * @return list of granted URI permissions
      *
      * @hide
      */
-    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) {
+    public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+            @Nullable String packageName) {
         try {
-            return getService().getGrantedUriPermissions(packageName,
-                    UserHandle.myUserId());
+            @SuppressWarnings("unchecked")
+            final ParceledListSlice<GrantedUriPermission> castedList = getService()
+                    .getGrantedUriPermissions(packageName, UserHandle.myUserId());
+            return castedList;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2705,7 +2759,7 @@
     /**
      * Permits an application to clear the persistent URI permissions granted to another.
      *
-     * <p>Typically called by Settings.
+     * <p>Typically called by Settings, requires {@code CLEAR_APP_GRANTED_URI_PERMISSIONS}.
      *
      * @param packageName application to clear its granted permissions
      *
diff --git a/core/java/android/app/GrantedUriPermission.aidl b/core/java/android/app/GrantedUriPermission.aidl
new file mode 100644
index 0000000..2734af0
--- /dev/null
+++ b/core/java/android/app/GrantedUriPermission.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/** @hide */
+parcelable GrantedUriPermission;
\ No newline at end of file
diff --git a/core/java/android/app/GrantedUriPermission.java b/core/java/android/app/GrantedUriPermission.java
new file mode 100644
index 0000000..9e84fe1
--- /dev/null
+++ b/core/java/android/app/GrantedUriPermission.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.UriPermission;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents an {@link UriPermission} granted to a package.
+ *
+ * {@hide}
+ */
+public class GrantedUriPermission implements Parcelable {
+
+    public final Uri uri;
+    public final String packageName;
+
+    public GrantedUriPermission(@NonNull Uri uri, @Nullable String packageName) {
+        this.uri = uri;
+        this.packageName = packageName;
+    }
+
+    @Override
+    public String toString() {
+        return packageName + ":" + uri;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(uri, flags);
+        out.writeString(packageName);
+    }
+
+    public static final Parcelable.Creator<GrantedUriPermission> CREATOR =
+            new Parcelable.Creator<GrantedUriPermission>() {
+                @Override
+                public GrantedUriPermission createFromParcel(Parcel in) {
+                    return new GrantedUriPermission(in);
+                }
+
+                @Override
+                public GrantedUriPermission[] newArray(int size) {
+                    return new GrantedUriPermission[size];
+                }
+            };
+
+    private GrantedUriPermission(Parcel in) {
+        uri = in.readParcelable(null);
+        packageName = in.readString();
+    }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 9c15562..5382e66 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ApplicationErrorReport;
 import android.app.ContentProviderHolder;
+import android.app.GrantedUriPermission;
 import android.app.IApplicationThread;
 import android.app.IActivityController;
 import android.app.IAppTask;
@@ -569,7 +570,7 @@
             in Rect tempDockedTaskInsetBounds,
             in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
     int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
-    // Gets the URI permissions granted to an arbitrary package.
+    // Gets the URI permissions granted to an arbitrary package (or all packages if null)
     // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
     // granted to another packages (instead of those granted to it).
     ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 26f4980..d24d4f3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -28,6 +28,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.dex.ArtManager;
 import android.content.pm.split.SplitDependencyLoader;
 import android.content.res.AssetManager;
 import android.content.res.CompatibilityInfo;
@@ -35,7 +36,6 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -49,13 +49,15 @@
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.LogPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayAdjustments;
+
 import com.android.internal.util.ArrayUtils;
+
 import dalvik.system.VMRuntime;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -749,13 +751,6 @@
         }
     }
 
-    // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
-    private static File getPrimaryProfileFile(String packageName) {
-        File profileDir = Environment.getDataProfilesDePackageDirectory(
-                UserHandle.myUserId(), packageName);
-        return new File(profileDir, "primary.prof");
-    }
-
     private void setupJitProfileSupport() {
         if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
             return;
@@ -783,10 +778,12 @@
             return;
         }
 
-        final File profileFile = getPrimaryProfileFile(mPackageName);
-
-        VMRuntime.registerAppInfo(profileFile.getPath(),
-                codePaths.toArray(new String[codePaths.size()]));
+        for (int i = codePaths.size() - 1; i >= 0; i--) {
+            String splitName = i == 0 ? null : mApplicationInfo.splitNames[i - 1];
+            String profileFile = ArtManager.getCurrentProfilePath(
+                    mPackageName, UserHandle.myUserId(), splitName);
+            VMRuntime.registerAppInfo(profileFile, new String[] {codePaths.get(i)});
+        }
 
         // Register the app data directory with the reporter. It will
         // help deciding whether or not a dex file is the primary apk or a
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b96e028..fb11272 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.content.res.CompatResources;
 import android.content.res.CompatibilityInfo;
@@ -35,7 +34,6 @@
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.LruCache;
 import android.util.Pair;
 import android.util.Slog;
 import android.view.Display;
@@ -43,13 +41,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.IndentingPrintWriter;
 
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Objects;
 import java.util.WeakHashMap;
 import java.util.function.Predicate;
@@ -65,7 +59,12 @@
      * Predicate that returns true if a WeakReference is gc'ed.
      */
     private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
-            weakRef -> weakRef == null || weakRef.get() == null;
+            new Predicate<WeakReference<Resources>>() {
+                @Override
+                public boolean test(WeakReference<Resources> weakRef) {
+                    return weakRef == null || weakRef.get() == null;
+                }
+            };
 
     /**
      * The global compatibility settings.
@@ -90,48 +89,6 @@
      */
     private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
 
-    private static class ApkKey {
-        public final String path;
-        public final boolean sharedLib;
-        public final boolean overlay;
-
-        ApkKey(String path, boolean sharedLib, boolean overlay) {
-            this.path = path;
-            this.sharedLib = sharedLib;
-            this.overlay = overlay;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = 1;
-            result = 31 * result + this.path.hashCode();
-            result = 31 * result + Boolean.hashCode(this.sharedLib);
-            result = 31 * result + Boolean.hashCode(this.overlay);
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ApkKey)) {
-                return false;
-            }
-            ApkKey other = (ApkKey) obj;
-            return this.path.equals(other.path) && this.sharedLib == other.sharedLib
-                    && this.overlay == other.overlay;
-        }
-    }
-
-    /**
-     * The ApkAssets we are caching and intend to hold strong references to.
-     */
-    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15);
-
-    /**
-     * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
-     * in our LRU cache. Bonus resources :)
-     */
-    private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
-
     /**
      * Resources and base configuration override associated with an Activity.
      */
@@ -303,41 +260,6 @@
         }
     }
 
-    private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
-            throws IOException {
-        final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
-        ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
-        if (apkAssets != null) {
-            return apkAssets;
-        }
-
-        // Optimistically check if this ApkAssets exists somewhere else.
-        final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
-        if (apkAssetsRef != null) {
-            apkAssets = apkAssetsRef.get();
-            if (apkAssets != null) {
-                mLoadedApkAssets.put(newKey, apkAssets);
-                return apkAssets;
-            } else {
-                // Clean up the reference.
-                mCachedApkAssets.remove(newKey);
-            }
-        }
-
-        // We must load this from disk.
-        if (overlay) {
-            final String idmapPath = "/data/resource-cache/"
-                    + path.substring(1).replace('/', '@')
-                    + "@idmap";
-            apkAssets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
-        } else {
-            apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
-        }
-        mLoadedApkAssets.put(newKey, apkAssets);
-        mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
-        return apkAssets;
-    }
-
     /**
      * Creates an AssetManager from the paths within the ResourcesKey.
      *
@@ -348,15 +270,13 @@
     */
     @VisibleForTesting
     protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
-        final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
+        AssetManager assets = new AssetManager();
 
         // resDir can be null if the 'android' package is creating a new Resources object.
         // This is fine, since each AssetManager automatically loads the 'android' package
         // already.
         if (key.mResDir != null) {
-            try {
-                apkAssets.add(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/));
-            } catch (IOException e) {
+            if (assets.addAssetPath(key.mResDir) == 0) {
                 Log.e(TAG, "failed to add asset path " + key.mResDir);
                 return null;
             }
@@ -364,10 +284,7 @@
 
         if (key.mSplitResDirs != null) {
             for (final String splitResDir : key.mSplitResDirs) {
-                try {
-                    apkAssets.add(loadApkAssets(splitResDir, false /*sharedLib*/,
-                            false /*overlay*/));
-                } catch (IOException e) {
+                if (assets.addAssetPath(splitResDir) == 0) {
                     Log.e(TAG, "failed to add split asset path " + splitResDir);
                     return null;
                 }
@@ -376,13 +293,7 @@
 
         if (key.mOverlayDirs != null) {
             for (final String idmapPath : key.mOverlayDirs) {
-                try {
-                    apkAssets.add(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/));
-                } catch (IOException e) {
-                    Log.w(TAG, "failed to add overlay path " + idmapPath);
-
-                    // continue.
-                }
+                assets.addOverlayPath(idmapPath);
             }
         }
 
@@ -391,77 +302,16 @@
                 if (libDir.endsWith(".apk")) {
                     // Avoid opening files we know do not have resources,
                     // like code-only .jar files.
-                    try {
-                        apkAssets.add(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/));
-                    } catch (IOException e) {
+                    if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
                         Log.w(TAG, "Asset path '" + libDir +
                                 "' does not exist or contains no resources.");
-
-                        // continue.
                     }
                 }
             }
         }
-
-        AssetManager assets = new AssetManager();
-        assets.setApkAssets(apkAssets.toArray(new ApkAssets[apkAssets.size()]),
-                false /*invalidateCaches*/);
         return assets;
     }
 
-    private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) {
-        int count = 0;
-        for (WeakReference<T> ref : collection) {
-            final T value = ref != null ? ref.get() : null;
-            if (value != null) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    /**
-     * @hide
-     */
-    public void dump(String prefix, PrintWriter printWriter) {
-        synchronized (this) {
-            IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
-            for (int i = 0; i < prefix.length() / 2; i++) {
-                pw.increaseIndent();
-            }
-
-            pw.println("ResourcesManager:");
-            pw.increaseIndent();
-            pw.print("cached apks: total=");
-            pw.print(mLoadedApkAssets.size());
-            pw.print(" created=");
-            pw.print(mLoadedApkAssets.createCount());
-            pw.print(" evicted=");
-            pw.print(mLoadedApkAssets.evictionCount());
-            pw.print(" hit=");
-            pw.print(mLoadedApkAssets.hitCount());
-            pw.print(" miss=");
-            pw.print(mLoadedApkAssets.missCount());
-            pw.print(" max=");
-            pw.print(mLoadedApkAssets.maxSize());
-            pw.println();
-
-            pw.print("total apks: ");
-            pw.println(countLiveReferences(mCachedApkAssets.values()));
-
-            pw.print("resources: ");
-
-            int references = countLiveReferences(mResourceReferences);
-            for (ActivityResources activityResources : mActivityResourceReferences.values()) {
-                references += countLiveReferences(activityResources.activityResources);
-            }
-            pw.println(references);
-
-            pw.print("resource impls: ");
-            pw.println(countLiveReferences(mResourceImpls.values()));
-        }
-    }
-
     private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
         Configuration config;
         final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
@@ -780,16 +630,28 @@
 
                 // We will create the ResourcesImpl object outside of holding this lock.
             }
+        }
 
-            // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
-            ResourcesImpl resourcesImpl = createResourcesImpl(key);
-            if (resourcesImpl == null) {
-                return null;
+        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+        ResourcesImpl resourcesImpl = createResourcesImpl(key);
+        if (resourcesImpl == null) {
+            return null;
+        }
+
+        synchronized (this) {
+            ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+            if (existingResourcesImpl != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+                            + " new impl=" + resourcesImpl);
+                }
+                resourcesImpl.getAssets().close();
+                resourcesImpl = existingResourcesImpl;
+            } else {
+                // Add this ResourcesImpl to the cache.
+                mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
             }
 
-            // Add this ResourcesImpl to the cache.
-            mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
-
             final Resources resources;
             if (activityToken != null) {
                 resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 963fc77..c525c89 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -54,6 +54,12 @@
             "android.app.extra.STATS_DIMENSIONS_VALUE";
 
     /**
+     * Broadcast Action: Statsd has started.
+     * Configurations and PendingIntents can now be sent to it.
+     */
+    public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+
+    /**
      * Constructor for StatsManagerClient.
      *
      * @hide
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 12f4483..6ec0969 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -252,6 +252,8 @@
     }
 
     /**
+     * @deprecated Since Android P app can no longer request restoring of its backup.
+     *
      * Restore the calling application from backup.  The data will be restored from the
      * current backup dataset if the application has stored data there, or from
      * the dataset used during the last full device setup operation if the current
@@ -269,6 +271,7 @@
      *
      * @return Zero on success; nonzero on error.
      */
+    @Deprecated
     public int requestRestore(RestoreObserver observer) {
         return requestRestore(observer, null);
     }
@@ -276,6 +279,8 @@
     // system APIs start here
 
     /**
+     * @deprecated Since Android P app can no longer request restoring of its backup.
+     *
      * Restore the calling application from backup.  The data will be restored from the
      * current backup dataset if the application has stored data there, or from
      * the dataset used during the last full device setup operation if the current
@@ -298,28 +303,12 @@
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public int requestRestore(RestoreObserver observer, BackupManagerMonitor monitor) {
-        int result = -1;
-        checkServiceBinder();
-        if (sService != null) {
-            RestoreSession session = null;
-            try {
-                IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
-                    null);
-                if (binder != null) {
-                    session = new RestoreSession(mContext, binder);
-                    result = session.restorePackage(mContext.getPackageName(), observer, monitor);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "restoreSelf() unable to contact service");
-            } finally {
-                if (session != null) {
-                    session.endRestoreSession();
-                }
-            }
-        }
-        return result;
+        Log.w(TAG, "requestRestore(): Since Android P app can no longer request restoring"
+                + " of its backup.");
+        return -1;
     }
 
     /**
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 2629929..5a1216b7 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.Trace;
 import android.util.Log;
 
@@ -166,6 +167,12 @@
 
     private class ISyncAdapterImpl extends ISyncAdapter.Stub {
         @Override
+        public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb)
+                throws RemoteException {
+            cb.onUnsyncableAccountDone(AbstractThreadedSyncAdapter.this.onUnsyncableAccount());
+        }
+
+        @Override
         public void startSync(ISyncContext syncContext, String authority, Account account,
                 Bundle extras) {
             if (ENABLE_LOG) {
@@ -374,6 +381,26 @@
     }
 
     /**
+     * Allows to defer syncing until all accounts are properly set up.
+     *
+     * <p>Called when a account / authority pair
+     * <ul>
+     * <li>that can be handled by this adapter</li>
+     * <li>{@link ContentResolver#requestSync(SyncRequest) is synced}</li>
+     * <li>and the account/provider {@link ContentResolver#getIsSyncable(Account, String) has
+     * unknown state (<0)}.</li>
+     * </ul>
+     *
+     * <p>This might be called on a different service connection as {@link #onPerformSync}.
+     *
+     * @return If {@code false} syncing is deferred. Returns {@code true} by default, i.e. by
+     *         default syncing starts immediately.
+     */
+    public boolean onUnsyncableAccount() {
+        return true;
+    }
+
+    /**
      * Perform a sync for this account. SyncAdapter-specific parameters may
      * be specified in extras, which is guaranteed to not be null. Invocations
      * of this method are guaranteed to be serialized.
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 4660527..0eb581e 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.os.Bundle;
 import android.content.ISyncContext;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
 
 /**
  * Interface used to control the sync activity on a SyncAdapter
@@ -26,6 +27,14 @@
  */
 oneway interface ISyncAdapter {
     /**
+     * Called before {@link #startSync}. This allows the adapter to defer syncs until the
+     * adapter is ready for the account
+     *
+     * @param cb If called back with {@code false} accounts are not synced.
+     */
+    void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb);
+
+    /**
      * Initiate a sync for this account. SyncAdapter-specific parameters may
      * be specified in extras, which is guaranteed to not be null.
      *
diff --git a/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
new file mode 100644
index 0000000..a738ac2
--- /dev/null
+++ b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * Callback for {@link ISyncAdapter#onUnsyncableAccount}
+ * @hide
+ */
+oneway interface ISyncAdapterUnsyncableAccountCallback {
+    /**
+     * Deliver the result for {@link ISyncAdapter#onUnsyncableAccount}
+     *
+     * @param isReady Iff {@code false} account is not synced.
+     */
+    void onUnsyncableAccountDone(boolean isReady);
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index df69d80..5a894c7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2604,6 +2604,14 @@
     public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device has a StrongBox hardware-backed Keystore.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_STRONGBOX_KEYSTORE =
+            "android.hardware.strongbox_keystore";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
@@ -4750,7 +4758,7 @@
 
             PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
             if ((flags & GET_SIGNATURES) != 0) {
-                PackageParser.collectCertificates(pkg, 0);
+                PackageParser.collectCertificates(pkg, false /* skipVerify */);
             }
             PackageUserState state = new PackageUserState();
             return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c705ef5..3bb812b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1311,6 +1311,24 @@
         }
     }
 
+    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+            throws PackageParserException {
+        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Invalid package file: " + apkPath);
+        }
+
+        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
+        // already exists in the AssetManager, addAssetPath will only return the cookie
+        // assigned to it.
+        int cookie = assets.addAssetPath(apkPath);
+        if (cookie == 0) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
+        }
+        return cookie;
+    }
+
     private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
             throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
@@ -1326,15 +1344,13 @@
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
 
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
+        Resources res = null;
         XmlResourceParser parser = null;
         try {
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
+            res = new Resources(assets, mMetrics, null);
             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
-            final Resources res = new Resources(assets, mMetrics, null);
 
             final String[] outError = new String[1];
             final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
@@ -1369,18 +1385,15 @@
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
 
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
         final Resources res;
         XmlResourceParser parser = null;
         try {
-            // This must always succeed, as the path has been added to the AssetManager before.
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-
-            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
             res = new Resources(assets, mMetrics, null);
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
             final String[] outError = new String[1];
             pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
@@ -1484,9 +1497,9 @@
      * populating {@link Package#mSigningDetails}. Also asserts that all APK
      * contents are signed correctly and consistently.
      */
-    public static void collectCertificates(Package pkg, @ParseFlags int parseFlags)
+    public static void collectCertificates(Package pkg, boolean skipVerify)
             throws PackageParserException {
-        collectCertificatesInternal(pkg, parseFlags);
+        collectCertificatesInternal(pkg, skipVerify);
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
             Package childPkg = pkg.childPackages.get(i);
@@ -1494,17 +1507,17 @@
         }
     }
 
-    private static void collectCertificatesInternal(Package pkg, @ParseFlags int parseFlags)
+    private static void collectCertificatesInternal(Package pkg, boolean skipVerify)
             throws PackageParserException {
         pkg.mSigningDetails = SigningDetails.UNKNOWN;
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
         try {
-            collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
+            collectCertificates(pkg, new File(pkg.baseCodePath), skipVerify);
 
             if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                 for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                    collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
+                    collectCertificates(pkg, new File(pkg.splitCodePaths[i]), skipVerify);
                 }
             }
         } finally {
@@ -1512,7 +1525,7 @@
         }
     }
 
-    private static void collectCertificates(Package pkg, File apkFile, @ParseFlags int parseFlags)
+    private static void collectCertificates(Package pkg, File apkFile, boolean skipVerify)
             throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
 
@@ -1522,7 +1535,7 @@
             minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
         }
         SigningDetails verified;
-        if ((parseFlags & PARSE_IS_SYSTEM_DIR) != 0) {
+        if (skipVerify) {
             // systemDir APKs are already trusted, save time by not verifying
             verified = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
                         apkPath, minSignatureScheme);
@@ -1582,9 +1595,9 @@
             int flags) throws PackageParserException {
         final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
 
+        ApkAssets apkAssets = null;
         XmlResourceParser parser = null;
         try {
-            final ApkAssets apkAssets;
             try {
                 apkAssets = fd != null
                         ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
@@ -1600,9 +1613,10 @@
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                 // TODO: factor signature related items out of Package object
                 final Package tempPkg = new Package((String) null);
+                final boolean skipVerify = (flags & PARSE_IS_SYSTEM_DIR) != 0;
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
                 try {
-                    collectCertificates(tempPkg, apkFile, flags);
+                    collectCertificates(tempPkg, apkFile, skipVerify);
                 } finally {
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
@@ -1620,7 +1634,7 @@
                     "Failed to parse " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            // TODO(b/72056911): Implement and call close() on ApkAssets.
+            IoUtils.closeQuietly(apkAssets);
         }
     }
 
diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java
index aa9c46e6..4129398 100644
--- a/core/java/android/content/pm/dex/ArtManager.java
+++ b/core/java/android/content/pm/dex/ArtManager.java
@@ -16,16 +16,22 @@
 
 package android.content.pm.dex;
 
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
 /**
  * Class for retrieving various kinds of information related to the runtime artifacts of
  * packages that are currently installed on the device.
@@ -43,6 +49,20 @@
     /** The snapshot failed because of an internal error (e.g. error during opening profiles). */
     public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2;
 
+    /** Constant used for applications profiles. */
+    public static final int PROFILE_APPS = 0;
+    /** Constant used for the boot image profile. */
+    public static final int PROFILE_BOOT_IMAGE = 1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "PROFILE_" }, value = {
+            PROFILE_APPS,
+            PROFILE_BOOT_IMAGE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProfileType {}
+
+
     private IArtManager mArtManager;
 
     /**
@@ -53,41 +73,59 @@
     }
 
     /**
-     * Snapshots the runtime profile for an apk belonging to the package {@code packageName}.
-     * The apk is identified by {@code codePath}. The calling process must have
-     * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+     * Snapshots a runtime profile according to the {@code profileType} parameter.
      *
-     * The result will be posted on {@code handler} using the given {@code callback}.
-     * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}.
+     * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot
+     * the profile for for an apk belonging to the package {@code packageName}.
+     * The apk is identified by {@code codePath}.
      *
-     * @param packageName the target package name
-     * @param codePath the code path for which the profile should be retrieved
+     * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot
+     * the profile for the boot image. In this case {@code codePath can be null}. The parameters
+     * {@code packageName} and {@code codePath} are ignored.
+     *u
+     * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+     *
+     * The result will be posted on the {@code executor} using the given {@code callback}.
+     * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}.
+     *
+     * This method will throw {@link IllegalStateException} if
+     * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
+     * {@code profileType}.
+     *
+     * @param profileType the type of profile that should be snapshot (boot image or app)
+     * @param packageName the target package name or null if the target is the boot image
+     * @param codePath the code path for which the profile should be retrieved or null if
+     *                 the target is the boot image
      * @param callback the callback which should be used for the result
-     * @param handler the handler which should be used to post the result
+     * @param executor the executor which should be used to post the result
      */
     @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
-    public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath,
-            @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) {
+    public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
+            @Nullable String codePath, @NonNull @CallbackExecutor Executor executor,
+            @NonNull SnapshotRuntimeProfileCallback callback) {
         Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath);
 
         SnapshotRuntimeProfileCallbackDelegate delegate =
-                new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper());
+                new SnapshotRuntimeProfileCallbackDelegate(callback, executor);
         try {
-            mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate);
+            mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Returns true if runtime profiles are enabled, false otherwise.
+     * Returns true if runtime profiles are enabled for the given type, false otherwise.
      *
      * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+     *
+     * @param profileType can be either {@link ArtManager#PROFILE_APPS}
+     *                    or {@link ArtManager#PROFILE_BOOT_IMAGE}
      */
     @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
-    public boolean isRuntimeProfilingEnabled() {
+    public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
         try {
-            return mArtManager.isRuntimeProfilingEnabled();
+            return mArtManager.isRuntimeProfilingEnabled(profileType);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -116,41 +154,24 @@
     }
 
     private static class SnapshotRuntimeProfileCallbackDelegate
-            extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub
-            implements Handler.Callback {
-        private static final int MSG_SNAPSHOT_OK = 1;
-        private static final int MSG_ERROR = 2;
+            extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub {
         private final ArtManager.SnapshotRuntimeProfileCallback mCallback;
-        private final Handler mHandler;
+        private final Executor mExecutor;
 
         private SnapshotRuntimeProfileCallbackDelegate(
-                ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) {
+                ArtManager.SnapshotRuntimeProfileCallback callback, Executor executor) {
             mCallback = callback;
-            mHandler = new Handler(looper, this);
+            mExecutor = executor;
         }
 
         @Override
-        public void onSuccess(ParcelFileDescriptor profileReadFd) {
-            mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget();
+        public void onSuccess(final ParcelFileDescriptor profileReadFd) {
+            mExecutor.execute(() -> mCallback.onSuccess(profileReadFd));
         }
 
         @Override
         public void onError(int errCode) {
-            mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget();
-        }
-
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SNAPSHOT_OK:
-                    mCallback.onSuccess((ParcelFileDescriptor) msg.obj);
-                    break;
-                case MSG_ERROR:
-                    mCallback.onError(msg.arg1);
-                    break;
-                default: return false;
-            }
-            return true;
+            mExecutor.execute(() -> mCallback.onError(errCode));
         }
     }
 
@@ -163,4 +184,27 @@
     public static String getProfileName(String splitName) {
         return splitName == null ? "primary.prof" : splitName + ".split.prof";
     }
+
+    /**
+     * Return the path to the current profile corresponding to given package and split.
+     *
+     * @hide
+     */
+    public static String getCurrentProfilePath(String packageName, int userId, String splitName) {
+        File profileDir = Environment.getDataProfilesDePackageDirectory(userId, packageName);
+        return new File(profileDir, getProfileName(splitName)).getAbsolutePath();
+    }
+
+    /**
+     * Return the snapshot profile file for the given package and profile name.
+     *
+     * KEEP in sync with installd dexopt.cpp.
+     * TODO(calin): inject the snapshot profile name from PM to avoid the dependency.
+     *
+     * @hide
+     */
+    public static File getProfileSnapshotFileForName(String packageName, String profileName) {
+        File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName);
+        return new File(profileDir, profileName  + ".snapshot");
+    }
 }
diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl
index 8cbb452..6abfdba 100644
--- a/core/java/android/content/pm/dex/IArtManager.aidl
+++ b/core/java/android/content/pm/dex/IArtManager.aidl
@@ -25,20 +25,34 @@
  */
 interface IArtManager {
     /**
-     * Snapshots the runtime profile for an apk belonging to the package {@param packageName}.
-     * The apk is identified by {@param codePath}. The calling process must have
-     * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+     * Snapshots a runtime profile according to the {@code profileType} parameter.
      *
-     * The result will be posted on {@param callback} with the profile being available as a
-     * read-only {@link android.os.ParcelFileDescriptor}.
-     */
-    oneway void snapshotRuntimeProfile(in String packageName,
-        in String codePath, in ISnapshotRuntimeProfileCallback callback);
-
-    /**
-     * Returns true if runtime profiles are enabled, false otherwise.
+     * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot
+     * the profile for for an apk belonging to the package {@code packageName}.
+     * The apk is identified by {@code codePath}.
+     *
+     * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot
+     * the profile for the boot image. In this case {@code codePath can be null}. The parameters
+     * {@code packageName} and {@code codePath} are ignored.
      *
      * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+     *
+     * The result will be posted on the {@code executor} using the given {@code callback}.
+     * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}.
+     *
+     * This method will throw {@link IllegalStateException} if
+     * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
+     * {@code profileType}.
      */
-    boolean isRuntimeProfilingEnabled();
+    oneway void snapshotRuntimeProfile(int profileType, in String packageName,
+        in String codePath, in ISnapshotRuntimeProfileCallback callback);
+
+     /**
+       * Returns true if runtime profiles are enabled for the given type, false otherwise.
+       * The type can be can be either {@code ArtManager.PROFILE_APPS}
+       * or {@code ArtManager.PROFILE_BOOT_IMAGE}.
+       *
+       * @param profileType
+       */
+    boolean isRuntimeProfilingEnabled(int profileType);
 }
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index 9e3a8f4..99eb470 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,13 +15,10 @@
  */
 package android.content.pm.split;
 
-import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.os.Build;
 
@@ -29,8 +26,6 @@
 
 import libcore.io.IoUtils;
 
-import java.io.IOException;
-
 /**
  * Loads the base and split APKs into a single AssetManager.
  * @hide
@@ -38,66 +33,68 @@
 public class DefaultSplitAssetLoader implements SplitAssetLoader {
     private final String mBaseCodePath;
     private final String[] mSplitCodePaths;
-    private final @ParseFlags int mFlags;
+    private final int mFlags;
+
     private AssetManager mCachedAssetManager;
 
-    public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
+    public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
         mBaseCodePath = pkg.baseCodePath;
         mSplitCodePaths = pkg.splitCodePaths;
         mFlags = flags;
     }
 
-    private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
-            throws PackageParserException {
-        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + path);
+    private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+            throws PackageParser.PackageParserException {
+        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
+            throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Invalid package file: " + apkPath);
         }
 
-        try {
-            return ApkAssets.loadFromPath(path);
-        } catch (IOException e) {
-            throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
-                    "Failed to load APK at path " + path, e);
+        if (assets.addAssetPath(apkPath) == 0) {
+            throw new PackageParser.PackageParserException(
+                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
         }
     }
 
     @Override
-    public AssetManager getBaseAssetManager() throws PackageParserException {
+    public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
         if (mCachedAssetManager != null) {
             return mCachedAssetManager;
         }
 
-        ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
-                ? mSplitCodePaths.length : 0) + 1];
+        AssetManager assets = new AssetManager();
+        try {
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+            loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
 
-        // Load the base.
-        int splitIdx = 0;
-        apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
+            if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+                for (String apkPath : mSplitCodePaths) {
+                    loadApkIntoAssetManager(assets, apkPath, mFlags);
+                }
+            }
 
-        // Load any splits.
-        if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
-            for (String apkPath : mSplitCodePaths) {
-                apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags);
+            mCachedAssetManager = assets;
+            assets = null;
+            return mCachedAssetManager;
+        } finally {
+            if (assets != null) {
+                IoUtils.closeQuietly(assets);
             }
         }
-
-        AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
-        assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
-
-        mCachedAssetManager = assets;
-        return mCachedAssetManager;
     }
 
     @Override
-    public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
+    public AssetManager getSplitAssetManager(int splitIdx)
+            throws PackageParser.PackageParserException {
         return getBaseAssetManager();
     }
 
     @Override
     public void close() throws Exception {
-        IoUtils.closeQuietly(mCachedAssetManager);
+        if (mCachedAssetManager != null) {
+            IoUtils.closeQuietly(mCachedAssetManager);
+        }
     }
 }
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 58eaabf..16023f0 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,21 +15,17 @@
  */
 package android.content.pm.split;
 
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
 import android.annotation.NonNull;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.os.Build;
 import android.util.SparseArray;
 
 import libcore.io.IoUtils;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -38,15 +34,17 @@
  * is to be used when an application opts-in to isolated split loading.
  * @hide
  */
-public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
+public class SplitAssetDependencyLoader
+        extends SplitDependencyLoader<PackageParser.PackageParserException>
         implements SplitAssetLoader {
     private final String[] mSplitPaths;
-    private final @ParseFlags int mFlags;
-    private final ApkAssets[][] mCachedSplitApks;
-    private final AssetManager[] mCachedAssetManagers;
+    private final int mFlags;
+
+    private String[][] mCachedPaths;
+    private AssetManager[] mCachedAssetManagers;
 
     public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
-            SparseArray<int[]> dependencies, @ParseFlags int flags) {
+            SparseArray<int[]> dependencies, int flags) {
         super(dependencies);
 
         // The base is inserted into index 0, so we need to shift all the splits by 1.
@@ -55,7 +53,7 @@
         System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
 
         mFlags = flags;
-        mCachedSplitApks = new ApkAssets[mSplitPaths.length][];
+        mCachedPaths = new String[mSplitPaths.length][];
         mCachedAssetManagers = new AssetManager[mSplitPaths.length];
     }
 
@@ -64,60 +62,58 @@
         return mCachedAssetManagers[splitIdx] != null;
     }
 
-    private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
-            throws PackageParserException {
-        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + path);
-        }
-
-        try {
-            return ApkAssets.loadFromPath(path);
-        } catch (IOException e) {
-            throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
-                    "Failed to load APK at path " + path, e);
-        }
-    }
-
-    private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
+    private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
+            throws PackageParser.PackageParserException {
         final AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
-        assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
-        return assets;
+        try {
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+
+            for (String assetPath : assetPaths) {
+                if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
+                        !PackageParser.isApkPath(assetPath)) {
+                    throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                            "Invalid package file: " + assetPath);
+                }
+
+                if (assets.addAssetPath(assetPath) == 0) {
+                    throw new PackageParser.PackageParserException(
+                            INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                            "Failed adding asset path: " + assetPath);
+                }
+            }
+            return assets;
+        } catch (Throwable e) {
+            IoUtils.closeQuietly(assets);
+            throw e;
+        }
     }
 
     @Override
     protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
-            int parentSplitIdx) throws PackageParserException {
-        final ArrayList<ApkAssets> assets = new ArrayList<>();
-
-        // Include parent ApkAssets.
+            int parentSplitIdx) throws PackageParser.PackageParserException {
+        final ArrayList<String> assetPaths = new ArrayList<>();
         if (parentSplitIdx >= 0) {
-            Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]);
+            Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
         }
 
-        // Include this ApkAssets.
-        assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags));
-
-        // Load and include all config splits for this feature.
+        assetPaths.add(mSplitPaths[splitIdx]);
         for (int configSplitIdx : configSplitIndices) {
-            assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags));
+            assetPaths.add(mSplitPaths[configSplitIdx]);
         }
-
-        // Cache the results.
-        mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]);
-        mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]);
+        mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+        mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
+                mFlags);
     }
 
     @Override
-    public AssetManager getBaseAssetManager() throws PackageParserException {
+    public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
         loadDependenciesForSplit(0);
         return mCachedAssetManagers[0];
     }
 
     @Override
-    public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
+    public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
         // Since we insert the base at position 0, and PackageParser keeps splits separate from
         // the base, we need to adjust the index.
         loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index fd664bc..b087c48 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -33,8 +33,8 @@
  * making the creation of AssetManagers very cheap.
  * @hide
  */
-public final class ApkAssets {
-    @GuardedBy("this") private final long mNativePtr;
+public final class ApkAssets implements AutoCloseable {
+    @GuardedBy("this") private long mNativePtr;
     @GuardedBy("this") private StringBlock mStringBlock;
 
     /**
@@ -127,12 +127,14 @@
 
     @NonNull String getAssetPath() {
         synchronized (this) {
+            ensureValidLocked();
             return nativeGetAssetPath(mNativePtr);
         }
     }
 
     CharSequence getStringFromPool(int idx) {
         synchronized (this) {
+            ensureValidLocked();
             return mStringBlock.get(idx);
         }
     }
@@ -149,6 +151,7 @@
     public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
         Preconditions.checkNotNull(fileName, "fileName");
         synchronized (this) {
+            ensureValidLocked();
             long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
             try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
                 XmlResourceParser parser = block.newParser();
@@ -167,13 +170,41 @@
      */
     public boolean isUpToDate() {
         synchronized (this) {
+            ensureValidLocked();
             return nativeIsUpToDate(mNativePtr);
         }
     }
 
+    /**
+     * Closes the ApkAssets and destroys the underlying native implementation. Further use of the
+     * ApkAssets object will cause exceptions to be thrown.
+     *
+     * Calling close on an already closed ApkAssets does nothing.
+     */
+    @Override
+    public void close() {
+        synchronized (this) {
+            if (mNativePtr == 0) {
+                return;
+            }
+
+            mStringBlock = null;
+            nativeDestroy(mNativePtr);
+            mNativePtr = 0;
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
-        nativeDestroy(mNativePtr);
+        if (mNativePtr != 0) {
+            nativeDestroy(mNativePtr);
+        }
+    }
+
+    private void ensureValidLocked() {
+        if (mNativePtr == 0) {
+            throw new RuntimeException("ApkAssets is closed");
+        }
     }
 
     private static native long nativeLoad(
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index abaf7014..78370f4 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -59,8 +59,6 @@
 
     private static final Object sSync = new Object();
 
-    private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0];
-
     // Not private for LayoutLib's BridgeAssetManager.
     @GuardedBy("sSync") static AssetManager sSystem = null;
 
@@ -216,16 +214,10 @@
      */
     public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
         Preconditions.checkNotNull(apkAssets, "apkAssets");
-
-        // Copy the apkAssets, but prepend the system assets (framework + overlays).
-        final ApkAssets[] newApkAssets = new ApkAssets[apkAssets.length + sSystemApkAssets.length];
-        System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length);
-        System.arraycopy(apkAssets, 0, newApkAssets, sSystemApkAssets.length, apkAssets.length);
-
         synchronized (this) {
-            ensureOpenLocked();
-            mApkAssets = newApkAssets;
-            nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
+            ensureValidLocked();
+            mApkAssets = apkAssets;
+            nativeSetApkAssets(mObject, apkAssets, invalidateCaches);
             if (invalidateCaches) {
                 // Invalidate all caches.
                 invalidateCachesLocked(-1);
@@ -244,37 +236,13 @@
     }
 
     /**
-     * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this
-     * returns a 0-length array.
      * @hide
      */
     public @NonNull ApkAssets[] getApkAssets() {
         synchronized (this) {
-            if (mOpen) {
-                return mApkAssets;
-            }
-        }
-        return sEmptyApkAssets;
-    }
-
-    /**
-     * Returns a cookie for use with the other APIs of AssetManager.
-     * @return 0 if the path was not found, otherwise a positive integer cookie representing
-     * this path in the AssetManager.
-     * @hide
-     */
-    public int findCookieForPath(@NonNull String path) {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
             ensureValidLocked();
-            final int count = mApkAssets.length;
-            for (int i = 0; i < count; i++) {
-                if (path.equals(mApkAssets[i].getAssetPath())) {
-                    return i + 1;
-                }
-            }
+            return mApkAssets;
         }
-        return 0;
     }
 
     /**
@@ -354,7 +322,6 @@
      * then this implies that ensureValidLocked() also passes.
      */
     private void ensureOpenLocked() {
-        // If mOpen is true, this implies that mObject != 0.
         if (!mOpen) {
             throw new RuntimeException("AssetManager has been closed");
         }
@@ -1186,7 +1153,6 @@
         if (mNumRefs == 0 && mObject != 0) {
             nativeDestroy(mObject);
             mObject = 0;
-            mApkAssets = sEmptyApkAssets;
         }
     }
 
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index bf5e391..429f1f3 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -64,8 +64,6 @@
 
     void cancelAnnouncement();
 
-    RadioManager.ProgramInfo getProgramInformation();
-
     Bitmap getImage(int id);
 
     /**
@@ -92,6 +90,4 @@
      * @return Vendor-specific key-value pairs, must be Map<String, String>
      */
     Map getParameters(in List<String> keys);
-
-    boolean isAntennaConnected();
 }
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index 54af30f..b32daa5 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -17,12 +17,14 @@
 package android.hardware.radio;
 
 import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioMetadata;
 
 /** {@hide} */
 oneway interface ITunerCallback {
     void onError(int status);
+    void onTuneFailed(int result, in ProgramSelector selector);
     void onConfigurationChanged(in RadioManager.BandConfig config);
     void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info);
     void onTrafficAnnouncement(boolean active);
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index ed20c4a..0edd055 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -64,7 +64,9 @@
      *  <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *  service fails, </li>
      * </ul>
+     * @deprecated Only applicable for HAL 1.x.
      */
+    @Deprecated
     public abstract int setConfiguration(RadioManager.BandConfig config);
 
     /**
@@ -80,7 +82,10 @@
      *  <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *  service fails, </li>
      * </ul>
+     *
+     * @deprecated Only applicable for HAL 1.x.
      */
+    @Deprecated
     public abstract int getConfiguration(RadioManager.BandConfig[] config);
 
 
@@ -228,7 +233,9 @@
      *  <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
      *  service fails, </li>
      * </ul>
+     * @deprecated Use {@link onProgramInfoChanged} callback instead.
      */
+    @Deprecated
     public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
 
     /**
@@ -427,7 +434,10 @@
      * Get current antenna connection state for current configuration.
      * Only valid if a configuration has been applied.
      * @return {@code true} if the antenna is connected, {@code false} otherwise.
+     *
+     * @deprecated Use {@link onAntennaState} callback instead
      */
+    @Deprecated
     public abstract boolean isAntennaConnected();
 
     /**
@@ -446,20 +456,41 @@
     public abstract boolean hasControl();
 
     /** Indicates a failure of radio IC or driver.
-     * The application must close and re open the tuner */
+     * The application must close and re open the tuner
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final int ERROR_HARDWARE_FAILURE = 0;
     /** Indicates a failure of the radio service.
-     * The application must close and re open the tuner */
+     * The application must close and re open the tuner
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final  int ERROR_SERVER_DIED = 1;
-    /** A pending seek or tune operation was cancelled */
+    /** A pending seek or tune operation was cancelled
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final  int ERROR_CANCELLED = 2;
-    /** A pending seek or tune operation timed out */
+    /** A pending seek or tune operation timed out
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final  int ERROR_SCAN_TIMEOUT = 3;
-    /** The requested configuration could not be applied */
+    /** The requested configuration could not be applied
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final  int ERROR_CONFIG = 4;
-    /** Background scan was interrupted due to hardware becoming temporarily unavailable. */
+    /** Background scan was interrupted due to hardware becoming temporarily unavailable.
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5;
-    /** Background scan failed due to other error, ie. HW failure. */
+    /** Background scan failed due to other error, ie. HW failure.
+     * @deprecated See {@link onError} callback.
+     */
+    @Deprecated
     public static final int ERROR_BACKGROUND_SCAN_FAILED = 6;
 
     /**
@@ -473,13 +504,29 @@
          * status is one of {@link #ERROR_HARDWARE_FAILURE}, {@link #ERROR_SERVER_DIED},
          * {@link #ERROR_CANCELLED}, {@link #ERROR_SCAN_TIMEOUT},
          * {@link #ERROR_CONFIG}
+         *
+         * @deprecated Use {@link onTuneFailed} for tune, scan and step;
+         *             other use cases (configuration, background scan) are already deprecated.
          */
         public void onError(int status) {}
+
+        /**
+         * Called when tune, scan or step operation fails.
+         *
+         * @param result cause of the failure
+         * @param selector ProgramSelector argument of tune that failed;
+         *                 null for scan and step.
+         */
+        public void onTuneFailed(int result, @Nullable ProgramSelector selector) {}
+
         /**
          * onConfigurationChanged() is called upon successful completion of
          * {@link RadioManager#openTuner(int, RadioManager.BandConfig, boolean, Callback, Handler)}
          * or {@link RadioTuner#setConfiguration(RadioManager.BandConfig)}
+         *
+         * @deprecated Only applicable for HAL 1.x.
          */
+        @Deprecated
         public void onConfigurationChanged(RadioManager.BandConfig config) {}
 
         /**
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 91944bf..85f3115 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -202,15 +202,17 @@
     @Override
     public int getProgramInformation(RadioManager.ProgramInfo[] info) {
         if (info == null || info.length != 1) {
-            throw new IllegalArgumentException("The argument must be an array of length 1");
+            Log.e(TAG, "The argument must be an array of length 1");
+            return RadioManager.STATUS_BAD_VALUE;
         }
-        try {
-            info[0] = mTuner.getProgramInformation();
-            return RadioManager.STATUS_OK;
-        } catch (RemoteException e) {
-            Log.e(TAG, "service died", e);
-            return RadioManager.STATUS_DEAD_OBJECT;
+
+        RadioManager.ProgramInfo current = mCallback.getCurrentProgramInformation();
+        if (current == null) {
+            Log.w(TAG, "Didn't get program info yet");
+            return RadioManager.STATUS_INVALID_OPERATION;
         }
+        info[0] = current;
+        return RadioManager.STATUS_OK;
     }
 
     @Override
@@ -288,12 +290,20 @@
 
     @Override
     public boolean isAnalogForced() {
-        return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG);
+        try {
+            return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG);
+        } catch (UnsupportedOperationException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     @Override
     public void setAnalogForced(boolean isForced) {
-        setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced);
+        try {
+            setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced);
+        } catch (UnsupportedOperationException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     @Override
@@ -343,11 +353,7 @@
 
     @Override
     public boolean isAntennaConnected() {
-        try {
-            return mTuner.isAntennaConnected();
-        } catch (RemoteException e) {
-            throw new RuntimeException("service died", e);
-        }
+        return mCallback.isAntennaConnected();
     }
 
     @Override
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index b299ffe..7437c40 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -37,8 +37,12 @@
     @NonNull private final Handler mHandler;
 
     @Nullable ProgramList mProgramList;
-    @Nullable List<RadioManager.ProgramInfo> mLastCompleteList;  // for legacy getProgramList call
+
+    // cache for deprecated methods
+    boolean mIsAntennaConnected = true;
+    @Nullable List<RadioManager.ProgramInfo> mLastCompleteList;
     private boolean mDelayedCompleteCallback = false;
+    @Nullable RadioManager.ProgramInfo mCurrentProgramInfo;
 
     TunerCallbackAdapter(@NonNull RadioTuner.Callback callback, @Nullable Handler handler) {
         mCallback = callback;
@@ -92,12 +96,46 @@
         }
     }
 
+    @Nullable RadioManager.ProgramInfo getCurrentProgramInformation() {
+        synchronized (mLock) {
+            return mCurrentProgramInfo;
+        }
+    }
+
+    boolean isAntennaConnected() {
+        return mIsAntennaConnected;
+    }
+
     @Override
     public void onError(int status) {
         mHandler.post(() -> mCallback.onError(status));
     }
 
     @Override
+    public void onTuneFailed(int status, @Nullable ProgramSelector selector) {
+        mHandler.post(() -> mCallback.onTuneFailed(status, selector));
+
+        int errorCode;
+        switch (status) {
+            case RadioManager.STATUS_PERMISSION_DENIED:
+            case RadioManager.STATUS_DEAD_OBJECT:
+                errorCode = RadioTuner.ERROR_SERVER_DIED;
+                break;
+            case RadioManager.STATUS_ERROR:
+            case RadioManager.STATUS_NO_INIT:
+            case RadioManager.STATUS_BAD_VALUE:
+            case RadioManager.STATUS_INVALID_OPERATION:
+                Log.i(TAG, "Got an error with no mapping to the legacy API (" + status
+                        + "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT");
+            // fall through
+            case RadioManager.STATUS_TIMED_OUT:
+            default:
+                errorCode = RadioTuner.ERROR_SCAN_TIMEOUT;
+        }
+        mHandler.post(() -> mCallback.onError(errorCode));
+    }
+
+    @Override
     public void onConfigurationChanged(RadioManager.BandConfig config) {
         mHandler.post(() -> mCallback.onConfigurationChanged(config));
     }
@@ -109,6 +147,10 @@
             return;
         }
 
+        synchronized (mLock) {
+            mCurrentProgramInfo = info;
+        }
+
         mHandler.post(() -> {
             mCallback.onProgramInfoChanged(info);
 
@@ -129,6 +171,7 @@
 
     @Override
     public void onAntennaState(boolean connected) {
+        mIsAntennaConnected = connected;
         mHandler.post(() -> mCallback.onAntennaState(connected));
     }
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 62731e8..158041d 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -302,9 +302,8 @@
     }
 
     /** {@hide} */
-    public static File getProfileSnapshotPath(String packageName, String codePath) {
-        return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName,
-                "primary.prof.snapshot"));
+    public static File getDataRefProfilesDePackageDirectory(String packageName) {
+        return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
     }
 
     /** {@hide} */
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 81d7506..d592000 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -493,6 +493,29 @@
         return mChains;
     }
 
+    /**
+     * DO NOT USE: Hacky API provided solely for {@code GnssLocationProvider}. See
+     * {@code setReturningDiffs} as well.
+     *
+     * @hide
+     */
+    public void transferWorkChains(WorkSource other) {
+        if (mChains != null) {
+            mChains.clear();
+        }
+
+        if (other.mChains == null || other.mChains.isEmpty()) {
+            return;
+        }
+
+        if (mChains == null) {
+            mChains = new ArrayList<>(4);
+        }
+
+        mChains.addAll(other.mChains);
+        other.mChains.clear();
+    }
+
     private boolean removeUids(WorkSource other) {
         int N1 = mNum;
         final int[] uids1 = mUids;
@@ -880,6 +903,13 @@
             return mUids[0];
         }
 
+        /**
+         * Return the tag associated with the attribution UID. See (@link #getAttributionUid}.
+         */
+        public String getAttributionTag() {
+            return mTags[0];
+        }
+
         // TODO: The following three trivial getters are purely for testing and will be removed
         // once we have higher level logic in place, e.g for serializing this WorkChain to a proto,
         // diffing it etc.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index e7fd59e..d96316a 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -738,7 +738,9 @@
     private static final String PATH_DOCUMENT = "document";
     private static final String PATH_CHILDREN = "children";
     private static final String PATH_SEARCH = "search";
-    private static final String PATH_TREE = "tree";
+    // TODO(b/72055774): make private again once ScopedAccessProvider is refactored
+    /** {@hide} */
+    public static final String PATH_TREE = "tree";
 
     private static final String PARAM_QUERY = "query";
     private static final String PARAM_MANAGE = "manage";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cadca24..e957842 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5510,6 +5510,27 @@
         public static final String LOCATION_MODE = "location_mode";
 
         /**
+         * The App or module that changes the location mode.
+         * @hide
+         */
+        public static final String LOCATION_CHANGER = "location_changer";
+        /**
+         * The location changer is unknown or unable to detect.
+         * @hide
+         */
+        public static final int LOCATION_CHANGER_UNKNOWN = 0;
+        /**
+         * Location settings in system settings.
+         * @hide
+         */
+        public static final int LOCATION_CHANGER_SYSTEM_SETTINGS = 1;
+        /**
+         * The location icon in drop down notification drawer.
+         * @hide
+         */
+        public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2;
+
+        /**
          * Location access disabled.
          *
          * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
@@ -7881,6 +7902,7 @@
             CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+            CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
             CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
new file mode 100644
index 0000000..f79d852
--- /dev/null
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+/**
+ * Provides a contract for platform-supported Settings {@link android.app.slice.Slice Slices}.
+ * <p>
+ * Contains definitions for the supported {@link android.app.slice.SliceProvider SliceProvider}
+ * authority, authority {@link Uri}, and key constants.
+ * <p>
+ * {@link android.app.slice.Slice Slice} presenters interested in learning meta-data about the
+ * {@link android.app.slice.Slice Slice} should read the {@link android.app.slice.Slice Slice}
+ * object at runtime.
+ * <p>
+ * {@link Uri} builder example:
+ * <pre>
+ * Uri wifiActionUri = AUTHORITY_URI
+ *         .buildUpon()
+ *         .appendPath(PATH_SETTING_ACTION)
+ *         .appendPath(KEY_WIFI)
+ *         .build();
+ * Uri bluetoothIntentUri = AUTHORITY_URI
+ *         .buildUpon()
+ *         .appendPath(PATH_SETTING_INTENT)
+ *         .appendPath(KEY_BLUETOOTH)
+ *         .build();
+ * </pre>
+ */
+public class SettingsSlicesContract {
+    private SettingsSlicesContract() {
+    }
+
+    /**
+     * Authority for platform Settings Slices.
+     */
+    public static final String AUTHORITY = "android.settings.slices";
+
+    /**
+     * A content:// style uri to the Settings Slices authority, {@link #AUTHORITY}.
+     */
+    public static final Uri BASE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(AUTHORITY)
+            .build();
+
+    /**
+     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+     * have inline controls for the corresponding setting.
+     * <p>
+     * This path will only contain Slices defined by keys in this class.
+     */
+    public static final String PATH_SETTING_ACTION = "action";
+
+    /**
+     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+     * be {@link android.content.Intent Intent}-only.
+     * <p>
+     * {@link android.app.slice.Slice Slices} with actions should use the {@link
+     * #PATH_SETTING_ACTION} path.
+     * <p>
+     * This path will only contain Slices defined by keys in this class
+     */
+    public static final String PATH_SETTING_INTENT = "intent";
+
+    /**
+     * {@link Uri} key for the Airplane Mode setting.
+     */
+    public static final String KEY_AIRPLANE_MODE = "airplane_mode";
+
+    /**
+     * {@link Uri} key for the Battery Saver setting.
+     */
+    public static final String KEY_BATTERY_SAVER = "battery_saver";
+
+    /**
+     * {@link Uri} key for the Bluetooth setting.
+     */
+    public static final String KEY_BLUETOOTH = "bluetooth";
+
+    /**
+     * {@link Uri} key for the Location setting.
+     */
+    public static final String KEY_LOCATION = "location";
+
+    /**
+     * {@link Uri} key for the Wi-fi setting.
+     */
+    public static final String KEY_WIFI = "wifi";
+}
diff --git a/core/java/android/security/IConfirmationPromptCallback.aidl b/core/java/android/security/IConfirmationPromptCallback.aidl
new file mode 100644
index 0000000..96a1a04
--- /dev/null
+++ b/core/java/android/security/IConfirmationPromptCallback.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2017, 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.security;
+
+/**
+ * This must be kept manually in sync with system/security/keystore until AIDL
+ * can generate both Java and C++ bindings.
+ *
+ * @hide
+ */
+interface IConfirmationPromptCallback {
+    oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed);
+}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index b5496e4..738eb68 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -81,4 +81,7 @@
         in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
         in long rootSid, in long fingerprintSid,
         out KeyCharacteristics characteristics);
+    int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
+        in String locale, in int uiOptionsAsFlags);
+    int cancelConfirmationPrompt(IBinder listener);
 }
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 5a09dab..62222b5 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -412,6 +412,20 @@
         }
     }
 
+    static byte[] generateFsverityRootHash(String apkPath)
+            throws IOException, SignatureNotFoundException, DigestException,
+                   NoSuchAlgorithmException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+            SignatureInfo signatureInfo = findSignature(apk);
+            VerifiedSigner vSigner = verify(apk, false);
+            if (vSigner.verityRootHash == null) {
+                return null;
+            }
+            return ApkVerityBuilder.generateFsverityRootHash(
+                    apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
+        }
+    }
+
     private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
         switch (sigAlgorithm) {
             case SIGNATURE_RSA_PSS_WITH_SHA256:
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 1b04eb2..ee6fc07 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -523,6 +523,20 @@
         }
     }
 
+    static byte[] generateFsverityRootHash(String apkPath)
+            throws NoSuchAlgorithmException, DigestException, IOException,
+                   SignatureNotFoundException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+            SignatureInfo signatureInfo = findSignature(apk);
+            VerifiedSigner vSigner = verify(apk, false);
+            if (vSigner.verityRootHash == null) {
+                return null;
+            }
+            return ApkVerityBuilder.generateFsverityRootHash(
+                    apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
+        }
+    }
+
     private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
         switch (sigAlgorithm) {
             case SIGNATURE_RSA_PSS_WITH_SHA256:
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 8794372..de9f55b 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -427,6 +427,27 @@
     }
 
     /**
+     * Generates the FSVerity root hash from FSVerity header, extensions and Merkle tree root hash
+     * in Signing Block.
+     *
+     * @return FSverity root hash
+     */
+    public static byte[] generateFsverityRootHash(String apkPath)
+            throws NoSuchAlgorithmException, DigestException, IOException {
+        // first try v3
+        try {
+            return ApkSignatureSchemeV3Verifier.generateFsverityRootHash(apkPath);
+        } catch (SignatureNotFoundException e) {
+            // try older version
+        }
+        try {
+            return ApkSignatureSchemeV2Verifier.generateFsverityRootHash(apkPath);
+        } catch (SignatureNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
      * Result of a successful APK verification operation.
      */
     public static class Result {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5bd0782..93b3fc2 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -25,7 +25,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.SystemApi;
 import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -1255,14 +1254,6 @@
     }
 
     /** @hide */
-    @SystemApi
-    public void setDisableWallpaperTouchEvents(boolean disable) {
-        setPrivateFlags(disable
-                ? WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS : 0,
-                WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS);
-    }
-
-    /** @hide */
     public abstract void alwaysReadCloseOnTouchAttr();
 
     /** @hide */
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java
index 2c93a19..8edf97e 100644
--- a/core/java/android/view/textclassifier/SmartSelection.java
+++ b/core/java/android/view/textclassifier/SmartSelection.java
@@ -16,6 +16,7 @@
 
 package android.view.textclassifier;
 
+import android.annotation.Nullable;
 import android.content.res.AssetFileDescriptor;
 
 /**
@@ -146,11 +147,24 @@
         final String mCollection;
         /** float range: 0 - 1 */
         final float mScore;
+        @Nullable final DatetimeParseResult mDatetime;
 
         ClassificationResult(String collection, float score) {
             mCollection = collection;
             mScore = score;
+            mDatetime = null;
         }
+
+        ClassificationResult(String collection, float score, DatetimeParseResult datetime) {
+            mCollection = collection;
+            mScore = score;
+            mDatetime = datetime;
+        }
+    }
+
+    /** Parsed date information for the classification result. */
+    static final class DatetimeParseResult {
+        long mMsSinceEpoch;
     }
 
     /** Represents a result of Annotate call. */
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 7089677..54e93d5 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -36,6 +36,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -592,6 +593,7 @@
     public static final class Options implements Parcelable {
 
         private @Nullable LocaleList mDefaultLocales;
+        private @Nullable Calendar mReferenceTime;
 
         public Options() {}
 
@@ -606,6 +608,16 @@
         }
 
         /**
+         * @param referenceTime reference time based on which relative dates (e.g. "tomorrow" should
+         *      be interpreted. This should usually be the time when the text was originally
+         *      composed. If no reference time is set, now is used.
+         */
+        public Options setReferenceTime(Calendar referenceTime) {
+            mReferenceTime = referenceTime;
+            return this;
+        }
+
+        /**
          * @return ordered list of locale preferences that can be used to disambiguate
          *      the provided text.
          */
@@ -614,6 +626,15 @@
             return mDefaultLocales;
         }
 
+        /**
+         * @return reference time based on which relative dates (e.g. "tomorrow") should be
+         *      interpreted.
+         */
+        @Nullable
+        public Calendar getReferenceTime() {
+            return mReferenceTime;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -625,6 +646,10 @@
             if (mDefaultLocales != null) {
                 mDefaultLocales.writeToParcel(dest, flags);
             }
+            dest.writeInt(mReferenceTime != null ? 1 : 0);
+            if (mReferenceTime != null) {
+                dest.writeSerializable(mReferenceTime);
+            }
         }
 
         public static final Parcelable.Creator<Options> CREATOR =
@@ -644,6 +669,9 @@
             if (in.readInt() > 0) {
                 mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
             }
+            if (in.readInt() > 0) {
+                mReferenceTime = (Calendar) in.readSerializable();
+            }
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index e9715c5..04ab447 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -47,12 +47,26 @@
     /** @hide */
     String DEFAULT_LOG_TAG = "androidtc";
 
+    /** The TextClassifier failed to run. */
     String TYPE_UNKNOWN = "";
+    /** The classifier ran, but didn't recognize a known entity. */
     String TYPE_OTHER = "other";
+    /** E-mail address (e.g. "noreply@android.com"). */
     String TYPE_EMAIL = "email";
+    /** Phone number (e.g. "555-123 456"). */
     String TYPE_PHONE = "phone";
+    /** Physical address. */
     String TYPE_ADDRESS = "address";
+    /** Web URL. */
     String TYPE_URL = "url";
+    /** Time reference that is no more specific than a date. May be absolute such as "01/01/2000" or
+     * relative like "tomorrow". **/
+    String TYPE_DATE = "date";
+    /** Time reference that includes a specific time. May be absolute such as "01/01/2000 5:30pm" or
+     * relative like "tomorrow at 5:30pm". **/
+    String TYPE_DATE_TIME = "datetime";
+    /** Flight number in IATA format. */
+    String TYPE_FLIGHT_NUMBER = "flight";
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -63,6 +77,9 @@
             TYPE_PHONE,
             TYPE_ADDRESS,
             TYPE_URL,
+            TYPE_DATE,
+            TYPE_DATE_TIME,
+            TYPE_FLIGHT_NUMBER,
     })
     @interface EntityType {}
 
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7db0e76..f434452 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -18,7 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.SearchManager;
 import android.content.ComponentName;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -28,6 +30,7 @@
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.provider.Browser;
+import android.provider.CalendarContract;
 import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.text.util.Linkify;
@@ -42,6 +45,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -49,6 +53,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -73,7 +78,10 @@
                     TextClassifier.TYPE_ADDRESS,
                     TextClassifier.TYPE_EMAIL,
                     TextClassifier.TYPE_PHONE,
-                    TextClassifier.TYPE_URL));
+                    TextClassifier.TYPE_URL,
+                    TextClassifier.TYPE_DATE,
+                    TextClassifier.TYPE_DATE_TIME,
+                    TextClassifier.TYPE_FLIGHT_NUMBER));
     private static final List<String> ENTITY_TYPES_BASE =
             Collections.unmodifiableList(Arrays.asList(
                     TextClassifier.TYPE_ADDRESS,
@@ -167,9 +175,8 @@
                         .classifyText(string, startIndex, endIndex,
                                 getHintFlags(string, startIndex, endIndex));
                 if (results.length > 0) {
-                    final TextClassification classificationResult =
-                            createClassificationResult(results, string, startIndex, endIndex);
-                    return classificationResult;
+                    return createClassificationResult(
+                            results, string, startIndex, endIndex, options.getReferenceTime());
                 }
             }
         } catch (Throwable t) {
@@ -410,18 +417,24 @@
 
     private TextClassification createClassificationResult(
             SmartSelection.ClassificationResult[] classifications,
-            String text, int start, int end) {
+            String text, int start, int end, @Nullable Calendar referenceTime) {
         final String classifiedText = text.substring(start, end);
         final TextClassification.Builder builder = new TextClassification.Builder()
                 .setText(classifiedText);
 
         final int size = classifications.length;
+        SmartSelection.ClassificationResult highestScoringResult = null;
+        float highestScore = Float.MIN_VALUE;
         for (int i = 0; i < size; i++) {
             builder.setEntityType(classifications[i].mCollection, classifications[i].mScore);
+            if (classifications[i].mScore > highestScore) {
+                highestScoringResult = classifications[i];
+                highestScore = classifications[i].mScore;
+            }
         }
 
-        final String type = getHighestScoringType(classifications);
-        addActions(builder, IntentFactory.create(mContext, type, classifiedText));
+        addActions(builder, IntentFactory.create(
+                mContext, referenceTime, highestScoringResult, classifiedText));
 
         return builder.setSignature(getSignature(text, start, end)).build();
     }
@@ -441,11 +454,10 @@
             }
             if (resolveInfo != null && resolveInfo.activityInfo != null) {
                 final String packageName = resolveInfo.activityInfo.packageName;
-                CharSequence label;
+                final String label = IntentFactory.getLabel(mContext, intent);
                 Drawable icon;
                 if ("android".equals(packageName)) {
                     // Requires the chooser to find an activity to handle the intent.
-                    label = IntentFactory.getLabel(mContext, intent);
                     icon = null;
                 } else {
                     // A default activity will handle the intent.
@@ -455,16 +467,11 @@
                     if (icon == null) {
                         icon = resolveInfo.loadIcon(pm);
                     }
-                    label = resolveInfo.activityInfo.loadLabel(pm);
-                    if (label == null) {
-                        label = resolveInfo.loadLabel(pm);
-                    }
                 }
-                final String labelString = (label != null) ? label.toString() : null;
                 if (i == 0) {
-                    builder.setPrimaryAction(intent, labelString, icon);
+                    builder.setPrimaryAction(intent, label, icon);
                 } else {
-                    builder.addSecondaryAction(intent, labelString, icon);
+                    builder.addSecondaryAction(intent, label, icon);
                 }
             }
         }
@@ -483,23 +490,6 @@
         return flag;
     }
 
-    private static String getHighestScoringType(SmartSelection.ClassificationResult[] types) {
-        if (types.length < 1) {
-            return "";
-        }
-
-        String type = types[0].mCollection;
-        float highestScore = types[0].mScore;
-        final int size = types.length;
-        for (int i = 1; i < size; i++) {
-            if (types[i].mScore > highestScore) {
-                type = types[i].mCollection;
-                highestScore = types[i].mScore;
-            }
-        }
-        return type;
-    }
-
     /**
      * Closes the ParcelFileDescriptor and logs any errors that occur.
      */
@@ -514,58 +504,139 @@
     /**
      * Creates intents based on the classification type.
      */
-    private static final class IntentFactory {
+    static final class IntentFactory {
+
+        private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5);
+        private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1);
 
         private IntentFactory() {}
 
         @NonNull
-        public static List<Intent> create(Context context, String type, String text) {
-            final List<Intent> intents = new ArrayList<>();
-            type = type.trim().toLowerCase(Locale.ENGLISH);
+        public static List<Intent> create(
+                Context context,
+                @Nullable Calendar referenceTime,
+                SmartSelection.ClassificationResult classification,
+                String text) {
+            final String type = classification.mCollection.trim().toLowerCase(Locale.ENGLISH);
             text = text.trim();
             switch (type) {
                 case TextClassifier.TYPE_EMAIL:
-                    intents.add(new Intent(Intent.ACTION_SENDTO)
-                            .setData(Uri.parse(String.format("mailto:%s", text))));
-                    intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+                    return createForEmail(text);
+                case TextClassifier.TYPE_PHONE:
+                    return createForPhone(text);
+                case TextClassifier.TYPE_ADDRESS:
+                    return createForAddress(text);
+                case TextClassifier.TYPE_URL:
+                    return createForUrl(context, text);
+                case TextClassifier.TYPE_DATE:
+                case TextClassifier.TYPE_DATE_TIME:
+                    if (classification.mDatetime != null) {
+                        Calendar eventTime = Calendar.getInstance();
+                        eventTime.setTimeInMillis(classification.mDatetime.mMsSinceEpoch);
+                        return createForDatetime(type, referenceTime, eventTime);
+                    } else {
+                        return new ArrayList<>();
+                    }
+                case TextClassifier.TYPE_FLIGHT_NUMBER:
+                    return createForFlight(text);
+                default:
+                    return new ArrayList<>();
+            }
+        }
+
+        @NonNull
+        private static List<Intent> createForEmail(String text) {
+            return Arrays.asList(
+                    new Intent(Intent.ACTION_SENDTO)
+                            .setData(Uri.parse(String.format("mailto:%s", text))),
+                    new Intent(Intent.ACTION_INSERT_OR_EDIT)
                             .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
                             .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
-                    break;
-                case TextClassifier.TYPE_PHONE:
-                    intents.add(new Intent(Intent.ACTION_DIAL)
-                            .setData(Uri.parse(String.format("tel:%s", text))));
-                    intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+        }
+
+        @NonNull
+        private static List<Intent> createForPhone(String text) {
+            return Arrays.asList(
+                    new Intent(Intent.ACTION_DIAL)
+                            .setData(Uri.parse(String.format("tel:%s", text))),
+                    new Intent(Intent.ACTION_INSERT_OR_EDIT)
                             .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
-                            .putExtra(ContactsContract.Intents.Insert.PHONE, text));
-                    intents.add(new Intent(Intent.ACTION_SENDTO)
+                            .putExtra(ContactsContract.Intents.Insert.PHONE, text),
+                    new Intent(Intent.ACTION_SENDTO)
                             .setData(Uri.parse(String.format("smsto:%s", text))));
-                    break;
-                case TextClassifier.TYPE_ADDRESS:
-                    intents.add(new Intent(Intent.ACTION_VIEW)
-                            .setData(Uri.parse(String.format("geo:0,0?q=%s", text))));
-                    break;
-                case TextClassifier.TYPE_URL:
-                    final String httpPrefix = "http://";
-                    final String httpsPrefix = "https://";
-                    if (text.toLowerCase().startsWith(httpPrefix)) {
-                        text = httpPrefix + text.substring(httpPrefix.length());
-                    } else if (text.toLowerCase().startsWith(httpsPrefix)) {
-                        text = httpsPrefix + text.substring(httpsPrefix.length());
-                    } else {
-                        text = httpPrefix + text;
-                    }
-                    intents.add(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
-                            .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
-                    break;
+        }
+
+        @NonNull
+        private static List<Intent> createForAddress(String text) {
+            return Arrays.asList(new Intent(Intent.ACTION_VIEW)
+                    .setData(Uri.parse(String.format("geo:0,0?q=%s", text))));
+        }
+
+        @NonNull
+        private static List<Intent> createForUrl(Context context, String text) {
+            final String httpPrefix = "http://";
+            final String httpsPrefix = "https://";
+            if (text.toLowerCase().startsWith(httpPrefix)) {
+                text = httpPrefix + text.substring(httpPrefix.length());
+            } else if (text.toLowerCase().startsWith(httpsPrefix)) {
+                text = httpsPrefix + text.substring(httpsPrefix.length());
+            } else {
+                text = httpPrefix + text;
+            }
+            return Arrays.asList(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+                    .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
+        }
+
+        @NonNull
+        private static List<Intent> createForDatetime(
+                String type, @Nullable Calendar referenceTime, Calendar eventTime) {
+            if (referenceTime == null) {
+                // If no reference time was given, use now.
+                referenceTime = Calendar.getInstance();
+            }
+            List<Intent> intents = new ArrayList<>();
+            intents.add(createCalendarViewIntent(eventTime));
+            final long millisSinceReference =
+                    eventTime.getTimeInMillis() - referenceTime.getTimeInMillis();
+            if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) {
+                intents.add(createCalendarCreateEventIntent(eventTime, type));
             }
             return intents;
         }
 
+        @NonNull
+        private static List<Intent> createForFlight(String text) {
+            return Arrays.asList(new Intent(Intent.ACTION_WEB_SEARCH)
+                    .putExtra(SearchManager.QUERY, text));
+        }
+
+        @NonNull
+        private static Intent createCalendarViewIntent(Calendar eventTime) {
+            Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
+            builder.appendPath("time");
+            ContentUris.appendId(builder, eventTime.getTimeInMillis());
+            return new Intent(Intent.ACTION_VIEW).setData(builder.build());
+        }
+
+        @NonNull
+        private static Intent createCalendarCreateEventIntent(
+                Calendar eventTime, @EntityType String type) {
+            final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
+            return new Intent(Intent.ACTION_INSERT)
+                    .setData(CalendarContract.Events.CONTENT_URI)
+                    .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
+                    .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, eventTime.getTimeInMillis())
+                    .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
+                            eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION);
+        }
+
         @Nullable
         public static String getLabel(Context context, @Nullable Intent intent) {
             if (intent == null || intent.getAction() == null) {
                 return null;
             }
+            final String authority =
+                    intent.getData() == null ? null : intent.getData().getAuthority();
             switch (intent.getAction()) {
                 case Intent.ACTION_DIAL:
                     return context.getString(com.android.internal.R.string.dial);
@@ -578,6 +649,11 @@
                         default:
                             return null;
                     }
+                case Intent.ACTION_INSERT:
+                    if (CalendarContract.AUTHORITY.equals(authority)) {
+                        return context.getString(com.android.internal.R.string.add_calendar_event);
+                    }
+                    return null;
                 case Intent.ACTION_INSERT_OR_EDIT:
                     switch (intent.getDataString()) {
                         case ContactsContract.Contacts.CONTENT_ITEM_TYPE:
@@ -586,6 +662,9 @@
                             return null;
                     }
                 case Intent.ACTION_VIEW:
+                    if (CalendarContract.AUTHORITY.equals(authority)) {
+                        return context.getString(com.android.internal.R.string.view_calendar);
+                    }
                     switch (intent.getScheme()) {
                         case "geo":
                             return context.getString(com.android.internal.R.string.map);
@@ -595,6 +674,8 @@
                         default:
                             return null;
                     }
+                case Intent.ACTION_WEB_SEARCH:
+                    return context.getString(com.android.internal.R.string.view_flight);
                 default:
                     return null;
             }
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 8650c0a..7f0c086 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -23,6 +23,7 @@
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.MediaPlayerBase;
+import android.media.session.MediaController;
 import android.media.update.ApiLoader;
 import android.media.update.VideoView2Provider;
 import android.media.update.ViewProvider;
@@ -76,8 +77,8 @@
  * If a developer wants to attach a customed MediaControlView2, then set enableControlView attribute
  * to false and assign the customed media control widget using {@link #setMediaControlView2}.
  * <li> VideoView2 is integrated with MediaPlayer2 while VideoView is integrated with MediaPlayer.
- * <li> VideoView2 is integrated with MediaSession2 and so it responses with media key events.
- * A VideoView2 keeps a MediaSession2 instance internally and connects it to a corresponding
+ * <li> VideoView2 is integrated with MediaSession and so it responses with media key events.
+ * A VideoView2 keeps a MediaSession instance internally and connects it to a corresponding
  * MediaControlView2 instance.
  * </p>
  * </ul>
@@ -159,60 +160,18 @@
         return mProvider.getMediaControlView2_impl();
     }
 
-    /**
-     * Starts playback with the media contents specified by {@link #setVideoURI} and
-     * {@link #setVideoPath}.
-     * If it has been paused, this method will resume playback from the current position.
-     */
-    public void start() {
-        mProvider.start_impl();
-    }
 
     /**
-     * Pauses playback.
+     * Returns MediaController instance which is connected with MediaSession that VideoView2 is
+     * using. This method should be called when VideoView2 is attached to window, or it throws
+     * IllegalStateException, since internal MediaSession instance is not available until
+     * this view is attached to window. Please check {@link android.view.View#isAttachedToWindow}
+     * before calling this method.
+     *
+     * @throws IllegalStateException if interal MediaSession is not created yet.
      */
-    public void pause() {
-        mProvider.pause_impl();
-    }
-
-    /**
-     * Gets the duration of the media content specified by #setVideoURI and #setVideoPath
-     * in milliseconds.
-     */
-    public int getDuration() {
-        return mProvider.getDuration_impl();
-    }
-
-    /**
-     * Gets current playback position in milliseconds.
-     */
-    public int getCurrentPosition() {
-        return mProvider.getCurrentPosition_impl();
-    }
-
-    // TODO: mention about key-frame related behavior.
-    /**
-     * Moves the media by specified time position.
-     * @param msec the offset in milliseconds from the start to seek to.
-     */
-    public void seekTo(int msec) {
-        mProvider.seekTo_impl(msec);
-    }
-
-    /**
-     * Says if the media is currently playing.
-     * @return true if the media is playing, false if it is not (eg. paused or stopped).
-     */
-    public boolean isPlaying() {
-        return mProvider.isPlaying_impl();
-    }
-
-    // TODO: check what will return if it is a local media.
-    /**
-     * Gets the percentage (0-100) of the content that has been buffered or played so far.
-     */
-    public int getBufferPercentage() {
-        return mProvider.getBufferPercentage_impl();
+    public MediaController getMediaController() {
+        return mProvider.getMediaController_impl();
     }
 
     /**
@@ -244,7 +203,6 @@
         mProvider.setFullScreen_impl(fullScreen);
     }
 
-    // TODO: This should be revised after integration with MediaPlayer2.
     /**
      * Sets playback speed.
      *
@@ -254,21 +212,12 @@
      * be reset to the normal speed 1.0f.
      * @param speed the playback speed. It should be positive.
      */
+    // TODO: Support this via MediaController2.
     public void setSpeed(float speed) {
         mProvider.setSpeed_impl(speed);
     }
 
     /**
-     * Returns current speed setting.
-     *
-     * If setSpeed() has never been called, returns the default value 1.0f.
-     * @return current speed setting
-     */
-    public float getSpeed() {
-        return mProvider.getSpeed_impl();
-    }
-
-    /**
      * Sets which type of audio focus will be requested during the playback, or configures playback
      * to not request audio focus. Valid values for focus requests are
      * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
@@ -367,14 +316,6 @@
     }
 
     /**
-     * Stops playback and release all the resources. This should be called whenever a VideoView2
-     * instance is no longer to be used.
-     */
-    public void stopPlayback() {
-        mProvider.stopPlayback_impl();
-    }
-
-    /**
      * Registers a callback to be invoked when the media file is loaded and ready to go.
      *
      * @param l the callback that will be run.
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index d3e807d..514ff76 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -91,8 +91,7 @@
 
     void noteVibratorOn(int uid, long durationMillis);
     void noteVibratorOff(int uid);
-    void noteStartGps(int uid);
-    void noteStopGps(int uid);
+    void noteGpsChanged(in WorkSource oldSource, in WorkSource newSource);
     void noteGpsSignalQuality(int signalLevel);
     void noteScreenState(int state);
     void noteScreenBrightness(int brightness);
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 2b0b5ee..d247013 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -146,7 +146,11 @@
 
         private String getLangScriptKey() {
             if (mLangScriptKey == null) {
-                Locale parentWithScript = getParent(LocaleHelper.addLikelySubtags(mLocale));
+                Locale baseLocale = new Locale.Builder()
+                    .setLocale(mLocale)
+                    .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "")
+                    .build();
+                Locale parentWithScript = getParent(LocaleHelper.addLikelySubtags(baseLocale));
                 mLangScriptKey =
                         (parentWithScript == null)
                         ? mLocale.toLanguageTag()
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 51f51c2..ee3bec8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4587,8 +4587,35 @@
 
     int mGpsNesting;
 
-    public void noteStartGpsLocked(int uid) {
-        uid = mapUid(uid);
+    public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs) {
+        for (int i = 0; i < newWs.size(); ++i) {
+            noteStartGpsLocked(newWs.get(i), null);
+        }
+
+        for (int i = 0; i < oldWs.size(); ++i) {
+            noteStopGpsLocked((oldWs.get(i)), null);
+        }
+
+        List<WorkChain>[] wcs = WorkSource.diffChains(oldWs, newWs);
+        if (wcs != null) {
+            if (wcs[0] != null) {
+                final List<WorkChain> newChains = wcs[0];
+                for (int i = 0; i < newChains.size(); ++i) {
+                    noteStartGpsLocked(-1, newChains.get(i));
+                }
+            }
+
+            if (wcs[1] != null) {
+                final List<WorkChain> goneChains = wcs[1];
+                for (int i = 0; i < goneChains.size(); ++i) {
+                    noteStopGpsLocked(-1, goneChains.get(i));
+                }
+            }
+        }
+    }
+
+    private void noteStartGpsLocked(int uid, WorkChain workChain) {
+        uid = getAttributionUid(uid, workChain);
         final long elapsedRealtime = mClocks.elapsedRealtime();
         final long uptime = mClocks.uptimeMillis();
         if (mGpsNesting == 0) {
@@ -4598,11 +4625,19 @@
             addHistoryRecordLocked(elapsedRealtime, uptime);
         }
         mGpsNesting++;
+
+        if (workChain == null) {
+            StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, 1);
+        } else {
+            StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED,
+                    workChain.getUids(), workChain.getTags(), 1);
+        }
+
         getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
     }
 
-    public void noteStopGpsLocked(int uid) {
-        uid = mapUid(uid);
+    private void noteStopGpsLocked(int uid, WorkChain workChain) {
+        uid = getAttributionUid(uid, workChain);
         final long elapsedRealtime = mClocks.elapsedRealtime();
         final long uptime = mClocks.uptimeMillis();
         mGpsNesting--;
@@ -4614,6 +4649,14 @@
             stopAllGpsSignalQualityTimersLocked(-1);
             mGpsSignalQualityBin = -1;
         }
+
+        if (workChain == null) {
+            StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, 0);
+        } else {
+            StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
+                    workChain.getTags(), 0);
+        }
+
         getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
     }
 
@@ -9842,9 +9885,7 @@
         public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
             DualTimer t = getSensorTimerLocked(sensor, /* create= */ true);
             t.startRunningLocked(elapsedRealtimeMs);
-            if (sensor == Sensor.GPS) {
-                StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), null, 1);
-            } else {
+            if (sensor != Sensor.GPS) {
                 StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null, sensor,
                         1);
             }
@@ -9855,14 +9896,9 @@
             DualTimer t = getSensorTimerLocked(sensor, false);
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
-                if (!t.isRunningLocked()) { // only tell statsd if truly stopped
-                    if (sensor == Sensor.GPS) {
-                        StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), null,
-                                0);
-                    } else {
-                        StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null,
-                                sensor, 0);
-                    }
+                if (sensor != Sensor.GPS) {
+                    StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null,
+                             sensor, 0);
                 }
             }
         }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5659470..39279b5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,7 @@
                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
                             instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
                             uuid, classLoaderContext, seInfo, false /* downgrade */,
-                            targetSdkVersion);
+                            targetSdkVersion, /*profileName*/ null);
                 } catch (RemoteException | ServiceSpecificException e) {
                     // Ignore (but log), we need this on the classpath for fallback mode.
                     Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 6af41a5..324f923 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -256,7 +256,7 @@
             final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
                     mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
             if (hgrav == Gravity.RIGHT) {
-                xOffset += mAnchorView.getWidth();
+                xOffset -= mAnchorView.getWidth();
             }
 
             popup.setHorizontalOffset(xOffset);
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index d9ca5be..445379b 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -263,7 +263,6 @@
                     mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
             subPopup.setPresenterCallback(mPresenterCallback);
             subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu));
-            subPopup.setGravity(mDropDownGravity);
 
             // Pass responsibility for handling onDismiss to the submenu.
             subPopup.setOnDismissListener(mOnDismissListener);
@@ -273,8 +272,17 @@
             mMenu.close(false /* closeAllMenus */);
 
             // Show the new sub-menu popup at the same location as this popup.
-            final int horizontalOffset = mPopup.getHorizontalOffset();
+            int horizontalOffset = mPopup.getHorizontalOffset();
             final int verticalOffset = mPopup.getVerticalOffset();
+
+            // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT,
+            // So, again to display sub-menu popup in same xOffset, add the Anchor width.
+            final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
+                mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
+            if (hgrav == Gravity.RIGHT) {
+              horizontalOffset += mAnchorView.getWidth();
+            }
+
             if (subPopup.tryShow(horizontalOffset, verticalOffset)) {
                 if (mPresenterCallback != null) {
                     mPresenterCallback.onOpenSubMenu(subMenu);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 102ff95..5751fc9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -163,6 +163,7 @@
         "android_media_AudioTrack.cpp",
         "android_media_DeviceCallback.cpp",
         "android_media_JetPlayer.cpp",
+        "android_media_MediaMetricsJNI.cpp",
         "android_media_RemoteDisplay.cpp",
         "android_media_ToneGenerator.cpp",
         "android_hardware_Camera.cpp",
@@ -261,6 +262,7 @@
         "libselinux",
         "libicuuc",
         "libmedia",
+        "libmediametrics",
         "libaudioclient",
         "libjpeg",
         "libusbhost",
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index e4da3c6..ebd16c7 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -31,6 +31,7 @@
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 #include "android_media_DeviceCallback.h"
+#include "android_media_MediaMetricsJNI.h"
 
 // ----------------------------------------------------------------------------
 
@@ -751,6 +752,39 @@
 }
 
 // ----------------------------------------------------------------------------
+static jobject
+android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz)
+{
+    ALOGV("android_media_AudioRecord_native_getMetrics");
+
+    sp<AudioRecord> lpRecord = getAudioRecord(env, thiz);
+
+    if (lpRecord == NULL) {
+        ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()");
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return (jobject) NULL;
+    }
+
+    // get what we have for the metrics from the record session
+    MediaAnalyticsItem *item = NULL;
+
+    status_t err = lpRecord->getMetrics(item);
+    if (err != OK) {
+        ALOGE("getMetrics failed");
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return (jobject) NULL;
+    }
+
+    jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
+
+    // housekeeping
+    delete item;
+    item = NULL;
+
+    return mybundle;
+}
+
+// ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static const JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
@@ -781,6 +815,8 @@
                              "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
     {"native_get_min_buff_size",
                              "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
+    {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
+                                         (void *)android_media_AudioRecord_native_getMetrics},
     {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
     {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
     {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 11011b1..afbc579 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -34,6 +34,7 @@
 
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
+#include "android_media_MediaMetricsJNI.h"
 #include "android_media_PlaybackParams.h"
 #include "android_media_DeviceCallback.h"
 #include "android_media_VolumeShaper.h"
@@ -1011,6 +1012,39 @@
     return (jint) nativeToJavaStatus(status);
 }
 
+// ----------------------------------------------------------------------------
+static jobject
+android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
+{
+    ALOGD("android_media_AudioTrack_native_getMetrics");
+
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+
+    if (lpTrack == NULL) {
+        ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return (jobject) NULL;
+    }
+
+    // get what we have for the metrics from the track
+    MediaAnalyticsItem *item = NULL;
+
+    status_t err = lpTrack->getMetrics(item);
+    if (err != OK) {
+        ALOGE("getMetrics failed");
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return (jobject) NULL;
+    }
+
+    jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
+
+    // housekeeping
+    delete item;
+    item = NULL;
+
+    return mybundle;
+}
+
 
 // ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
@@ -1275,6 +1309,8 @@
     {"native_get_underrun_count", "()I",      (void *)android_media_AudioTrack_get_underrun_count},
     {"native_get_flags",     "()I",      (void *)android_media_AudioTrack_get_flags},
     {"native_get_timestamp", "([J)I",    (void *)android_media_AudioTrack_get_timestamp},
+    {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
+                                         (void *)android_media_AudioTrack_native_getMetrics},
     {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
     {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
     {"native_get_output_sample_rate",
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/core/jni/android_media_MediaMetricsJNI.cpp
similarity index 100%
rename from media/jni/android_media_MediaMetricsJNI.cpp
rename to core/jni/android_media_MediaMetricsJNI.cpp
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/core/jni/android_media_MediaMetricsJNI.h
similarity index 100%
rename from media/jni/android_media_MediaMetricsJNI.h
rename to core/jni/android_media_MediaMetricsJNI.h
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index 03f8204..4756c13 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -21,65 +21,6 @@
 option java_multiple_files = true;
 option java_outer_classname = "ActivityManagerProto";
 
-// ActivityManager.java PROCESS_STATEs
-enum ProcessState {
-  // Order matters for process states, so values have been spaced to provide
-  // room for future additions.
-
-  // Not a real process state.
-  PROCESS_STATE_UNKNOWN = -100;
-  // Process is a persistent system process.
-  PROCESS_STATE_PERSISTENT = 0;
-  // Process is a persistent system process and is doing UI.
-  PROCESS_STATE_PERSISTENT_UI = 100;
-  // Process is hosting the current top activities. Note that this covers
-  // all activities that are visible to the user.
-  PROCESS_STATE_TOP = 200;
-  // Process is hosting a foreground service due to a system binding.
-  PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300;
-  // Process is hosting a foreground service.
-  PROCESS_STATE_FOREGROUND_SERVICE = 400;
-  // Process is important to the user, and something they are aware of.
-  PROCESS_STATE_IMPORTANT_FOREGROUND = 500;
-  // Process is important to the user, but not something they are aware of.
-  PROCESS_STATE_IMPORTANT_BACKGROUND = 600;
-  // Process is in the background transient so we will try to keep running.
-  PROCESS_STATE_TRANSIENT_BACKGROUND = 700;
-  // Process is in the background running a backup/restore operation.
-  PROCESS_STATE_BACKUP = 800;
-  // Process is in the background running a service. Unlike oom_adj, this
-  // level is used for both the normal running in background state and the
-  // executing operations state.
-  PROCESS_STATE_SERVICE = 900;
-  // Process is in the background running a receiver. Note that from the
-  // perspective of oom_adj, receivers run at a higher foreground level, but
-  // for our prioritization here that is not necessary and putting them
-  // below services means many fewer changes in some process states as they
-  // receive broadcasts.
-  PROCESS_STATE_RECEIVER = 1000;
-  // Same as PROCESS_STATE_TOP but while device is sleeping.
-  PROCESS_STATE_TOP_SLEEPING = 1100;
-  // Process is in the background, but it can't restore its state so we want
-  // to try to avoid killing it.
-  PROCESS_STATE_HEAVY_WEIGHT = 1200;
-  // Process is in the background but hosts the home activity.
-  PROCESS_STATE_HOME = 1300;
-  // Process is in the background but hosts the last shown activity.
-  PROCESS_STATE_LAST_ACTIVITY = 1400;
-  // Process is being cached for later use and contains activities.
-  PROCESS_STATE_CACHED_ACTIVITY = 1500;
-  // Process is being cached for later use and is a client of another cached
-  // process that contains activities.
-  PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600;
-  // Process is being cached for later use and has an activity that corresponds
-  // to an existing recent task.
-  PROCESS_STATE_CACHED_RECENT = 1700;
-  // Process is being cached for later use and is empty.
-  PROCESS_STATE_CACHED_EMPTY = 1800;
-  // Process does not exist.
-  PROCESS_STATE_NONEXISTENT = 1900;
-}
-
 // ActivityManager.java UID_OBSERVERs flags
 enum UidObserverFlag {
   // report changes in process state, original value is 1 << 0
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
new file mode 100644
index 0000000..2de2574
--- /dev/null
+++ b/core/proto/android/app/enums.proto
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+
+package android.app;
+
+option java_outer_classname = "AppProtoEnums";
+option java_multiple_files = true;
+
+// ActivityManager.java PROCESS_STATEs
+enum ProcessStateEnum {
+    // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values
+    // here are completely fixed and arbitrary. Order is irrelevant.
+    // No attempt need be made to keep them in sync.
+    // The values here must not be modified. Any new process states can be appended to the end.
+
+    // Process state that is unknown to this proto file (i.e. is not mapped
+    // by ActivityManager.processStateAmToProto()). Can only happen if there's a bug in the mapping.
+    PROCESS_STATE_UNKNOWN_TO_PROTO = 998;
+    // Not a real process state.
+    PROCESS_STATE_UNKNOWN = 999;
+    // Process is a persistent system process.
+    PROCESS_STATE_PERSISTENT = 1000;
+    // Process is a persistent system process and is doing UI.
+    PROCESS_STATE_PERSISTENT_UI = 1001;
+    // Process is hosting the current top activities. Note that this covers
+    // all activities that are visible to the user.
+    PROCESS_STATE_TOP = 1002;
+    // Process is hosting a foreground service.
+    PROCESS_STATE_FOREGROUND_SERVICE = 1003;
+    // Process is hosting a foreground service due to a system binding.
+    PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 1004;
+    // Process is important to the user, and something they are aware of.
+    PROCESS_STATE_IMPORTANT_FOREGROUND = 1005;
+    // Process is important to the user, but not something they are aware of.
+    PROCESS_STATE_IMPORTANT_BACKGROUND = 1006;
+    // Process is in the background transient so we will try to keep running.
+    PROCESS_STATE_TRANSIENT_BACKGROUND = 1007;
+    // Process is in the background running a backup/restore operation.
+    PROCESS_STATE_BACKUP = 1008;
+    // Process is in the background running a service. Unlike oom_adj, this
+    // level is used for both the normal running in background state and the
+    // executing operations state.
+    PROCESS_STATE_SERVICE = 1009;
+    // Process is in the background running a receiver. Note that from the
+    // perspective of oom_adj, receivers run at a higher foreground level, but
+    // for our prioritization here that is not necessary and putting them
+    // below services means many fewer changes in some process states as they
+    // receive broadcasts.
+    PROCESS_STATE_RECEIVER = 1010;
+    // Same as PROCESS_STATE_TOP but while device is sleeping.
+    PROCESS_STATE_TOP_SLEEPING = 1011;
+    // Process is in the background, but it can't restore its state so we want
+    // to try to avoid killing it.
+    PROCESS_STATE_HEAVY_WEIGHT = 1012;
+    // Process is in the background but hosts the home activity.
+    PROCESS_STATE_HOME = 1013;
+    // Process is in the background but hosts the last shown activity.
+    PROCESS_STATE_LAST_ACTIVITY = 1014;
+    // Process is being cached for later use and contains activities.
+    PROCESS_STATE_CACHED_ACTIVITY = 1015;
+    // Process is being cached for later use and is a client of another cached
+    // process that contains activities.
+    PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1016;
+    // Process is being cached for later use and has an activity that corresponds
+    // to an existing recent task.
+    PROCESS_STATE_CACHED_RECENT = 1017;
+    // Process is being cached for later use and is empty.
+    PROCESS_STATE_CACHED_EMPTY = 1018;
+    // Process does not exist.
+    PROCESS_STATE_NONEXISTENT = 1019;
+}
+
diff --git a/core/proto/android/app/notification.proto b/core/proto/android/app/notification.proto
index 5376b0e..379a4ae 100644
--- a/core/proto/android/app/notification.proto
+++ b/core/proto/android/app/notification.proto
@@ -18,6 +18,8 @@
 option java_package = "android.app";
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.app;
 
 /**
@@ -25,13 +27,15 @@
  * Deprecated fields are not included in the proto.
  */
 message NotificationProto {
-    optional string channel_id = 1;
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string channel_id = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional bool has_ticker_text = 2;
     optional int32 flags = 3;
     optional int32 color = 4;
-    optional string category = 5;
-    optional string group_key = 6;
-    optional string sort_key = 7;
+    optional string category = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string group_key = 6 [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string sort_key = 7 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional int32 action_length = 8;
 
     // If this field is not set, then the value is unknown.
diff --git a/core/proto/android/app/profilerinfo.proto b/core/proto/android/app/profilerinfo.proto
index ca1b935..6b28318 100644
--- a/core/proto/android/app/profilerinfo.proto
+++ b/core/proto/android/app/profilerinfo.proto
@@ -18,12 +18,16 @@
 option java_package = "android.app";
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.app;
 
 /**
  * An android.app.ProfilerInfo object.
  */
 message ProfilerInfoProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string profile_file = 1;
     optional int32 profile_fd = 2;
     optional int32 sampling_interval = 3;
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index 111b27f..a62d56c 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -22,11 +22,14 @@
 
 import "frameworks/base/core/proto/android/app/window_configuration.proto";
 import "frameworks/base/core/proto/android/content/locale.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 /**
  * An android resource configuration.
  */
 message ConfigurationProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional float font_scale = 1;
   optional uint32 mcc = 2;
   optional uint32 mnc = 3;
diff --git a/core/proto/android/content/featureinfo.proto b/core/proto/android/content/featureinfo.proto
index a750120..6878f0e 100644
--- a/core/proto/android/content/featureinfo.proto
+++ b/core/proto/android/content/featureinfo.proto
@@ -16,14 +16,20 @@
 
 syntax = "proto2";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_package = "android.content.pm";
 option java_multiple_files = true;
 
 package android.content.pm;
 
 message FeatureInfoProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Some hard coded feature name
     optional string name = 1;
     optional int32 version = 2;
+    // String representation of reqGlEsVersion.
     optional string gles_version = 3;
     optional int32 flags = 4;
 }
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index 3e5265a..c25b46d 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -21,9 +21,12 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/os/patternmatcher.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 // Next Tag: 13
 message IntentProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum DockState {
         // Used as an int value for Intent#EXTRA_DOCK_STATE to represent that
         // the phone is not in any dock.
@@ -48,13 +51,13 @@
 
     optional string action = 1;
     repeated string categories = 2;
-    optional string data = 3;
+    optional string data = 3  [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional string type = 4;
     optional string flag = 5;
     optional string package = 6;
     optional string component = 7;
     optional string source_bounds = 8;
-    optional string clip_data = 9;
+    optional string clip_data = 9  [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional string extras = 10;
     optional int32 content_user_hint = 11;
     optional string selector = 12;
@@ -62,9 +65,11 @@
 
 // Next Tag: 11
 message IntentFilterProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated string actions = 1;
     repeated string categories = 2;
-    repeated string data_schemes = 3;
+    repeated string data_schemes = 3  [ (.android.privacy).dest = DEST_EXPLICIT ];
     repeated android.os.PatternMatcherProto data_scheme_specs = 4;
     repeated AuthorityEntryProto data_authorities = 5;
     repeated android.os.PatternMatcherProto data_paths = 6;
@@ -75,6 +80,8 @@
 }
 
 message AuthorityEntryProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string host = 1;
     optional bool wild = 2;
     optional int32 port = 3;
diff --git a/core/proto/android/content/locale.proto b/core/proto/android/content/locale.proto
index f0de31c..2be3ab9 100644
--- a/core/proto/android/content/locale.proto
+++ b/core/proto/android/content/locale.proto
@@ -18,9 +18,13 @@
 option java_package = "android.content";
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.content;
 
 message LocaleProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string language = 1;
   optional string country = 2;
   optional string variant = 3;
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index 8470159..6e99bec 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -18,9 +18,13 @@
 option java_package = "android.content.pm";
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.content.pm;
 
 message PackageItemInfoProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     optional string package_name = 2;
     optional int32 label_res = 3;
@@ -31,6 +35,8 @@
 
 // Proto of android.content.pm.ApplicationInfo which extends PackageItemInfo
 message ApplicationInfoProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional PackageItemInfoProto package = 1;
     optional string permission = 2;
     optional string process_name = 3;
@@ -48,6 +54,8 @@
     repeated string split_class_loader_names = 15;
 
     message Version {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool enabled = 1;
         optional int32 min_sdk_version = 2;
         optional int32 target_sdk_version = 3;
@@ -57,6 +65,8 @@
     optional Version version = 16;
 
     message Detail {
+        option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
         optional string class_name = 1;
         optional string task_affinity = 2;
         optional int32 requires_smallest_width_dp = 3;
diff --git a/core/proto/android/graphics/point.proto b/core/proto/android/graphics/point.proto
index 5ae17cb..035b9fe 100644
--- a/core/proto/android/graphics/point.proto
+++ b/core/proto/android/graphics/point.proto
@@ -17,9 +17,13 @@
 syntax = "proto2";
 package android.graphics;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 message PointProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 x = 1;
   optional int32 y = 2;
 }
diff --git a/core/proto/android/graphics/rect.proto b/core/proto/android/graphics/rect.proto
index 562ffce..eb403fe 100644
--- a/core/proto/android/graphics/rect.proto
+++ b/core/proto/android/graphics/rect.proto
@@ -17,9 +17,13 @@
 syntax = "proto2";
 package android.graphics;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 message RectProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 left = 1;
   optional int32 top = 2;
   optional int32 right = 3;
diff --git a/core/proto/android/os/cpufreq.proto b/core/proto/android/os/cpufreq.proto
index a8da0bf..8481ffc 100644
--- a/core/proto/android/os/cpufreq.proto
+++ b/core/proto/android/os/cpufreq.proto
@@ -18,10 +18,13 @@
 option java_multiple_files = true;
 option java_outer_classname = "CpuFreqProto";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.os;
 
 // cpu frequency time from /sys/devices/system/cpu/cpufreq/all_time_in_state
 message CpuFreq {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 jiffy_hz = 1; // obtain by system config.
 
@@ -30,10 +33,13 @@
 
 // frequency time pre cpu, unit in jiffy, TODO: obtain jiffies.
 message CpuFreqStats {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional string cpu_name = 1;
 
     message TimeInState {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 state_khz = 1;  // cpu frequency
         optional int64 time_jiffy = 2; // number of jiffies
     }
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index cd151e2..ca43602 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -18,6 +18,8 @@
 option java_multiple_files = true;
 option java_outer_classname = "CpuInfoProto";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.os;
 
 /**
@@ -27,8 +29,11 @@
  * Next Tag: 6
  */
 message CpuInfo {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     message TaskStats {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 total = 1;    // total number of cpu tasks
         optional int32 running = 2;  // number of running tasks
         optional int32 sleeping = 3; // number of sleeping tasks
@@ -38,6 +43,8 @@
     optional TaskStats task_stats = 1;
 
     message MemStats { // unit in kB
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 total = 1;
         optional int32 used = 2;
         optional int32 free = 3;
@@ -48,6 +55,8 @@
     optional MemStats swap = 3;
 
     message CpuUsage { // unit is percentage %
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 cpu = 1;   // 400% cpu indicates 4 cores
         optional int32 user = 2;
         optional int32 nice = 3;
@@ -62,9 +71,11 @@
 
     // Next Tag: 13
     message Task {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 pid = 1;
         optional int32 tid = 2;
-        optional string user = 3;
+        optional string user = 3;   // the process name which uses cpu
         optional string pr = 4;     // priority of each task, using string type is because special value RT (real time)
         optional sint32 ni = 5;     // niceness value
         optional float cpu = 6;     // precentage of cpu usage of the task
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index 7e5be9d..c296dab 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -18,15 +18,21 @@
 option java_multiple_files = true;
 option java_outer_classname = "WakeupSourcesProto";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.os;
 
 message KernelWakeSources {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Kernel records of what caused the application processor to wake up
     repeated WakeupSourceProto wakeup_sources = 1;
 }
 
 // Next Tag: 11
 message WakeupSourceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Name of the event which triggers application processor
     optional string name = 1;
 
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
index ef84bb1..435c648 100644
--- a/core/proto/android/os/looper.proto
+++ b/core/proto/android/os/looper.proto
@@ -20,9 +20,12 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/os/messagequeue.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message LooperProto {
-    optional string thread_name = 1;
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string thread_name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional int64 thread_id = 2;
     optional int32 identity_hash_code = 3;
     optional android.os.MessageQueueProto queue = 4;
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
index 38e27a1..048d031 100644
--- a/core/proto/android/os/message.proto
+++ b/core/proto/android/os/message.proto
@@ -17,9 +17,12 @@
 syntax = "proto2";
 package android.os;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 option java_multiple_files = true;
 
 message MessageProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 when = 1;
     // Name of callback class.
     optional string callback = 2;
@@ -29,7 +32,7 @@
     optional int32 arg1 = 4;
     optional int32 arg2 = 5;
     // String representation of an arbitrary object to send to the recipient.
-    optional string obj = 6;
+    optional string obj = 6 [ (.android.privacy).dest = DEST_EXPLICIT ];
     // Name of target class.
     optional string target = 7;
     optional int32 barrier = 8;
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
index 5d4bff0..4bfcb81 100644
--- a/core/proto/android/os/messagequeue.proto
+++ b/core/proto/android/os/messagequeue.proto
@@ -20,8 +20,11 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/os/message.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message MessageQueueProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated android.os.MessageProto messages = 1;
     optional bool is_polling_locked = 2;
     optional bool is_quitting = 3;
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index f82ea76..b8f618b 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -18,6 +18,8 @@
 option java_multiple_files = true;
 option java_outer_classname = "PageTypeInfoProto";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 package android.os;
 
 /*
@@ -36,6 +38,7 @@
  *  Next tag: 5
  */
 message PageTypeInfo {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 page_block_order = 1;
 
@@ -48,6 +51,7 @@
 
 // Next tag: 5
 message MigrateTypeProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 node = 1;
 
@@ -61,6 +65,7 @@
 
 // Next tag: 9
 message BlockProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 node = 1;
 
diff --git a/core/proto/android/os/patternmatcher.proto b/core/proto/android/os/patternmatcher.proto
index d30315b..520f2f5 100644
--- a/core/proto/android/os/patternmatcher.proto
+++ b/core/proto/android/os/patternmatcher.proto
@@ -16,10 +16,13 @@
 
 syntax = "proto2";
 option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package android.os;
 
 message PatternMatcherProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     optional string pattern = 1;
 
     enum Type {
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 07b9ad0..694b94b 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -134,6 +134,8 @@
     optional bool   hal_instrumentation_enable = 11;
 
     message InitSvc {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         enum Status {
             STATUS_UNKNOWN = 0;
             STATUS_RUNNING = 1;
@@ -230,7 +232,7 @@
 
     // Read only properites on the device.
     message Ro {
-        optional bool  adb_secure = 1;
+        optional bool  adb_secure = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional string arch = 2;
         optional bool   audio_ignore_effects = 3;
         optional bool   audio_monitorRotation = 4;
@@ -265,6 +267,8 @@
 
         // boot.img's properties.
         message BootImage {
+            option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
             // When the boot.img is built.
             optional string build_date = 1;
             // UTC timestamp of build date.
@@ -278,12 +282,14 @@
         optional BootImage bootimage = 8;
 
         // Version of bootloader on device.
-        optional string bootloader = 9;
+        optional string bootloader = 9  [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Kernel bootmode, e.g. charger.
-        optional string bootmode = 10;
+        optional string bootmode = 10  [ (android.privacy).dest = DEST_AUTOMATIC ];
 
         // Android Platform build metadata.
         message Build {
+            option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional string date = 1;
             optional int64  date_utc = 2;
             optional string description = 3;
@@ -297,6 +303,8 @@
             optional string user = 11;
 
             message Version {
+                option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
                 optional string base_os = 1;
                 optional string codename = 2;
                 optional string incremental = 3;
@@ -313,10 +321,10 @@
         }
         optional Build build = 11;
 
-        optional bool   camera_notify_nfc = 12;
+        optional bool   camera_notify_nfc = 12  [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional string carrier = 13;
-        optional bool   com_android_dataroaming = 14;
-        optional bool   com_android_prov_mobiledata = 15;
+        optional bool   com_android_dataroaming = 14  [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional bool   com_android_prov_mobiledata = 15  [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional string com_google_clientidbase = 16;
 
         message Config {
@@ -341,6 +349,8 @@
         optional string gfx_driver_0 = 26;
 
         message Hardware {
+            option (android.msg_privacy).dest = DEST_LOCAL;
+
             optional string value = 1; // value of ro.hardware itself
 
             optional string activity_recognition = 2;
@@ -392,6 +402,8 @@
         optional int32  opengles_version = 31;
 
         message Product {
+            option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional string board = 1;
             optional string brand = 2;
             optional string cpu_abi = 3;
@@ -405,6 +417,8 @@
             optional string name = 11;
 
             message Vendor {
+                option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
                 optional string brand = 1;
                 optional string device = 2;
                 optional string manufacturer = 3;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 1434d82..55e6a74 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -19,6 +19,7 @@
 package com.android.server.am.proto;
 
 import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/app/notification.proto";
 import "frameworks/base/core/proto/android/app/profilerinfo.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -32,10 +33,13 @@
 import "frameworks/base/core/proto/android/server/intentresolver.proto";
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/util/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 option java_multiple_files = true;
 
 message ActivityManagerServiceProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional ActivityStackSupervisorProto activities = 1;
 
   optional BroadcastProto broadcasts = 2;
@@ -47,6 +51,8 @@
 
 // "dumpsys activity --proto activities"
 message ActivityStackSupervisorProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   repeated ActivityDisplayProto displays = 2;
   optional KeyguardControllerProto keyguard_controller = 3;
@@ -56,12 +62,16 @@
 
 /* represents ActivityStackSupervisor.ActivityDisplay */
 message ActivityDisplayProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated ActivityStackProto stacks = 3;
 }
 
 message ActivityStackProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated TaskRecordProto tasks = 3;
@@ -72,6 +82,8 @@
 }
 
 message TaskRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated ActivityRecordProto activities = 3;
@@ -88,6 +100,8 @@
 }
 
 message ActivityRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
   optional .com.android.server.wm.proto.IdentifierProto identifier = 2;
   optional string state = 3;
@@ -97,12 +111,16 @@
 }
 
 message KeyguardControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool keyguard_showing = 1;
   optional bool keyguard_occluded = 2;
 }
 
 // "dumpsys activity --proto broadcasts"
 message BroadcastProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   repeated ReceiverListProto  receiver_list = 1;
 
   optional .com.android.server.IntentResolverProto receiver_resolver = 2;
@@ -119,6 +137,8 @@
 }
 
 message ReceiverListProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional ProcessRecordProto app = 1;
   optional int32 pid = 2;
   optional int32 uid = 3;
@@ -130,6 +150,8 @@
 }
 
 message ProcessRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 pid = 1;
   optional string process_name = 2;
   optional int32 uid = 3;
@@ -140,11 +162,15 @@
 }
 
 message BroadcastRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 user_id = 1;
   optional string intent_action = 2;
 }
 
 message BroadcastFilterProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.content.IntentFilterProto intent_filter = 1;
   optional string required_permission = 2;
   optional string hex_hash = 3; // used to find the object in IntentResolver
@@ -152,6 +178,8 @@
 }
 
 message BroadcastQueueProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string queue_name = 1;
   repeated BroadcastRecordProto parallel_broadcasts = 2;
   repeated BroadcastRecordProto ordered_broadcasts = 3;
@@ -159,6 +187,8 @@
   repeated BroadcastRecordProto historical_broadcasts = 5;
 
   message BroadcastSummary {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional .android.content.IntentProto intent = 1;
     optional int64 enqueue_clock_time_ms = 2;
     optional int64 dispatch_clock_time_ms = 3;
@@ -168,14 +198,20 @@
 }
 
 message MemInfoProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int64 uptime_duration_ms = 1;
   optional int64 elapsed_realtime_ms = 2;
 
   message ProcessMemory {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 pid = 1;
     optional string process_name = 2;
 
     message MemoryInfo {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional string name = 1;
       // The proportional set size for the heap.
       optional int32 total_pss_kb = 2;
@@ -197,6 +233,8 @@
       }
     }
     message HeapInfo {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional MemoryInfo mem_info = 1;
       optional int32 heap_size_kb = 2;
       optional int32 heap_alloc_kb = 3;
@@ -212,6 +250,8 @@
     repeated MemoryInfo dalvik_details = 8;
 
     message AppSummary {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 java_heap_pss_kb = 1;
       optional int32 native_heap_pss_kb = 2;
       optional int32 code_pss_kb = 3;
@@ -230,9 +270,13 @@
   repeated ProcessMemory native_processes = 3;
 
   message AppData {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional ProcessMemory process_memory = 1;
 
     message ObjectStats {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 view_instance_count = 1;
       optional int32 view_root_instance_count = 2;
       optional int32 app_context_instance_count = 3;
@@ -250,11 +294,15 @@
     optional ObjectStats objects = 2;
 
     message SqlStats {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 memory_used_kb = 1;
       optional int32 pagecache_overflow_kb = 2;
       optional int32 malloc_size_kb = 3;
 
       message Database {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional string name = 1;
         optional int32 page_size = 2;
         optional int32 db_size = 3;
@@ -274,6 +322,8 @@
   repeated AppData app_processes = 4;
 
   message MemItem {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string tag = 1;
     optional string label = 2;
     optional int32 id = 3;
@@ -337,9 +387,13 @@
 }
 
 message StickyBroadcastProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 user = 1;
 
   message StickyAction {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     repeated .android.content.IntentProto intents = 2;
   }
@@ -348,6 +402,7 @@
 
 // "dumpsys activity --proto service"
 message ActiveServicesProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
   message ServicesByUser {
     optional int32 user_id = 1;
@@ -358,11 +413,15 @@
 
 // corresponds to ActivityManagerService.GrantUri Java class
 message GrantUriProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 source_user_id = 1;
-  optional string uri = 2;
+  optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
 
 message NeededUriGrantsProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string target_package = 1;
   optional int32 target_uid = 2;
   optional int32 flags = 3;
@@ -371,12 +430,16 @@
 }
 
 message UriPermissionOwnerProto {
+  option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
   optional string owner = 1;
   repeated GrantUriProto read_perms = 2;
   repeated GrantUriProto write_perms = 3;
 }
 
 message ServiceRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string short_name = 1;
   optional string hex_hash = 2;
   optional bool is_running = 3; // false if the application service is null
@@ -387,6 +450,8 @@
   optional string permission = 8;
 
   message AppInfo {
+    option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
     optional string base_dir = 1;
     optional string res_dir = 2;
     optional string data_dir = 3;
@@ -398,6 +463,8 @@
   optional bool delayed = 13;
 
   message Foreground {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 id = 1;
     optional .android.app.NotificationProto notification = 2;
   }
@@ -411,6 +478,8 @@
 
   // variables used to track states related to service start
   message Start {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional bool start_requested = 1;
     optional bool delayed_stop = 2;
     optional bool stop_if_killed = 3;
@@ -420,6 +489,8 @@
   optional Start start = 20;
 
   message ExecuteNesting {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 execute_nesting = 1;
     optional bool execute_fg = 2;
     optional .android.util.Duration executing_start = 3;
@@ -429,6 +500,8 @@
   optional .android.util.Duration destory_time = 22;
 
   message Crash {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 restart_count = 1;
     optional .android.util.Duration restart_delay = 2;
     optional .android.util.Duration next_restart_time = 3;
@@ -437,6 +510,8 @@
   optional Crash crash = 23;
 
   message StartItemProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 id = 1;
     optional .android.util.Duration duration = 2;
     optional int32 delivery_count = 3;
@@ -453,6 +528,8 @@
 }
 
 message ConnectionRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string hex_hash = 1;
   optional int32 user_id = 2;
 
@@ -480,12 +557,16 @@
 }
 
 message AppBindRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string hex_hash = 1;
   optional ProcessRecordProto client = 2;
   repeated ConnectionRecordProto connections = 3;
 }
 
 message IntentBindRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string hex_hash = 1;
   optional bool is_create = 2;
   optional .android.content.IntentProto intent = 3;
@@ -500,6 +581,8 @@
 
 // TODO: "dumpsys activity --proto processes"
 message ProcessesProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   repeated ProcessRecordProto procs = 1;
   repeated ProcessRecordProto isolated_procs = 2;
   repeated ActiveInstrumentationProto active_instrumentations = 3;
@@ -508,6 +591,8 @@
 
   // Process LRU list (sorted by oom_adj)
   message LruProcesses {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 size = 1;
     optional int32 non_act_at = 2;
     optional int32 non_svc_at = 3;
@@ -538,18 +623,24 @@
   optional bool config_will_change = 21;
 
   message ScreenCompatPackage {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string package = 1;
     optional int32 mode = 2;
   }
   repeated ScreenCompatPackage screen_compat_packages = 22;
 
   message UidObserverRegistrationProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 uid = 1;
     optional string package = 2;
     repeated .android.app.UidObserverFlag flags = 3;
     optional int32 cut_point = 4; // only available when UID_OBSERVER_PROCSTATE is on
 
     message ProcState {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 uid = 1;
       optional int32 state = 2;
     }
@@ -560,6 +651,8 @@
   repeated int32 device_idle_temp_whitelist = 25;
 
   message PendingTempWhitelist {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 target_uid = 1;
     optional int64 duration_ms = 2;
     optional string tag = 3;
@@ -567,6 +660,8 @@
   repeated PendingTempWhitelist pending_temp_whitelist = 26;
 
   message SleepStatus {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional .android.os.PowerManagerInternalProto.Wakefulness wakefulness = 1;
     repeated string sleep_tokens = 2;
     optional bool sleeping = 3;
@@ -576,12 +671,16 @@
   optional SleepStatus sleep_status = 27;
 
   message VoiceProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string session = 1;
     optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2;
   }
   optional VoiceProto running_voice = 28;
 
   message VrControllerProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum VrMode {
       FLAG_NON_VR_MODE = 0;
       FLAG_VR_MODE = 1;
@@ -593,6 +692,8 @@
   optional VrControllerProto vr_controller = 29;
 
   message DebugApp {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string debug_app = 1;
     optional string orig_debug_app = 2;
     optional bool debug_transient = 3;
@@ -602,10 +703,16 @@
   optional AppTimeTrackerProto current_tracker = 31;
 
   message MemWatchProcess {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message Process {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional string name = 1;
 
       message MemStats {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 uid = 1;
         optional string size = 2;
         optional string report_to = 3;
@@ -615,8 +722,10 @@
     repeated Process procs = 1;
 
     message Dump {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional string proc_name = 1;
-      optional string file = 2;
+      optional string file = 2  [ (.android.privacy).dest = DEST_EXPLICIT ];
       optional int32 pid = 3;
       optional int32 uid = 4;
     }
@@ -626,6 +735,8 @@
   optional string track_allocation_app = 33;
 
   message Profile {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string app_name = 1;
     optional ProcessRecordProto proc = 2;
     optional .android.app.ProfilerInfoProto info = 3;
@@ -636,6 +747,8 @@
   optional bool always_finish_activities = 36;
 
   message Controller {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string controller = 1;
     optional bool is_a_monkey = 2;
   }
@@ -666,6 +779,8 @@
 }
 
 message ActiveInstrumentationProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.content.ComponentNameProto class = 1;
   optional bool finished = 2;
   repeated ProcessRecordProto running_processes = 3;
@@ -674,14 +789,16 @@
   optional string profile_file = 6;
   optional string watcher = 7;
   optional string ui_automation_connection = 8;
-  optional string arguments = 9;
+  optional string arguments = 9  [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
 
 // Proto definition of com.android.server.am.UidRecord.java
 message UidRecordProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string hex_hash = 1;
   optional int32 uid = 2;
-  optional .android.app.ProcessState current = 3;
+  optional .android.app.ProcessStateEnum current = 3;
   optional bool ephemeral = 4;
   optional bool fg_services = 5;
   optional bool whilelist = 6;
@@ -699,6 +816,8 @@
   optional int32 num_procs = 10;
 
   message ProcStateSequence {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 cururent = 1;
     optional int64 last_network_updated = 2;
     optional int64 last_dispatched = 3;
@@ -708,12 +827,16 @@
 
 // proto of class ImportanceToken in ActivityManagerService
 message ImportanceTokenProto {
+  option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
   optional int32 pid = 1;
   optional string token = 2;
   optional string reason = 3;
 }
 
 message ProcessOomProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool persistent = 1;
   optional int32 num = 2;
   optional string oom_adj = 3;
@@ -733,7 +856,7 @@
     bool services = 6;
   }
 
-  optional .android.app.ProcessState state = 7;
+  optional .android.app.ProcessStateEnum state = 7;
   optional int32 trim_memory_level = 8;
   optional ProcessRecordProto proc = 9;
   optional string adj_type = 10;
@@ -749,13 +872,15 @@
   }
 
   message Detail {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 max_adj = 1;
     optional int32 cur_raw_adj = 2;
     optional int32 set_raw_adj = 3;
     optional int32 cur_adj = 4;
     optional int32 set_adj = 5;
-    optional .android.app.ProcessState current_state = 7;
-    optional .android.app.ProcessState set_state = 8;
+    optional .android.app.ProcessStateEnum current_state = 7;
+    optional .android.app.ProcessStateEnum set_state = 8;
     optional string last_pss = 9;
     optional string last_swap_pss = 10;
     optional string last_cached_pss = 11;
@@ -765,6 +890,8 @@
 
     // only make sense if process is a service
     message CpuRunTime {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int64 over_ms = 1;
       optional int64 used_ms = 2;
       optional float ultilization = 3; // ratio of cpu time usage
@@ -775,6 +902,8 @@
 }
 
 message ProcessToGcProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional ProcessRecordProto proc = 1;
   optional bool report_low_memory = 2;
   optional int64 now_uptime_ms = 3;
@@ -784,13 +913,18 @@
 
 // sync with com.android.server.am.AppErrors.java
 message AppErrorsProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
   optional int64 now_uptime_ms = 1;
 
   message ProcessCrashTime {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string process_name = 1;
 
     message Entry {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 uid = 1;
       optional int64 last_crashed_at_ms = 2;
     }
@@ -799,14 +933,18 @@
   repeated ProcessCrashTime process_crash_times = 2;
 
   message BadProcess {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string process_name = 1;
 
     message Entry {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional int32 uid = 1;
       optional int64 crashed_at_ms = 2;
       optional string short_msg = 3;
-      optional string long_msg = 4;
-      optional string stack = 5;
+      optional string long_msg = 4  [ (.android.privacy).dest = DEST_EXPLICIT ];
+      optional string stack = 5  [ (.android.privacy).dest = DEST_EXPLICIT ];
     }
     repeated Entry entries = 2;
   }
@@ -815,6 +953,8 @@
 
 // sync with com.android.server.am.UserState.java
 message UserStateProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   enum State {
     STATE_BOOTING = 0;
     STATE_RUNNING_LOCKED = 1;
@@ -829,7 +969,11 @@
 
 // sync with com.android.server.am.UserController.java
 message UserControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   message User {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 id = 1;
     optional UserStateProto state = 2;
   }
@@ -838,6 +982,8 @@
   repeated int32 user_lru = 3;
 
   message UserProfile {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 user = 1;
     optional int32 profile = 2;
   }
@@ -846,6 +992,8 @@
 
 // sync with com.android.server.am.AppTimeTracker.java
 message AppTimeTrackerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string receiver = 1;
   optional int64 total_duration_ms = 2;
 
diff --git a/core/proto/android/server/appwindowthumbnail.proto b/core/proto/android/server/appwindowthumbnail.proto
index e67b854..8f48d75 100644
--- a/core/proto/android/server/appwindowthumbnail.proto
+++ b/core/proto/android/server/appwindowthumbnail.proto
@@ -17,6 +17,7 @@
 syntax = "proto2";
 
 import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package com.android.server.wm.proto;
 option java_multiple_files = true;
@@ -25,6 +26,8 @@
  * Represents a {@link com.android.server.wm.AppWindowThumbnail} object.
  */
 message AppWindowThumbnailProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 width = 1;
   optional int32 height = 2;
   optional SurfaceAnimatorProto surface_animator = 3;
diff --git a/core/proto/android/server/fingerprint.proto b/core/proto/android/server/fingerprint.proto
index ec4ffe0..2a7fbc3 100644
--- a/core/proto/android/server/fingerprint.proto
+++ b/core/proto/android/server/fingerprint.proto
@@ -17,15 +17,21 @@
 syntax = "proto2";
 package com.android.server.fingerprint;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 option java_outer_classname = "FingerprintServiceProto";
 
 message FingerprintServiceDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Each log may include multiple tuples of (user_id, num_fingerprints).
     repeated FingerprintUserStatsProto users = 1;
 }
 
 message FingerprintUserStatsProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
     optional int32 user_id = 1;
 
@@ -42,6 +48,8 @@
 
 // A com.android.server.fingerprint.FingerpintService.PerformanceStats object.
 message PerformanceStatsProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Number of accepted fingerprints.
     optional int32 accept = 1;
 
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index c1bd692..babbef0 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -19,7 +19,7 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
 import "frameworks/base/core/proto/android/os/batterymanager.proto";
 import "frameworks/base/core/proto/android/os/looper.proto";
@@ -28,13 +28,20 @@
 import "frameworks/base/core/proto/android/providers/settings.proto";
 import "frameworks/base/core/proto/android/server/wirelesschargerdetector.proto";
 import "frameworks/base/core/proto/android/view/display.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message PowerManagerServiceDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // A com.android.server.power.PowerManagerService.Constants object.
     message ConstantsProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_no_cached_wake_locks = 1;
     }
     message ActiveWakeLocksProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_cpu = 1;
         optional bool is_screen_bright = 2;
         optional bool is_screen_dim = 3;
@@ -46,18 +53,21 @@
         optional bool is_draw = 8;
     }
     message UserActivityProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_screen_bright = 1;
         optional bool is_screen_dim = 2;
         optional bool is_screen_dream = 3;
     }
     // A com.android.server.power.PowerManagerService.UidState object.
     message UidStateProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 uid = 1;
         optional string uid_string = 2;
         optional bool is_active = 3;
         optional int32 num_wake_locks = 4;
-        optional bool is_process_state_unknown = 5;
-        optional .android.app.ProcessState process_state = 6;
+        optional .android.app.ProcessStateEnum process_state = 5;
     }
 
     optional ConstantsProto constants = 1;
@@ -167,13 +177,19 @@
 
 // A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
 message SuspendBlockerProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     optional int32 reference_count = 2;
 }
 
 // A com.android.server.power.PowerManagerService.WakeLock object.
 message WakeLockProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message WakeLockFlagsProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         // Turn the screen on when the wake lock is acquired.
         optional bool is_acquire_causes_wakeup = 1;
         // When this wake lock is released, poke the user activity timer
@@ -182,7 +198,7 @@
     }
 
     optional .android.os.PowerManagerProto.WakeLockLevel lock_level = 1;
-    optional string tag = 2;
+    optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional WakeLockFlagsProto flags = 3;
     optional bool is_disabled = 4;
     // Acquire time in ms
@@ -196,12 +212,18 @@
 }
 
 message PowerServiceSettingsAndConfigurationDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message StayOnWhilePluggedInProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_stay_on_while_plugged_in_ac = 1;
         optional bool is_stay_on_while_plugged_in_usb = 2;
         optional bool is_stay_on_while_plugged_in_wireless = 3;
     }
     message ScreenBrightnessSettingLimitsProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 setting_minimum = 1;
         optional int32 setting_maximum = 2;
         optional int32 setting_default = 3;
diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto
index 60713d7..7f7839e 100644
--- a/core/proto/android/server/surfaceanimator.proto
+++ b/core/proto/android/server/surfaceanimator.proto
@@ -17,6 +17,7 @@
 syntax = "proto2";
 
 import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package com.android.server.wm.proto;
 option java_multiple_files = true;
@@ -25,6 +26,8 @@
  * Represents a {@link com.android.server.wm.SurfaceAnimator} object.
  */
 message SurfaceAnimatorProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string animation_adapter = 1;
   optional .android.view.SurfaceControlProto leash = 2;
   optional bool animation_start_delayed = 3;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 71f33c7..c11058a 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -26,12 +26,15 @@
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
 import "frameworks/base/core/proto/android/view/surface.proto";
 import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package com.android.server.wm.proto;
 
 option java_multiple_files = true;
 
 message WindowManagerServiceProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowManagerPolicyProto policy = 1;
   /* window hierarchy root */
   optional RootWindowContainerProto root_window_container = 2;
@@ -46,6 +49,8 @@
 
 /* represents DisplayContent */
 message RootWindowContainerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   repeated DisplayProto displays = 2;
   /* window references in top down z order */
@@ -53,16 +58,22 @@
 }
 
 message BarControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.app.StatusBarManagerProto.WindowState state = 1;
   optional .android.app.StatusBarManagerProto.TransientWindowState transient_state = 2;
 }
 
 message WindowOrientationListenerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool enabled = 1;
   optional .android.view.SurfaceProto.Rotation rotation = 2;
 }
 
 message KeyguardServiceDelegateProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool showing = 1;
   optional bool occluded = 2;
   optional bool secure = 3;
@@ -84,6 +95,8 @@
 
 /* represents PhoneWindowManager */
 message WindowManagerPolicyProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 last_system_ui_flags = 1;
   enum UserRotationMode {
     USER_ROTATION_FREE = 0;
@@ -112,6 +125,8 @@
 
 /* represents AppTransition */
 message AppTransitionProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   enum AppState {
     APP_STATE_IDLE = 0;
     APP_STATE_READY = 1;
@@ -147,6 +162,8 @@
 
 /* represents DisplayContent */
 message DisplayProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   optional int32 id = 2;
   repeated StackProto stacks = 3;
@@ -165,22 +182,30 @@
 
 /* represents DisplayFrames */
 message DisplayFramesProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.graphics.RectProto stable_bounds = 1;
 }
 
 /* represents DockedStackDividerController */
 message DockedStackDividerControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool minimized_dock = 1;
 }
 
 /* represents PinnedStackController */
 message PinnedStackControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.graphics.RectProto default_bounds = 1;
   optional .android.graphics.RectProto movement_bounds = 2;
 }
 
 /* represents TaskStack */
 message StackProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   optional int32 id = 2;
   repeated TaskProto tasks = 3;
@@ -197,6 +222,8 @@
 
 /* represents Task */
 message TaskProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   optional int32 id = 2;
   repeated AppWindowTokenProto app_window_tokens = 3;
@@ -208,8 +235,10 @@
 
 /* represents AppWindowToken */
 message AppWindowTokenProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   /* obtained from ActivityRecord */
-  optional string name = 1;
+  optional string name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
   optional WindowTokenProto window_token = 2;
   optional bool last_surface_showing = 3;
   optional bool is_waiting_for_transition_start =  4;
@@ -236,6 +265,8 @@
 
 /* represents WindowToken */
 message WindowTokenProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   optional int32 hash_code = 2;
   repeated WindowStateProto windows = 3;
@@ -246,6 +277,8 @@
 
 /* represents WindowState */
 message WindowStateProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional WindowContainerProto window_container = 1;
   optional IdentifierProto identifier = 2;
   optional int32 display_id = 3;
@@ -287,13 +320,17 @@
 }
 
 message IdentifierProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 hash_code = 1;
   optional int32 user_id = 2;
-  optional string title = 3;
+  optional string title = 3  [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
 
 /* represents WindowStateAnimator */
 message WindowStateAnimatorProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.graphics.RectProto last_clip_rect = 1;
   optional WindowSurfaceControllerProto surface = 2;
   enum DrawState {
@@ -309,18 +346,24 @@
 
 /* represents WindowSurfaceController */
 message WindowSurfaceControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool shown = 1;
   optional int32 layer = 2;
 }
 
 /* represents ScreenRotationAnimation */
 message ScreenRotationAnimationProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional bool started = 1;
   optional bool animation_running = 2;
 }
 
 /* represents WindowContainer */
 message WindowContainerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional ConfigurationContainerProto configuration_container = 1;
   optional int32 orientation = 2;
   optional bool visible = 3;
@@ -329,6 +372,8 @@
 
 /* represents ConfigurationContainer */
 message ConfigurationContainerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional .android.content.ConfigurationProto override_configuration = 1;
   optional .android.content.ConfigurationProto full_configuration = 2;
   optional .android.content.ConfigurationProto merged_override_configuration = 3;
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
index 3c7a0e3..3d7ee91 100644
--- a/core/proto/android/service/diskstats.proto
+++ b/core/proto/android/service/diskstats.proto
@@ -17,10 +17,14 @@
 syntax = "proto2";
 package android.service.diskstats;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 option java_outer_classname = "DiskStatsServiceProto";
 
 message DiskStatsServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum EncryptionType {
         // Unknown encryption type
         ENCRYPTION_UNKNOWN = 0;
@@ -34,7 +38,7 @@
     // Whether the latency test resulted in an error
     optional bool has_test_error = 1;
     // If the test errored, error message is contained here
-    optional string error_message = 2;
+    optional string error_message = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
     // 512B write latency in milliseconds, if the test was successful
     optional int32 write_512b_latency_millis = 3;
     // Free Space in the major partitions
@@ -48,6 +52,8 @@
 }
 
 message DiskStatsCachedValuesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Total app code size, in kilobytes
     optional int64 agg_apps_size = 1;
     // Total app cache size, in kilobytes
@@ -71,6 +77,8 @@
 }
 
 message DiskStatsAppSizesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Name of the package
     optional string package_name = 1;
     // App's code size in kilobytes
@@ -82,6 +90,8 @@
 }
 
 message DiskStatsFreeSpaceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Folder {
         // Data folder
         FOLDER_DATA = 0;
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index ad9191c..29fd195 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -17,11 +17,15 @@
 syntax = "proto2";
 package android.service;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 option java_outer_classname = "NetworkStatsServiceProto";
 
 // Represents dumpsys from NetworkStatsService (netstats).
 message NetworkStatsServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated NetworkInterfaceProto active_interfaces = 1;
 
     repeated NetworkInterfaceProto active_uid_interfaces = 2;
@@ -41,6 +45,8 @@
 
 // Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
 message NetworkInterfaceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string interface = 1;
 
     optional NetworkIdentitySetProto identities = 2;
@@ -48,17 +54,21 @@
 
 // Corresponds to NetworkIdentitySet.
 message NetworkIdentitySetProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated NetworkIdentityProto identities = 1;
 }
 
 // Corresponds to NetworkIdentity.
 message NetworkIdentityProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Constats from ConnectivityManager.TYPE_*.
     optional int32 type = 1;
 
-    optional string subscriber_id = 2;
+    optional string subscriber_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
 
-    optional string network_id = 3;
+    optional string network_id = 3 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     optional bool roaming = 4;
 
@@ -69,6 +79,8 @@
 
 // Corresponds to NetworkStatsRecorder.
 message NetworkStatsRecorderProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 pending_total_bytes = 1;
 
     optional NetworkStatsCollectionProto complete_history = 2;
@@ -76,11 +88,15 @@
 
 // Corresponds to NetworkStatsCollection.
 message NetworkStatsCollectionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated NetworkStatsCollectionStatsProto stats = 1;
 }
 
 // Corresponds to NetworkStatsCollection.mStats.
 message NetworkStatsCollectionStatsProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional NetworkStatsCollectionKeyProto key = 1;
 
     optional NetworkStatsHistoryProto history = 2;
@@ -88,6 +104,8 @@
 
 // Corresponds to NetworkStatsCollection.Key.
 message NetworkStatsCollectionKeyProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional NetworkIdentitySetProto identity = 1;
 
     optional int32 uid = 2;
@@ -99,6 +117,8 @@
 
 // Corresponds to NetworkStatsHistory.
 message NetworkStatsHistoryProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Duration for this bucket in milliseconds.
     optional int64 bucket_duration_ms = 1;
 
@@ -107,6 +127,8 @@
 
 // Corresponds to each bucket in NetworkStatsHistory.
 message NetworkStatsHistoryBucketProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Bucket start time in milliseconds since epoch.
     optional int64 bucket_start_ms = 1;
 
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index aa1a575..ef777de 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -18,18 +18,25 @@
 package android.service.pm;
 
 import "frameworks/base/core/proto/android/content/featureinfo.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 option java_multiple_files = true;
 option java_outer_classname = "PackageServiceProto";
 
 message PackageServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message PackageShortProto {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         // Name of package. e.g. "com.android.providers.telephony".
         optional string name = 1;
         // UID for this package as assigned by Android OS.
         optional int32 uid = 2;
     }
     message SharedLibraryProto {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional string name = 1;
         // True if library path is not null (jar), false otherwise (apk)
         optional bool is_jar = 2;
@@ -39,8 +46,10 @@
         optional string apk = 4;
     }
     message SharedUserProto {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 user_id = 1;
-        optional string name = 2;
+        optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
     }
 
     // Installed packages.
@@ -51,15 +60,22 @@
     repeated PackageProto packages = 5;
     repeated SharedUserProto shared_users = 6;
     // Messages from the settings problem file
-    repeated string messages = 7;
+    repeated string messages = 7 [ (android.privacy).dest = DEST_EXPLICIT ];
 }
 
 message PackageProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message SplitProto {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+        // The split name of package, e.g. base
         optional string name = 1;
         optional int32 revision_code = 2;
     }
     message UserInfoProto {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         enum InstallType {
             NOT_INSTALLED_FOR_USER = 0;
             FULL_APP_INSTALL = 1;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index b2e0373..4c11f1e 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -19,6 +19,7 @@
 option java_outer_classname = "ProcessStatsServiceProto";
 
 import "frameworks/base/core/proto/android/util/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package android.service.procstats;
 
@@ -28,6 +29,7 @@
  * Next Tag: 4
  */
 message ProcessStatsServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional ProcessStatsSectionProto procstats_now = 1;
 
@@ -43,6 +45,7 @@
  * Next Tag: 9
  */
 message ProcessStatsSectionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Elapsed realtime at start of report.
     optional int64 start_realtime_ms = 1;
@@ -78,6 +81,7 @@
 
 // Next Tag: 6
 message ProcessStatsProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     // Name of process.
     optional string process = 1;
@@ -87,6 +91,8 @@
 
     // Information about how often kills occurred
     message Kill {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
       // Count of excessive CPU kills
       optional int32 cpu = 1;
 
@@ -99,6 +105,8 @@
     optional Kill kill = 3;
 
     message State {
+        option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
         enum ScreenState {
             SCREEN_UNKNOWN = 0;
             OFF = 1;
@@ -115,6 +123,8 @@
         }
         optional MemoryState memory_state = 2;
 
+        // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+        // and not frameworks/base/core/java/android/app/ActivityManager.java
         enum ProcessState {
             PROCESS_UNKNOWN = 0;
             // Persistent system process.
@@ -127,14 +137,14 @@
             IMPORTANT_BACKGROUND = 4;
             // Performing backup operation.
             BACKUP = 5;
-            // Heavy-weight process (currently not used).
-            HEAVY_WEIGHT = 6;
             // Background process running a service.
-            SERVICE = 7;
+            SERVICE = 6;
             // Process not running, but would be if there was enough RAM.
-            SERVICE_RESTARTING = 8;
+            SERVICE_RESTARTING = 7;
             // Process running a receiver.
-            RECEIVER = 9;
+            RECEIVER = 8;
+            // Heavy-weight process (currently not used).
+            HEAVY_WEIGHT = 9;
             // Process hosting home/launcher app when not on top.
             HOME = 10;
             // Process hosting the last app the user was in.
diff --git a/core/proto/android/util/common.proto b/core/proto/android/util/common.proto
index 308ef70..f8f7885 100644
--- a/core/proto/android/util/common.proto
+++ b/core/proto/android/util/common.proto
@@ -17,12 +17,15 @@
 syntax = "proto2";
 package android.util;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 /**
  * Very basic data structure used by aggregated stats.
  */
 message AggStats {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int64 min = 1;
 
@@ -35,6 +38,7 @@
  * Very basic data structure to represent Duration.
  */
 message Duration {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int64 start_ms = 1;
 
diff --git a/core/proto/android/util/log.proto b/core/proto/android/util/log.proto
index fd4fa9e..416c055 100644
--- a/core/proto/android/util/log.proto
+++ b/core/proto/android/util/log.proto
@@ -17,11 +17,15 @@
 syntax = "proto2";
 package android.util;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 // Represents a Text Log in logd
 // Next Tag: 9
 message TextLogEntry {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     optional uint64 sec = 1;
     optional uint64 nanosec = 2;
 
@@ -47,6 +51,8 @@
 // Represents a Binary Log in logd, need to look event-log-tags for more info.
 // Next Tag: 8
 message BinaryLogEntry {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     optional uint64 sec = 1;
     optional uint64 nanosec = 2;
     optional int32 uid = 3;
@@ -81,6 +87,8 @@
 }
 
 message LogProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     repeated TextLogEntry text_logs = 1;
 
     repeated BinaryLogEntry binary_logs = 2;
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index 9ca4046..3ac8f3b 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -17,10 +17,14 @@
 syntax = "proto2";
 package android.view;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 /* represents DisplayInfo */
 message DisplayInfoProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 logical_width = 1;
   optional int32 logical_height = 2;
   optional int32 app_width = 3;
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index f079e1e..0362ab1 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -18,12 +18,15 @@
 
 import "frameworks/base/core/proto/android/graphics/pixelformat.proto";
 import "frameworks/base/core/proto/android/view/display.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package android.view;
 option java_multiple_files = true;
 
 /* represents WindowManager.LayoutParams */
 message WindowLayoutParamsProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 type = 1;
   optional int32 x = 2;
   optional int32 y = 3;
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
index 3254ebb..6f3dc8c 100644
--- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -20,19 +20,54 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false" android:zAdjustment="top">
 
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-           android:startOffset="300"
-           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:interpolator="@interpolator/decelerate_quart"
-           android:duration="167"/>
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="67"
+        android:duration="217"/>
 
-    <translate android:fromYDelta="110%" android:toYDelta="0"
-               android:startOffset="300"
-               android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-               android:interpolator="@interpolator/decelerate_quint"
-               android:duration="417"/>
+    <translate
+        android:fromXDelta="-105%"
+        android:toXDelta="0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/aggressive_ease"
+        android:startOffset="50"
+        android:duration="383"/>
 
-    <!-- To keep the thumbnail around longer -->
+    <scale
+        android:fromXScale="1.0526"
+        android:toXScale="1"
+        android:fromYScale="1.0526"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_slow_in"
+        android:duration="283"/>
+
+    <scale
+        android:fromXScale="0.95"
+        android:toXScale="1"
+        android:fromYScale="0.95"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_slow_in"
+        android:startOffset="283"
+        android:duration="317"/>
+
+    <!-- To keep the thumbnail around longer and fade out the thumbnail -->
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
            android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 2ee7cd8..0e66eda 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -14,7 +14,9 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
---><!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+-->
+<!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+<!-- This should in sync with cross_profile_apps_thumbnail_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false"
     android:zAdjustment="top">
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index f8a77f8..ce4ac61 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -44,7 +44,8 @@
 
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
-    <color name="error_color_material">#F4511E</color>
+    <color name="error_color_material_dark">#ff7043</color><!-- deep orange 400 -->
+    <color name="error_color_material_light">#ff5722</color><!-- deep orange 500 -->
 
     <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
     <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 012212f3..69d96fc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2731,6 +2731,15 @@
     <!-- Label for item in the text selection menu to trigger adding a contact [CHAR LIMIT=20] -->
     <string name="add_contact">Add</string>
 
+    <!-- Label for item in the text selection menu to view the calendar for the selected time/date [CHAR LIMIT=20] -->
+    <string name="view_calendar">View</string>
+
+    <!-- Label for item in the text selection menu to create a calendar event at the selected time/date [CHAR LIMIT=20] -->
+    <string name="add_calendar_event">Schedule</string>
+
+    <!-- Label for item in the text selection menu to track a selected flight number [CHAR LIMIT=20] -->
+    <string name="view_flight">Track</string>
+
     <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the title of that notification. -->
     <string name="low_internal_storage_view_title">Storage space running out</string>
     <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the message of that notification. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f94168d..710bbfb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -533,6 +533,9 @@
   <java-symbol type="string" name="browse" />
   <java-symbol type="string" name="sms" />
   <java-symbol type="string" name="add_contact" />
+  <java-symbol type="string" name="view_calendar" />
+  <java-symbol type="string" name="add_calendar_event" />
+  <java-symbol type="string" name="view_flight" />
   <java-symbol type="string" name="textSelectionCABTitle" />
   <java-symbol type="string" name="BaMmi" />
   <java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9e6b1ab..15d8fb7 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -51,7 +51,7 @@
         <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
         <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
-        <item name="colorError">@color/error_color_material</item>
+        <item name="colorError">@color/error_color_material_dark</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
@@ -420,6 +420,7 @@
         <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
         <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_light</item>
         <item name="backgroundDimAmount">0.6</item>
+        <item name="colorError">@color/error_color_material_light</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
@@ -811,6 +812,7 @@
         <item name="colorBackground">@color/background_material_light</item>
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
+        <item name="colorError">@color/error_color_material_light</item>
 
         <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
@@ -844,6 +846,7 @@
         <item name="colorBackground">@color/background_material_dark</item>
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
+        <item name="colorError">@color/error_color_material_dark</item>
 
         <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index 896fd15..370659e 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -122,6 +122,7 @@
 
     private void resetCallback() {
         verify(mCallback, atLeast(0)).onMetadataChanged(any());
+        verify(mCallback, atLeast(0)).onProgramInfoChanged(any());
         verifyNoMoreInteractions(mCallback);
         Mockito.reset(mCallback);
     }
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3e38010..53c22f6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1045,6 +1045,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml
new file mode 100644
index 0000000..3b9e2bd
--- /dev/null
+++ b/core/tests/coretests/res/layout/context_menu.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <LinearLayout
+            android:id="@+id/context_menu_target_ltr"
+            android:orientation="horizontal"
+            android:layoutDirection="ltr"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="50px"
+            android:layout_marginEnd="50px">
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="LTR"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:id="@+id/context_menu_target_rtl"
+            android:orientation="horizontal"
+            android:layoutDirection="rtl"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="50px"
+            android:layout_marginEnd="50px">
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="RTL"/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java
index a427a2f..952a64d 100644
--- a/core/tests/coretests/src/android/os/WorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceTest.java
@@ -349,6 +349,15 @@
         assertEquals(100, wc.getAttributionUid());
     }
 
+    public void testGetAttributionTag() {
+        WorkSource ws1 = new WorkSource();
+        WorkChain wc = ws1.createWorkChain();
+        wc.addNode(100, "tag");
+        assertEquals("tag", wc.getAttributionTag());
+        wc.addNode(200, "tag2");
+        assertEquals("tag", wc.getAttributionTag());
+    }
+
     public void testRemove_fromChainedWorkSource() {
         WorkSource ws1 = new WorkSource();
         ws1.createWorkChain().addNode(50, "foo");
@@ -368,4 +377,25 @@
         assertEquals(1, ws1.getWorkChains().size());
         assertEquals(75, ws1.getWorkChains().get(0).getAttributionUid());
     }
+
+    public void testTransferWorkChains() {
+        WorkSource ws1 = new WorkSource();
+        WorkChain wc1 = ws1.createWorkChain().addNode(100, "tag");
+        WorkChain wc2 = ws1.createWorkChain().addNode(200, "tag2");
+
+        WorkSource ws2 = new WorkSource();
+        ws2.transferWorkChains(ws1);
+
+        assertEquals(0, ws1.getWorkChains().size());
+        assertEquals(2, ws2.getWorkChains().size());
+        assertSame(wc1, ws2.getWorkChains().get(0));
+        assertSame(wc2, ws2.getWorkChains().get(1));
+
+        ws1.clear();
+        ws1.createWorkChain().addNode(300, "tag3");
+        ws1.transferWorkChains(ws2);
+        assertEquals(0, ws2.getWorkChains().size());
+        assertSame(wc1, ws1.getWorkChains().get(0));
+        assertSame(wc2, ws1.getWorkChains().get(1));
+    }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1520fb6..2f747ec 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -497,6 +497,7 @@
                  Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
                  Settings.Secure.INSTALL_NON_MARKET_APPS,
                  Settings.Secure.LAST_SETUP_SHOWN,
+                 Settings.Secure.LOCATION_CHANGER,
                  Settings.Secure.LOCATION_MODE,
                  Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, // Candidate?
                  Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java
new file mode 100644
index 0000000..468b9b2
--- /dev/null
+++ b/core/tests/coretests/src/android/util/PollingCheck.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import org.junit.Assert;
+
+/**
+ * Utility used for testing that allows to poll for a certain condition to happen within a timeout.
+ *
+ * Code copied from com.android.compatibility.common.util.PollingCheck
+ */
+public abstract class PollingCheck {
+
+    private static final long DEFAULT_TIMEOUT = 3000;
+    private static final long TIME_SLICE = 50;
+    private final long mTimeout;
+
+    /**
+     * The condition that the PollingCheck should use to proceed successfully.
+     */
+    public interface PollingCheckCondition {
+
+        /**
+         * @return Whether the polling condition has been met.
+         */
+        boolean canProceed();
+    }
+
+    public PollingCheck(long timeout) {
+        mTimeout = timeout;
+    }
+
+    protected abstract boolean check();
+
+    /**
+     * Start running the polling check.
+     */
+    public void run() {
+        if (check()) {
+            return;
+        }
+
+        long timeout = mTimeout;
+        while (timeout > 0) {
+            try {
+                Thread.sleep(TIME_SLICE);
+            } catch (InterruptedException e) {
+                Assert.fail("unexpected InterruptedException");
+            }
+
+            if (check()) {
+                return;
+            }
+
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail("unexpected timeout");
+    }
+
+    /**
+     * Instantiate and start polling for a given condition with a default 3000ms timeout.
+     *
+     * @param condition The condition to check for success.
+     */
+    public static void waitFor(final PollingCheckCondition condition) {
+        new PollingCheck(DEFAULT_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+
+    /**
+     * Instantiate and start polling for a given condition.
+     *
+     * @param timeout Time out in ms
+     * @param condition The condition to check for success.
+     */
+    public static void waitFor(long timeout, final PollingCheckCondition condition) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+}
+
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
new file mode 100644
index 0000000..830b3d5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.menu;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+public class ContextMenuActivity extends Activity {
+
+    static final String LABEL_ITEM = "Item";
+    static final String LABEL_SUBMENU = "Submenu";
+    static final String LABEL_SUBITEM = "Subitem";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.context_menu);
+        registerForContextMenu(getTargetLtr());
+        registerForContextMenu(getTargetRtl());
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        menu.add(LABEL_ITEM);
+        menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM);
+    }
+
+    View getTargetLtr() {
+        return findViewById(R.id.context_menu_target_ltr);
+    }
+
+    View getTargetRtl() {
+        return findViewById(R.id.context_menu_target_rtl);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
new file mode 100644
index 0000000..59d4e55
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.menu;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.support.test.filters.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
+import android.util.PollingCheck;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.espresso.ContextMenuUtils;
+
+@MediumTest
+public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
+
+    public ContextMenuTest() {
+        super("com.android.frameworks.coretests", ContextMenuActivity.class);
+    }
+
+    public void testContextMenuPositionLtr() throws InterruptedException {
+        testMenuPosition(getActivity().getTargetLtr());
+    }
+
+    public void testContextMenuPositionRtl() throws InterruptedException {
+        testMenuPosition(getActivity().getTargetRtl());
+    }
+
+    private void testMenuPosition(View target) throws InterruptedException {
+        final int minScreenDimension = getMinScreenDimension();
+        if (minScreenDimension < 320) {
+            // Assume there is insufficient room for the context menu to be aligned properly.
+            return;
+        }
+
+        int offsetX = target.getWidth() / 2;
+        int offsetY = target.getHeight() / 2;
+
+        getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY));
+
+        PollingCheck.waitFor(
+                () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU));
+
+        ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+
+        ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU);
+
+        PollingCheck.waitFor(
+                () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM));
+
+        if (minScreenDimension < getCascadingMenuTreshold()) {
+            // A non-cascading submenu should be displayed at the same location as its parent.
+            // Not testing cascading submenu position, as it is positioned differently.
+            ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+        }
+    }
+
+    /**
+     * Returns the minimum of the default display's width and height.
+     */
+    private int getMinScreenDimension() {
+        final WindowManager windowManager = (WindowManager) getActivity().getSystemService(
+                Context.WINDOW_SERVICE);
+        final Display display = windowManager.getDefaultDisplay();
+        final Point displaySize = new Point();
+        display.getRealSize(displaySize);
+        return Math.min(displaySize.x, displaySize.y);
+    }
+
+    /**
+     * Returns the minimum display size where cascading submenus are supported.
+     */
+    private int getCascadingMenuTreshold() {
+        // Use the same dimension resource as in MenuPopupHelper.createPopup().
+        return getActivity().getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.cascading_menus_min_smallest_width);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index 9ee7fac..8a81743 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -32,7 +32,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Calendar;
 import java.util.Locale;
+import java.util.TimeZone;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -146,8 +148,12 @@
 
     @Test
     public void testParcelOptions() {
+        Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+        referenceTime.setTimeInMillis(946771200000L);  // 2000-01-02
+
         TextClassification.Options reference = new TextClassification.Options();
         reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
+        reference.setReferenceTime(referenceTime);
 
         // Parcel and unparcel.
         final Parcel parcel = Parcel.obtain();
@@ -157,5 +163,6 @@
                 parcel);
 
         assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+        assertEquals(referenceTime, result.getReferenceTime());
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
index c8218aa..02ee9be 100644
--- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -17,25 +17,33 @@
 package android.widget.espresso;
 
 import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
 import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
 import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
 import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
 import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.not;
 
-import com.android.internal.view.menu.ListMenuItemView;
-
 import android.support.test.espresso.NoMatchingRootException;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewInteraction;
 import android.support.test.espresso.matcher.ViewMatchers;
+import android.view.View;
 import android.widget.MenuPopupWindow.MenuDropDownListView;
 
+import com.android.internal.view.menu.ListMenuItemView;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
 /**
  * Espresso utility methods for the context menu.
  */
@@ -82,10 +90,15 @@
     private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
             boolean enabled) {
         onContextMenu().check(matches(
-                hasDescendant(allOf(
-                        isAssignableFrom(ListMenuItemView.class),
-                        enabled ? isEnabled() : not(isEnabled()),
-                        hasDescendant(withText(itemLabel))))));
+                hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled))));
+    }
+
+    private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) {
+        return allOf(
+                isAssignableFrom(ListMenuItemView.class),
+                hasDescendant(withText(itemLabel)),
+                enabled ? isEnabled() : not(isEnabled()),
+                isDisplayingAtLeast(90));
     }
 
     /**
@@ -107,4 +120,70 @@
     public static void assertContextMenuContainsItemDisabled(String itemLabel) {
         asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
     }
+
+    /**
+     * Asserts that the context menu window is aligned to a given view with a given offset.
+     *
+     * @param anchor Anchor view.
+     * @param offsetX x offset
+     * @param offsetY y offset.
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) {
+        int [] expectedLocation = new int[2];
+        anchor.getLocationOnScreen(expectedLocation);
+        expectedLocation[0] += offsetX;
+        expectedLocation[1] += offsetY;
+
+        final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+        onContextMenu().check(matches(new TypeSafeMatcher<View>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("root view ");
+                description.appendText(rtl ? "right" : "left");
+                description.appendText("=");
+                description.appendText(Integer.toString(offsetX));
+                description.appendText(", top=");
+                description.appendText(Integer.toString(offsetY));
+            }
+
+            @Override
+            public boolean matchesSafely(View view) {
+                View rootView = view.getRootView();
+                int [] actualLocation = new int[2];
+                rootView.getLocationOnScreen(actualLocation);
+                if (rtl) {
+                    actualLocation[0] += rootView.getWidth();
+                }
+                return expectedLocation[0] == actualLocation[0]
+                    && expectedLocation[1] == actualLocation[1];
+            }
+        }));
+    }
+
+    /**
+     * Check is the menu item is clickable (i.e. visible and enabled).
+     *
+     * @param itemLabel Label of the item.
+     * @return True if the menu item is clickable.
+     */
+    public static boolean isMenuItemClickable(String itemLabel) {
+        try {
+            onContextMenu().check(matches(
+                    hasDescendant(getVisibleMenuItemMatcher(itemLabel, true))));
+            return true;
+        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+            return false;
+        }
+    }
+
+    /**
+     * Click on a menu item with the specified label
+     * @param itemLabel Label of the item.
+     */
+    public static void clickMenuItem(String itemLabel) {
+        onView(getVisibleMenuItemMatcher(itemLabel, true))
+                .inRoot(withDecorView(hasFocus())).perform(click());
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index a55563a..82ac9da 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -23,10 +23,12 @@
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
+import android.os.BatteryStats.Uid.Sensor;
 import android.os.WorkSource;
 import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import com.android.internal.os.BatteryStatsImpl.DualTimer;
 import com.android.internal.os.BatteryStatsImpl.Uid;
 import junit.framework.TestCase;
 
@@ -446,4 +448,52 @@
         pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
         assertEquals(0, pkg.getWakeupAlarmStats().size());
     }
+
+    @SmallTest
+    public void testNoteGpsChanged() {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+        bi.mForceOnBattery = true;
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        WorkSource ws = new WorkSource();
+        ws.add(UID);
+
+        bi.noteGpsChangedLocked(new WorkSource(), ws);
+        DualTimer t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+        assertNotNull(t);
+        assertTrue(t.isRunningLocked());
+
+        bi.noteGpsChangedLocked(ws, new WorkSource());
+        t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+        assertFalse(t.isRunningLocked());
+    }
+
+    @SmallTest
+    public void testNoteGpsChanged_workSource() {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+        bi.mForceOnBattery = true;
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        WorkSource ws = new WorkSource();
+        ws.createWorkChain().addNode(UID, "com.foo");
+
+        bi.noteGpsChangedLocked(new WorkSource(), ws);
+        DualTimer t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+        assertNotNull(t);
+        assertTrue(t.isRunningLocked());
+
+        bi.noteGpsChangedLocked(ws, new WorkSource());
+        t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+        assertFalse(t.isRunningLocked());
+    }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index e25386b..ded427e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -38,6 +38,7 @@
 import android.security.keystore.KeyExpiredException;
 import android.security.keystore.KeyNotYetValidException;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.StrongBoxUnavailableException;
 import android.security.keystore.UserNotAuthenticatedException;
 import android.util.Log;
 
@@ -65,6 +66,7 @@
     public static final int VALUE_CORRUPTED = 8;
     public static final int UNDEFINED_ACTION = 9;
     public static final int WRONG_PASSWORD = 10;
+    public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
 
     /**
      * Per operation authentication is needed before this operation is valid.
@@ -123,7 +125,6 @@
      */
     public static final int FLAG_STRONGBOX = 1 << 4;
 
-
     // States
     public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
 
@@ -730,6 +731,58 @@
         }
     }
 
+    // Keep in sync with confirmationui/1.0/types.hal.
+    public static final int CONFIRMATIONUI_OK = 0;
+    public static final int CONFIRMATIONUI_CANCELED = 1;
+    public static final int CONFIRMATIONUI_ABORTED = 2;
+    public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
+    public static final int CONFIRMATIONUI_IGNORED = 4;
+    public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
+    public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
+    public static final int CONFIRMATIONUI_UNEXPECTED = 7;
+    public static final int CONFIRMATIONUI_UIERROR = 0x10000;
+    public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
+    public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
+    public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
+
+    /**
+     * Requests keystore call into the confirmationui HAL to display a prompt.
+     *
+     * @param listener the binder to use for callbacks.
+     * @param promptText the prompt to display.
+     * @param extraData extra data / nonce from application.
+     * @param locale the locale as a BCP 47 langauge tag.
+     * @param uiOptionsAsFlags the UI options to use, as flags.
+     * @return one of the {@code CONFIRMATIONUI_*} constants, for
+     * example {@code KeyStore.CONFIRMATIONUI_OK}.
+     */
+    public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
+                                         String locale, int uiOptionsAsFlags) {
+        try {
+            return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
+                                                     uiOptionsAsFlags);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return CONFIRMATIONUI_SYSTEM_ERROR;
+        }
+    }
+
+    /**
+     * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+     *
+     * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
+     * @return one of the {@code CONFIRMATIONUI_*} constants, for
+     * example {@code KeyStore.CONFIRMATIONUI_OK}.
+     */
+    public int cancelConfirmationPrompt(IBinder listener) {
+        try {
+            return mBinder.cancelConfirmationPrompt(listener);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return CONFIRMATIONUI_SYSTEM_ERROR;
+        }
+    }
+
     /**
      * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
      * code.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index dba3949..d1eb688 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -21,6 +21,7 @@
 import android.security.GateKeeper;
 import android.security.KeyPairGeneratorSpec;
 import android.security.KeyStore;
+import android.security.KeyStoreException;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterCertificateChain;
@@ -451,7 +452,7 @@
             throw new IllegalStateException("Not initialized");
         }
 
-        final int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
+        int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
         if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
                 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
             throw new IllegalStateException(
@@ -459,6 +460,10 @@
                     + ", but the user has not yet entered the credential");
         }
 
+        if (mSpec.isStrongBoxBacked()) {
+            flags |= KeyStore.FLAG_STRONGBOX;
+        }
+
         byte[] additionalEntropy =
                 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
                         mRng, (mKeySizeBits + 7) / 8);
@@ -501,8 +506,12 @@
         int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
                 mEntryUid, flags, resultingKeyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
-            throw new ProviderException(
-                    "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+            if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
+                throw new StrongBoxUnavailableException("Failed to generate key pair");
+            } else {
+                throw new ProviderException(
+                        "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+            }
         }
     }
 
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index ad41a58..66a77ed 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -16,6 +16,9 @@
 
 package android.security.keystore;
 
+import android.security.KeyStore;
+import android.security.KeyStoreException;
+
 import java.security.ProviderException;
 
 /**
@@ -24,5 +27,13 @@
  */
 public class StrongBoxUnavailableException extends ProviderException {
 
+    /**
+     * @hide
+     */
+    public StrongBoxUnavailableException(String message) {
+        super(message,
+                new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
+        );
+    }
 }
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 27784e9..eb6e830 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.ArrayMap;
@@ -1314,6 +1315,23 @@
         return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
     }
 
+    /**
+     *  Return Metrics data about the current AudioTrack instance.
+     *
+     * @return a {@link PersistableBundle} containing the set of attributes and values
+     * available for the media being handled by this instance of AudioRecord
+     * The attributes are descibed in {@link MetricsConstants}.
+     *
+     * Additional vendor-specific fields may also be present in
+     * the return value.
+     */
+    public PersistableBundle getMetrics() {
+        PersistableBundle bundle = native_getMetrics();
+        return bundle;
+    }
+
+    private native PersistableBundle native_getMetrics();
+
     //--------------------------------------------------------------------------
     // Initialization / configuration
     //--------------------
@@ -1739,4 +1757,46 @@
     private static void loge(String msg) {
         Log.e(TAG, msg);
     }
+
+    public static final class MetricsConstants
+    {
+        private MetricsConstants() {}
+
+        /**
+         * Key to extract the output format being recorded
+         * from the {@link AudioRecord#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String ENCODING = "android.media.audiorecord.encoding";
+
+        /**
+         * Key to extract the Source Type for this track
+         * from the {@link AudioRecord#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String SOURCE = "android.media.audiorecord.source";
+
+        /**
+         * Key to extract the estimated latency through the recording pipeline
+         * from the {@link AudioRecord#getMetrics} return value.
+         * This is in units of milliseconds.
+         * The value is an integer.
+         */
+        public static final String LATENCY = "android.media.audiorecord.latency";
+
+        /**
+         * Key to extract the sink sample rate for this record track in Hz
+         * from the {@link AudioRecord#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+
+        /**
+         * Key to extract the number of channels being recorded in this record track
+         * from the {@link AudioRecord#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String CHANNELS = "android.media.audiorecord.channels";
+
+    }
 }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5928d03..4e9ce8e 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -36,6 +36,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1718,6 +1719,23 @@
          return ret;
      }
 
+    /**
+     *  Return Metrics data about the current AudioTrack instance.
+     *
+     * @return a {@link PersistableBundle} containing the set of attributes and values
+     * available for the media being handled by this instance of AudioTrack
+     * The attributes are descibed in {@link MetricsConstants}.
+     *
+     * Additional vendor-specific fields may also be present in
+     * the return value.
+     */
+    public PersistableBundle getMetrics() {
+        PersistableBundle bundle = native_getMetrics();
+        return bundle;
+    }
+
+    private native PersistableBundle native_getMetrics();
+
     //--------------------------------------------------------------------------
     // Initialization / configuration
     //--------------------
@@ -3239,4 +3257,46 @@
     private static void loge(String msg) {
         Log.e(TAG, msg);
     }
+
+    public final static class MetricsConstants
+    {
+        private MetricsConstants() {}
+
+        /**
+         * Key to extract the Stream Type for this track
+         * from the {@link AudioTrack#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String STREAMTYPE = "android.media.audiotrack.streamtype";
+
+        /**
+         * Key to extract the Content Type for this track
+         * from the {@link AudioTrack#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String CONTENTTYPE = "android.media.audiotrack.type";
+
+        /**
+         * Key to extract the Content Type for this track
+         * from the {@link AudioTrack#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String USAGE = "android.media.audiotrack.usage";
+
+        /**
+         * Key to extract the sample rate for this track in Hz
+         * from the {@link AudioTrack#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+
+        /**
+         * Key to extract the channel mask information for this track
+         * from the {@link AudioTrack#getMetrics} return value.
+         *
+         * The value is a Long integer.
+         */
+        public static final String CHANNELMASK = "android.media.audiorecord.channelmask";
+
+    }
 }
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index be4be3f..5ad4313 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -16,8 +16,10 @@
 
 package android.media;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.media.update.ApiLoader;
 import android.media.update.MediaBrowser2Provider;
@@ -99,17 +101,17 @@
                 @Nullable Bundle options, @Nullable List<MediaItem2> result) { }
     }
 
-    public MediaBrowser2(Context context, SessionToken2 token, BrowserCallback callback,
-            Executor executor) {
-        super(context, token, callback, executor);
+    public MediaBrowser2(@NonNull Context context, @NonNull SessionToken2 token,
+            @NonNull @CallbackExecutor Executor executor, @NonNull BrowserCallback callback) {
+        super(context, token, executor, callback);
         mProvider = (MediaBrowser2Provider) getProvider();
     }
 
     @Override
     MediaBrowser2Provider createProvider(Context context, SessionToken2 token,
-            ControllerCallback callback, Executor executor) {
+            Executor executor, ControllerCallback callback) {
         return ApiLoader.getProvider(context)
-                .createMediaBrowser2(this, context, token, (BrowserCallback) callback, executor);
+                .createMediaBrowser2(context, this, token, executor, (BrowserCallback) callback);
     }
 
     public void getBrowserRoot(Bundle rootHints) {
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index d669bc1..6064ec4 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -16,15 +16,17 @@
 
 package android.media;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.PlaylistParam;
+import android.media.MediaSession2.PlaylistParams;
 import android.media.session.MediaSessionManager;
 import android.media.update.ApiLoader;
 import android.media.update.MediaController2Provider;
@@ -63,8 +65,6 @@
  * @see MediaSessionService2
  * @hide
  */
-// TODO(jaewan): Unhide
-// TODO(jaewan): Revisit comments. Currently MediaBrowser case is missing.
 public class MediaController2 implements AutoCloseable {
     /**
      * Interface for listening to change in activeness of the {@link MediaSession2}.  It's
@@ -130,7 +130,7 @@
          * @param param
          */
         public void onPlaylistChanged(
-                @NonNull List<MediaItem2> list, @NonNull PlaylistParam param) { }
+                @NonNull List<MediaItem2> list, @NonNull PlaylistParams param) { }
 
         /**
          * Called when the playback state is changed.
@@ -239,12 +239,12 @@
      *
      * @param context Context
      * @param token token to connect to
-     * @param callback controller callback to receive changes in
      * @param executor executor to run callbacks on.
+     * @param callback controller callback to receive changes in
      */
     // TODO(jaewan): Put @CallbackExecutor to the constructor.
     public MediaController2(@NonNull Context context, @NonNull SessionToken2 token,
-            @NonNull ControllerCallback callback, @NonNull Executor executor) {
+            @NonNull @CallbackExecutor Executor executor, @NonNull ControllerCallback callback) {
         super();
 
         // This also connects to the token.
@@ -252,14 +252,14 @@
         // session whose session binder is only valid while it's active.
         // prevent a controller from reusable after the
         // session is released and recreated.
-        mProvider = createProvider(context, token, callback, executor);
+        mProvider = createProvider(context, token, executor, callback);
     }
 
     MediaController2Provider createProvider(@NonNull Context context,
-            @NonNull SessionToken2 token, @NonNull ControllerCallback callback,
-            @NonNull Executor executor) {
+            @NonNull SessionToken2 token, @NonNull Executor executor,
+            @NonNull ControllerCallback callback) {
         return ApiLoader.getProvider(context)
-                .createMediaController2(this, context, token, callback, executor);
+                .createMediaController2(context, this, token, executor, callback);
     }
 
     /**
@@ -271,9 +271,7 @@
         mProvider.close_impl();
     }
 
-    /**
-     * @hide
-     */
+    @SystemApi
     public MediaController2Provider getProvider() {
         return mProvider;
     }
@@ -578,7 +576,8 @@
         return mProvider.getPlaylist_impl();
     }
 
-    public @Nullable PlaylistParam getPlaylistParam() {
+    public @Nullable
+    PlaylistParams getPlaylistParam() {
         return mProvider.getPlaylistParam_impl();
     }
 
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 844f2ef..a0edefa 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1253,8 +1253,6 @@
      *
      * Additional vendor-specific fields may also be present in
      * the return value.
-     *
-     * @hide - not part of the public API at this time
      */
     public PersistableBundle getMetrics() {
         PersistableBundle bundle = getMetricsNative();
@@ -1571,8 +1569,6 @@
     /**
      * Definitions for the metrics that are reported via the
      * {@link #getMetrics} call.
-     *
-     * @hide - not part of the public API at this time
      */
     public final static class MetricsConstants
     {
@@ -1585,7 +1581,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String OPEN_SESSION_OK_COUNT
-            = "/drm/mediadrm/open_session/ok/count";
+            = "drm.mediadrm.open_session.ok.count";
 
         /**
          * Key to extract the number of failed {@link #openSession} calls
@@ -1594,7 +1590,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String OPEN_SESSION_ERROR_COUNT
-            = "/drm/mediadrm/open_session/error/count";
+            = "drm.mediadrm.open_session.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1605,7 +1601,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String OPEN_SESSION_ERROR_LIST
-            = "/drm/mediadrm/open_session/error/list";
+            = "drm.mediadrm.open_session.error.list";
 
         /**
          * Key to extract the number of successful {@link #closeSession} calls
@@ -1614,7 +1610,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String CLOSE_SESSION_OK_COUNT
-            = "/drm/mediadrm/close_session/ok/count";
+            = "drm.mediadrm.close_session.ok.count";
 
         /**
          * Key to extract the number of failed {@link #closeSession} calls
@@ -1623,7 +1619,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String CLOSE_SESSION_ERROR_COUNT
-            = "/drm/mediadrm/close_session/error/count";
+            = "drm.mediadrm.close_session.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1634,7 +1630,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String CLOSE_SESSION_ERROR_LIST
-            = "/drm/mediadrm/close_session/error/list";
+            = "drm.mediadrm.close_session.error.list";
 
         /**
          * Key to extract the start times of sessions. Times are
@@ -1648,7 +1644,7 @@
          * the start time for each session.
          */
         public static final String SESSION_START_TIMES_MS
-            = "/drm/mediadrm/session_start_times_ms";
+            = "drm.mediadrm.session_start_times_ms";
 
         /**
          * Key to extract the end times of sessions. Times are
@@ -1662,7 +1658,7 @@
          * the end time for each session.
          */
         public static final String SESSION_END_TIMES_MS
-            = "/drm/mediadrm/session_end_times_ms";
+            = "drm.mediadrm.session_end_times_ms";
 
         /**
          * Key to extract the number of successful {@link #getKeyRequest} calls
@@ -1671,7 +1667,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_KEY_REQUEST_OK_COUNT
-            = "/drm/mediadrm/get_key_request/ok/count";
+            = "drm.mediadrm.get_key_request.ok.count";
 
         /**
          * Key to extract the number of failed {@link #getKeyRequest}
@@ -1680,7 +1676,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_KEY_REQUEST_ERROR_COUNT
-            = "/drm/mediadrm/get_key_request/error/count";
+            = "drm.mediadrm.get_key_request.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1691,7 +1687,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String GET_KEY_REQUEST_ERROR_LIST
-            = "/drm/mediadrm/get_key_request/error/list";
+            = "drm.mediadrm.get_key_request.error.list";
 
         /**
          * Key to extract the average time in microseconds of calls to
@@ -1700,7 +1696,7 @@
          * The time is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_KEY_REQUEST_OK_TIME_MICROS
-            = "/drm/mediadrm/get_key_request/ok/average_time_micros";
+            = "drm.mediadrm.get_key_request.ok.average_time_micros";
 
         /**
          * Key to extract the number of successful {@link #provideKeyResponse}
@@ -1709,7 +1705,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String PROVIDE_KEY_RESPONSE_OK_COUNT
-            = "/drm/mediadrm/provide_key_response/ok/count";
+            = "drm.mediadrm.provide_key_response.ok.count";
 
         /**
          * Key to extract the number of failed {@link #provideKeyResponse}
@@ -1718,7 +1714,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String PROVIDE_KEY_RESPONSE_ERROR_COUNT
-            = "/drm/mediadrm/provide_key_response/error/count";
+            = "drm.mediadrm.provide_key_response.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1729,7 +1725,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String PROVIDE_KEY_RESPONSE_ERROR_LIST
-            = "/drm/mediadrm/provide_key_response/error/list";
+            = "drm.mediadrm.provide_key_response.error.list";
 
         /**
          * Key to extract the average time in microseconds of calls to
@@ -1738,7 +1734,7 @@
          * The time is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS
-            = "/drm/mediadrm/provide_key_response/ok/average_time_micros";
+            = "drm.mediadrm.provide_key_response.ok.average_time_micros";
 
         /**
          * Key to extract the number of successful {@link #getProvisionRequest}
@@ -1747,7 +1743,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_PROVISION_REQUEST_OK_COUNT
-            = "/drm/mediadrm/get_provision_request/ok/count";
+            = "drm.mediadrm.get_provision_request.ok.count";
 
         /**
          * Key to extract the number of failed {@link #getProvisionRequest}
@@ -1756,7 +1752,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_PROVISION_REQUEST_ERROR_COUNT
-            = "/drm/mediadrm/get_provision_request/error/count";
+            = "drm.mediadrm.get_provision_request.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1767,7 +1763,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String GET_PROVISION_REQUEST_ERROR_LIST
-            = "/drm/mediadrm/get_provision_request/error/list";
+            = "drm.mediadrm.get_provision_request.error.list";
 
         /**
          * Key to extract the number of successful
@@ -1776,7 +1772,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String PROVIDE_PROVISION_RESPONSE_OK_COUNT
-            = "/drm/mediadrm/provide_provision_response/ok/count";
+            = "drm.mediadrm.provide_provision_response.ok.count";
 
         /**
          * Key to extract the number of failed
@@ -1785,7 +1781,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT
-            = "/drm/mediadrm/provide_provision_response/error/count";
+            = "drm.mediadrm.provide_provision_response.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1796,7 +1792,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String PROVIDE_PROVISION_RESPONSE_ERROR_LIST
-            = "/drm/mediadrm/provide_provision_response/error/list";
+            = "drm.mediadrm.provide_provision_response.error.list";
 
         /**
          * Key to extract the number of successful
@@ -1807,7 +1803,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_DEVICE_UNIQUE_ID_OK_COUNT
-            = "/drm/mediadrm/get_device_unique_id/ok/count";
+            = "drm.mediadrm.get_device_unique_id.ok.count";
 
         /**
          * Key to extract the number of failed
@@ -1818,7 +1814,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String GET_DEVICE_UNIQUE_ID_ERROR_COUNT
-            = "/drm/mediadrm/get_device_unique_id/error/count";
+            = "drm.mediadrm.get_device_unique_id.error.count";
 
         /**
          * Key to extract the list of error codes that were returned from
@@ -1830,7 +1826,7 @@
          * ({@link android.os.BaseBundle#getLongArray}).
          */
         public static final String GET_DEVICE_UNIQUE_ID_ERROR_LIST
-            = "/drm/mediadrm/get_device_unique_id/error/list";
+            = "drm.mediadrm.get_device_unique_id.error.list";
 
         /**
          * Key to extraact the count of {@link KeyStatus#STATUS_EXPIRED} events
@@ -1839,7 +1835,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String KEY_STATUS_EXPIRED_COUNT
-            = "/drm/mediadrm/key_status/EXPIRED/count";
+            = "drm.mediadrm.key_status.EXPIRED.count";
 
         /**
          * Key to extract the count of {@link KeyStatus#STATUS_INTERNAL_ERROR}
@@ -1848,7 +1844,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String KEY_STATUS_INTERNAL_ERROR_COUNT
-            = "/drm/mediadrm/key_status/INTERNAL_ERROR/count";
+            = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
 
         /**
          * Key to extract the count of
@@ -1858,7 +1854,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT
-            = "/drm/mediadrm/key_status_change/OUTPUT_NOT_ALLOWED/count";
+            = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
 
         /**
          * Key to extract the count of {@link KeyStatus#STATUS_PENDING}
@@ -1867,7 +1863,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String KEY_STATUS_PENDING_COUNT
-            = "/drm/mediadrm/key_status_change/PENDING/count";
+            = "drm.mediadrm.key_status_change.PENDING.count";
 
         /**
          * Key to extract the count of {@link KeyStatus#STATUS_USABLE}
@@ -1876,7 +1872,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String KEY_STATUS_USABLE_COUNT
-            = "/drm/mediadrm/key_status_change/USABLE/count";
+            = "drm.mediadrm.key_status_change.USABLE.count";
 
         /**
          * Key to extract the count of {@link OnEventListener#onEvent}
@@ -1886,7 +1882,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String EVENT_PROVISION_REQUIRED_COUNT
-            = "/drm/mediadrm/event/PROVISION_REQUIRED/count";
+            = "drm.mediadrm.event.PROVISION_REQUIRED.count";
 
         /**
          * Key to extract the count of {@link OnEventListener#onEvent}
@@ -1896,7 +1892,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String EVENT_KEY_NEEDED_COUNT
-            = "/drm/mediadrm/event/KEY_NEEDED/count";
+            = "drm.mediadrm.event.KEY_NEEDED.count";
 
         /**
          * Key to extract the count of {@link OnEventListener#onEvent}
@@ -1906,7 +1902,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String EVENT_KEY_EXPIRED_COUNT
-            = "/drm/mediadrm/event/KEY_EXPIRED/count";
+            = "drm.mediadrm.event.KEY_EXPIRED.count";
 
         /**
          * Key to extract the count of {@link OnEventListener#onEvent}
@@ -1916,7 +1912,7 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String EVENT_VENDOR_DEFINED_COUNT
-            = "/drm/mediadrm/event/VENDOR_DEFINED/count";
+            = "drm.mediadrm.event.VENDOR_DEFINED.count";
 
         /**
          * Key to extract the count of {@link OnEventListener#onEvent}
@@ -1926,6 +1922,6 @@
          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
          */
         public static final String EVENT_SESSION_RECLAIMED_COUNT
-            = "/drm/mediadrm/event/SESSION_RECLAIMED/count";
+            = "drm.mediadrm.event.SESSION_RECLAIMED.count";
     }
 }
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 2c1b4b3..174d6a3 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -626,6 +626,12 @@
      */
     public native long getSampleTime();
 
+    /**
+     * @return size of the current sample in bytes or -1 if no more
+     * samples are available.
+     */
+    public native long getSampleSize();
+
     // Keep these in sync with their equivalents in NuMediaExtractor.h
     /**
      * The sample is a sync sample (or in {@link MediaCodec}'s terminology
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index 96a87d5..6a96faa 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.text.TextUtils;
 
@@ -32,15 +33,10 @@
  * When it's sent to a controller or browser, it's anonymized and data descriptor wouldn't be sent.
  * <p>
  * This object isn't a thread safe.
- *
  * @hide
  */
-// TODO(jaewan): Unhide and extends from DataSourceDesc.
-//               Note) Feels like an anti-pattern. We should anonymize MediaItem2 to remove *all*
-//                     information in the DataSourceDesc. Why it should extends from this?
-// TODO(jaewan): Move this to updatable
-// Previously MediaBrowser.MediaItem
 public class MediaItem2 {
+    // TODO(jaewan): Keep DataSourceDesc.
     private final int mFlags;
     private MediaMetadata2 mMetadata;
 
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index d7e43ec..5dadcb5 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -28,7 +28,6 @@
 import android.media.update.MediaSession2Provider;
 import android.media.update.MediaSessionService2Provider;
 import android.os.Bundle;
-import android.service.media.MediaBrowserService.BrowserRoot;
 
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -54,7 +53,6 @@
  * declare metadata in the manifest as follows.
  * @hide
  */
-// TODO(jaewan): Unhide
 public abstract class MediaLibraryService2 extends MediaSessionService2 {
     /**
      * This is the interface name that a service implementing a session service should say that it
@@ -69,21 +67,21 @@
         private final MediaLibrarySessionProvider mProvider;
 
         MediaLibrarySession(Context context, MediaPlayerBase player, String id,
-                Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
-                int ratingType, PendingIntent sessionActivity) {
-            super(context, player, id, callbackExecutor, callback, volumeProvider, ratingType,
-                    sessionActivity);
+                VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+                Executor callbackExecutor, SessionCallback callback) {
+            super(context, player, id, volumeProvider, ratingType, sessionActivity,
+                    callbackExecutor, callback);
             mProvider = (MediaLibrarySessionProvider) getProvider();
         }
 
         @Override
         MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
-                Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
-                int ratingType, PendingIntent sessionActivity) {
+                VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+                Executor callbackExecutor, SessionCallback callback) {
             return ApiLoader.getProvider(context)
-                    .createMediaLibraryService2MediaLibrarySession(this, context, player, id,
-                            callbackExecutor, (MediaLibrarySessionCallback) callback,
-                            volumeProvider, ratingType, sessionActivity);
+                    .createMediaLibraryService2MediaLibrarySession(context, this, player, id,
+                            volumeProvider, ratingType, sessionActivity,
+                            callbackExecutor, (MediaLibrarySessionCallback) callback);
         }
 
         /**
@@ -226,9 +224,9 @@
         }
 
         @Override
-        public MediaLibrarySession build() throws IllegalStateException {
-            return new MediaLibrarySession(mContext, mPlayer, mId, mCallbackExecutor, mCallback,
-                    mVolumeProvider, mRatingType, mSessionActivity);
+        public MediaLibrarySession build() {
+            return new MediaLibrarySession(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+                    mSessionActivity, mCallbackExecutor, mCallback);
         }
     }
 
@@ -277,7 +275,7 @@
          * @see #EXTRA_OFFLINE
          * @see #EXTRA_SUGGESTED
          */
-        public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+        public static final String EXTRA_RECENT = "android.media.extra.RECENT";
 
         /**
          * The lookup key for a boolean that indicates whether the browser service should return a
@@ -295,7 +293,7 @@
          * @see #EXTRA_RECENT
          * @see #EXTRA_SUGGESTED
          */
-        public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+        public static final String EXTRA_OFFLINE = "android.media.extra.OFFLINE";
 
         /**
          * The lookup key for a boolean that indicates whether the browser service should return a
@@ -303,8 +301,8 @@
          *
          * <p>When creating a media browser for a given media browser service, this key can be
          * supplied as a root hint for retrieving the media items suggested by the media browser
-         * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
-         * is considered ordered by relevance, first being the top suggestion.
+         * service. The list of media items is considered ordered by relevance, first being the top
+         * suggestion.
          * If the media browser service can provide such media items, the implementation must return
          * the key in the root hint when
          * {@link MediaLibrarySessionCallback#onGetRoot(ControllerInfo, Bundle)} is called back.
@@ -314,7 +312,7 @@
          * @see #EXTRA_RECENT
          * @see #EXTRA_OFFLINE
          */
-        public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+        public static final String EXTRA_SUGGESTED = "android.media.extra.SUGGESTED";
 
         final private String mRootId;
         final private Bundle mExtras;
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 0e24db6..fcdb4f7 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -34,6 +34,7 @@
 
 /**
  * Contains metadata about an item, such as the title, artist, etc.
+ *
  * @hide
  */
 // TODO(jaewan): Move this to updatable
@@ -218,7 +219,7 @@
     /**
      * A Uri formatted String representing the content. This value is specific to the
      * service providing the content. It may be used with
-     * {@link MediaController2#playFromUri(Uri, Bundle)}
+     * {@link MediaController2#playFromUri(String, Bundle)}
      * to initiate playback when provided by a {@link MediaBrowser2} connected to
      * the same app.
      */
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index d638a9f..0efec901 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -16,16 +16,13 @@
 
 package android.media;
 
-import android.media.MediaSession2.PlaylistParam;
-import android.media.session.PlaybackState;
-import android.os.Handler;
+import android.media.MediaSession2.PlaylistParams;
 
 import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
  * Base interfaces for all media players that want media session.
- *
  * @hide
  */
 public abstract class MediaPlayerBase {
@@ -52,7 +49,7 @@
     public abstract PlaybackState2 getPlaybackState();
     public abstract AudioAttributes getAudioAttributes();
 
-    public abstract void setPlaylist(List<MediaItem2> item, PlaylistParam param);
+    public abstract void setPlaylist(List<MediaItem2> item, PlaylistParams param);
     public abstract void setCurrentPlaylistItem(int index);
 
     /**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 0e90040..7dffd40 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -20,7 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Activity;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -77,12 +77,6 @@
  * @see MediaSessionService2
  * @hide
  */
-// TODO(jaewan): Unhide
-// TODO(jaewan): Revisit comments. Currently it's borrowed from the MediaSession.
-// TODO(jaewan): Should we support thread safe? It may cause tricky issue such as b/63797089
-// TODO(jaewan): Should we make APIs for MediaSessionService2 public? It's helpful for
-//               developers that doesn't want to override from Browser, but user may not use this
-//               correctly.
 public class MediaSession2 implements AutoCloseable {
     private final MediaSession2Provider mProvider;
 
@@ -349,7 +343,8 @@
         /**
          * Called when a controller set rating on the currently playing contents.
          *
-         * @param
+         * @param controller controller information
+         * @param rating new rating from the controller
          */
         public void onSetRating(@NonNull ControllerInfo controller, @NonNull Rating2 rating) { }
 
@@ -429,7 +424,7 @@
         /**
          * Override to handle requests to play a specific media item represented by a URI.
          */
-        public void prepareFromUri(@NonNull ControllerInfo controller,
+        public void onPrepareFromUri(@NonNull ControllerInfo controller,
                 @NonNull Uri uri, @Nullable Bundle extras) { }
 
         /**
@@ -527,7 +522,7 @@
         /**
          * Set an intent for launching UI for this Session. This can be used as a
          * quick link to an ongoing media screen. The intent should be for an
-         * activity that may be started using {@link Activity#startActivity(Intent)}.
+         * activity that may be started using {@link Context#startActivity(Intent)}.
          *
          * @param pi The intent to launch to show UI for this session.
          */
@@ -555,7 +550,7 @@
         }
 
         /**
-         * Set {@link SessionCallback}.
+         * Set callback for the session.
          *
          * @param executor callback executor
          * @param callback session callback.
@@ -581,7 +576,7 @@
          * @throws IllegalStateException if the session with the same id is already exists for the
          *      package.
          */
-        public abstract MediaSession2 build() throws IllegalStateException;
+        public abstract MediaSession2 build();
     }
 
     /**
@@ -599,12 +594,12 @@
         }
 
         @Override
-        public MediaSession2 build() throws IllegalStateException {
+        public MediaSession2 build() {
             if (mCallback == null) {
                 mCallback = new SessionCallback();
             }
-            return new MediaSession2(mContext, mPlayer, mId, mCallbackExecutor, mCallback,
-                    mVolumeProvider, mRatingType, mSessionActivity);
+            return new MediaSession2(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+                    mSessionActivity, mCallbackExecutor, mCallback);
         }
     }
 
@@ -624,7 +619,7 @@
                 IMediaSession2Callback callback) {
             mProvider = ApiLoader.getProvider(context)
                     .createMediaSession2ControllerInfoProvider(
-                            this, context, uid, pid, packageName, callback);
+                            context, this, uid, pid, packageName, callback);
         }
 
         /**
@@ -652,11 +647,7 @@
             return mProvider.isTrusted_impl();
         }
 
-        /**
-         * @hide
-         * @return
-         */
-        // TODO(jaewan): SystemApi
+        @SystemApi
         public ControllerInfoProvider getProvider() {
             return mProvider;
         }
@@ -855,7 +846,7 @@
      * Parameter for the playlist.
      */
     // TODO(jaewan): add fromBundle()/toBundle()
-    public static class PlaylistParam {
+    public static class PlaylistParams {
         /**
          * @hide
          */
@@ -915,7 +906,7 @@
 
         private MediaMetadata2 mPlaylistMetadata;
 
-        public PlaylistParam(@RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
+        public PlaylistParams(@RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
                 @Nullable MediaMetadata2 playlistMetadata) {
             mRepeatMode = repeatMode;
             mShuffleMode = shuffleMode;
@@ -949,26 +940,25 @@
      *       framework had to add heuristics to figure out if an app is
      * @hide
      */
-    MediaSession2(Context context, MediaPlayerBase player, String id, Executor callbackExecutor,
-            SessionCallback callback, VolumeProvider volumeProvider, int ratingType,
-            PendingIntent sessionActivity) {
+
+    MediaSession2(Context context, MediaPlayerBase player, String id, VolumeProvider volumeProvider,
+            int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
+            SessionCallback callback) {
         super();
-        mProvider = createProvider(context, player, id, callbackExecutor, callback,
-                volumeProvider, ratingType, sessionActivity);
+        mProvider = createProvider(context, player, id, volumeProvider, ratingType, sessionActivity,
+                callbackExecutor, callback
+        );
     }
 
     MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
-            Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
-            int ratingType, PendingIntent sessionActivity) {
+            VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+            Executor callbackExecutor, SessionCallback callback) {
         return ApiLoader.getProvider(context)
-                .createMediaSession2(this, context, player, id, callbackExecutor,
-                        callback, volumeProvider, ratingType, sessionActivity);
+                .createMediaSession2(context, this, player, id, volumeProvider, ratingType,
+                        sessionActivity, callbackExecutor, callback);
     }
 
-    /**
-     * @hide
-     */
-    // TODO(jaewan): SystemApi
+    @SystemApi
     public MediaSession2Provider getProvider() {
         return mProvider;
     }
@@ -998,10 +988,8 @@
      * @param volumeProvider a volume provider
      * @see #setPlayer(MediaPlayerBase)
      * @see Builder#setVolumeProvider(VolumeProvider)
-     * @throws IllegalArgumentException if a parameter is {@code null}.
      */
-    public void setPlayer(@NonNull MediaPlayerBase player, @NonNull VolumeProvider volumeProvider)
-            throws IllegalArgumentException {
+    public void setPlayer(@NonNull MediaPlayerBase player, @NonNull VolumeProvider volumeProvider) {
         mProvider.setPlayer_impl(player, volumeProvider);
     }
 
@@ -1217,7 +1205,7 @@
         // To match with KEYCODE_MEDIA_SKIP_BACKWARD
     }
 
-    public void setPlaylist(@NonNull List<MediaItem2> playlist, @NonNull PlaylistParam param) {
+    public void setPlaylist(@NonNull List<MediaItem2> playlist, @NonNull PlaylistParams param) {
         mProvider.setPlaylist_impl(playlist, param);
     }
 }
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 19814f0..6b2de06 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -23,7 +23,6 @@
 import android.app.Service;
 import android.content.Intent;
 import android.media.MediaSession2.ControllerInfo;
-import android.media.session.PlaybackState;
 import android.media.update.ApiLoader;
 import android.media.update.MediaSessionService2Provider;
 import android.os.IBinder;
@@ -89,7 +88,7 @@
  * rejected, the controller will unbind. If it's accepted, the controller will be available to use
  * and keep binding.
  * <p>
- * When playback is started for this session service, {@link #onUpdateNotification(PlaybackState)}
+ * When playback is started for this session service, {@link #onUpdateNotification(PlaybackState2)}
  * is called and service would become a foreground service. It's needed to keep playback after the
  * controller is destroyed. The session service becomes background service when the playback is
  * stopped.
@@ -99,20 +98,8 @@
  * Any app can bind to the session service with controller, but the controller can be used only if
  * the session service accepted the connection request through
  * {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)}.
- *
  * @hide
  */
-// TODO(jaewan): Unhide
-// TODO(jaewan): Can we clean up sessions in onDestroy() automatically instead?
-//               What about currently running SessionCallback when the onDestroy() is called?
-// TODO(jaewan): Protect this with system|privilleged permission - Q.
-// TODO(jaewan): Add permission check for the service to know incoming connection request.
-//               Follow-up questions: What about asking a XML for list of white/black packages for
-//                                    allowing enumeration?
-//                                    We can read the information even when the service is started,
-//                                    so SessionManager.getXXXXService() can only return apps
-//                                    TODO(jaewan): Will be the black/white listing persistent?
-//                                                  In other words, can we cache the rejection?
 public abstract class MediaSessionService2 extends Service {
     private final MediaSessionService2Provider mProvider;
 
@@ -213,7 +200,7 @@
     }
 
     /**
-     * Returned by {@link #onUpdateNotification(PlaybackState)} for making session service
+     * Returned by {@link #onUpdateNotification(PlaybackState2)} for making session service
      * foreground service to keep playback running in the background. It's highly recommended to
      * show media style notification here.
      */
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
index 46d6f45..04f211d 100644
--- a/media/java/android/media/PlaybackState2.java
+++ b/media/java/android/media/PlaybackState2.java
@@ -28,7 +28,6 @@
  * the current playback position and extra.
  * @hide
  */
-// TODO(jaewan): Move to updatable
 public final class PlaybackState2 {
     private static final String TAG = "PlaybackState2";
 
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index 67e5e72..93aea6f 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -32,7 +32,6 @@
  * through one of the factory methods.
  * @hide
  */
-// TODO(jaewan): Move this to updatable
 public final class Rating2 {
     private static final String TAG = "Rating2";
 
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
index 697a5a8..0abb852 100644
--- a/media/java/android/media/SessionToken2.java
+++ b/media/java/android/media/SessionToken2.java
@@ -37,9 +37,7 @@
  * It can be also obtained by {@link MediaSessionManager}.
  * @hide
  */
-// TODO(jaewan): Unhide. SessionToken2?
 // TODO(jaewan): Move Token to updatable!
-// TODO(jaewan): Find better name for this (SessionToken or Session2Token)
 public final class SessionToken2 {
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
@@ -210,7 +208,6 @@
      * Create a {@link Bundle} from this token to share it across processes.
      *
      * @return Bundle
-     * @hide
      */
     public Bundle toBundle() {
         Bundle bundle = new Bundle();
diff --git a/media/java/android/media/update/MediaBrowser2Provider.java b/media/java/android/media/update/MediaBrowser2Provider.java
index e48711d..67680c7 100644
--- a/media/java/android/media/update/MediaBrowser2Provider.java
+++ b/media/java/android/media/update/MediaBrowser2Provider.java
@@ -16,6 +16,7 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.os.Bundle;
 
 /**
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index c5f6b96..8dfb892 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -16,11 +16,12 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaSession2.Command;
-import android.media.MediaSession2.PlaylistParam;
+import android.media.MediaSession2.PlaylistParams;
 import android.media.PlaybackState2;
 import android.media.Rating2;
 import android.media.SessionToken2;
@@ -59,6 +60,6 @@
     void removePlaylistItem_impl(MediaItem2 index);
     void addPlaylistItem_impl(int index, MediaItem2 item);
 
-    PlaylistParam getPlaylistParam_impl();
+    PlaylistParams getPlaylistParam_impl();
     PlaybackState2 getPlaybackState_impl();
 }
diff --git a/media/java/android/media/update/MediaLibraryService2Provider.java b/media/java/android/media/update/MediaLibraryService2Provider.java
index dac5784..a568839 100644
--- a/media/java/android/media/update/MediaLibraryService2Provider.java
+++ b/media/java/android/media/update/MediaLibraryService2Provider.java
@@ -16,8 +16,11 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.media.MediaSession2.ControllerInfo;
-import android.os.Bundle; /**
+import android.os.Bundle;
+
+/**
  * @hide
  */
 public interface MediaLibraryService2Provider extends MediaSessionService2Provider {
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 2a68ad1..d32b741 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -16,14 +16,15 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.media.AudioAttributes;
 import android.media.MediaItem2;
 import android.media.MediaPlayerBase;
-import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.PlaylistParams;
 import android.media.SessionToken2;
 import android.media.VolumeProvider;
 import android.os.Bundle;
@@ -50,11 +51,8 @@
     void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
             ResultReceiver receiver);
     void sendCustomCommand_impl(Command command, Bundle args);
-    void setPlaylist_impl(List<MediaItem2> playlist, MediaSession2.PlaylistParam param);
+    void setPlaylist_impl(List<MediaItem2> playlist, PlaylistParams param);
 
-    /**
-     * @hide
-     */
     interface ControllerInfoProvider {
         String getPackageName_impl();
         int getUid_impl();
diff --git a/media/java/android/media/update/MediaSessionService2Provider.java b/media/java/android/media/update/MediaSessionService2Provider.java
index a6b462b..9455da7 100644
--- a/media/java/android/media/update/MediaSessionService2Provider.java
+++ b/media/java/android/media/update/MediaSessionService2Provider.java
@@ -16,6 +16,7 @@
 
 package android.media.update;
 
+import android.annotation.SystemApi;
 import android.content.Intent;
 import android.media.MediaSession2;
 import android.media.MediaSessionService2.MediaNotification;
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 7c222c3..3cd1a99 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -17,9 +17,9 @@
 package android.media.update;
 
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.media.IMediaSession2Callback;
 import android.media.MediaBrowser2;
 import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaController2;
@@ -35,6 +35,7 @@
 import android.media.VolumeProvider;
 import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
 import android.media.update.MediaSession2Provider.ControllerInfoProvider;
+import android.os.IInterface;
 import android.util.AttributeSet;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
@@ -46,10 +47,8 @@
  *
  * This interface provides access to constructors and static methods that are otherwise not directly
  * accessible via an implementation object.
- *
  * @hide
  */
-// TODO @SystemApi
 public interface StaticProvider {
     MediaControlView2Provider createMediaControlView2(
             MediaControlView2 instance, ViewProvider superProvider);
@@ -57,25 +56,20 @@
             VideoView2 instance, ViewProvider superProvider,
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
 
-    MediaSession2Provider createMediaSession2(MediaSession2 mediaSession2, Context context,
-            MediaPlayerBase player, String id, Executor callbackExecutor, SessionCallback callback,
-            VolumeProvider volumeProvider, int ratingType,
-            PendingIntent sessionActivity);
-    ControllerInfoProvider createMediaSession2ControllerInfoProvider(
-            MediaSession2.ControllerInfo instance, Context context, int uid, int pid,
-            String packageName, IMediaSession2Callback callback);
-    MediaController2Provider createMediaController2(
-            MediaController2 instance, Context context, SessionToken2 token,
-            ControllerCallback callback, Executor executor);
-    MediaBrowser2Provider createMediaBrowser2(
-            MediaBrowser2 instance, Context context, SessionToken2 token,
-            BrowserCallback callback, Executor executor);
-    MediaSessionService2Provider createMediaSessionService2(
-            MediaSessionService2 instance);
-    MediaSessionService2Provider createMediaLibraryService2(
-            MediaLibraryService2 instance);
-    MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(
-            MediaLibrarySession instance, Context context, MediaPlayerBase player, String id,
-            Executor callbackExecutor, MediaLibrarySessionCallback callback,
-            VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity);
+    MediaSession2Provider createMediaSession2(Context context, MediaSession2 instance,
+            MediaPlayerBase player, String id, VolumeProvider volumeProvider, int ratingType,
+            PendingIntent sessionActivity, Executor executor, SessionCallback callback);
+    ControllerInfoProvider createMediaSession2ControllerInfoProvider(Context context,
+            MediaSession2.ControllerInfo instance, int uid, int pid,
+            String packageName, IInterface callback);
+    MediaController2Provider createMediaController2(Context context, MediaController2 instance,
+            SessionToken2 token, Executor executor, ControllerCallback callback);
+    MediaBrowser2Provider createMediaBrowser2(Context context, MediaBrowser2 instance,
+            SessionToken2 token, Executor executor, BrowserCallback callback);
+    MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance);
+    MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance);
+    MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(Context context,
+            MediaLibrarySession instance, MediaPlayerBase player, String id,
+            VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+            Executor executor, MediaLibrarySessionCallback callback);
 }
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index 5217a9d..0c87063e 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -16,14 +16,9 @@
 
 package android.media.update;
 
-import android.media.MediaPlayerBase;
-import android.media.session.PlaybackState;
-import android.os.Handler;
-
 /**
  * @hide
  */
-// TODO(jaewan): SystemApi
 public interface TransportControlProvider {
     void play_impl();
     void pause_impl();
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 416ea98..5c05ce4 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -18,6 +18,7 @@
 
 import android.media.AudioAttributes;
 import android.media.MediaPlayerBase;
+import android.media.session.MediaController;
 import android.net.Uri;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
@@ -41,20 +42,14 @@
 // TODO @SystemApi
 public interface VideoView2Provider extends ViewProvider {
     void setMediaControlView2_impl(MediaControlView2 mediaControlView);
+    MediaController getMediaController_impl();
     MediaControlView2 getMediaControlView2_impl();
-    void start_impl();
-    void pause_impl();
-    int getDuration_impl();
-    int getCurrentPosition_impl();
-    void seekTo_impl(int msec);
-    boolean isPlaying_impl();
-    int getBufferPercentage_impl();
     int getAudioSessionId_impl();
     void showSubtitle_impl();
     void hideSubtitle_impl();
     void setFullScreen_impl(boolean fullScreen);
+    // TODO: remove setSpeed_impl once MediaController2 is ready.
     void setSpeed_impl(float speed);
-    float getSpeed_impl();
     void setAudioFocusRequest_impl(int focusGain);
     void setAudioAttributes_impl(AudioAttributes attributes);
     void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player);
@@ -63,7 +58,6 @@
     void setVideoURI_impl(Uri uri, Map<String, String> headers);
     void setViewType_impl(int viewType);
     int getViewType_impl();
-    void stopPlayback_impl();
     void setOnPreparedListener_impl(VideoView2.OnPreparedListener l);
     void setOnCompletionListener_impl(VideoView2.OnCompletionListener l);
     void setOnErrorListener_impl(VideoView2.OnErrorListener l);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index ee775db..051c802 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -12,7 +12,6 @@
         "android_media_MediaDrm.cpp",
         "android_media_MediaExtractor.cpp",
         "android_media_MediaHTTPConnection.cpp",
-        "android_media_MediaMetricsJNI.cpp",
         "android_media_MediaMetadataRetriever.cpp",
         "android_media_MediaMuxer.cpp",
         "android_media_MediaPlayer.cpp",
@@ -93,7 +92,6 @@
         "android_media_MediaCrypto.cpp",
         "android_media_Media2DataSource.cpp",
         "android_media_MediaDrm.cpp",
-        "android_media_MediaMetricsJNI.cpp",
         "android_media_MediaPlayer2.cpp",
         "android_media_SyncParams.cpp",
     ],
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 5c90d00..a855526 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -244,6 +244,10 @@
     return mImpl->getSampleTime(sampleTimeUs);
 }
 
+status_t JMediaExtractor::getSampleSize(size_t *sampleSize) {
+    return mImpl->getSampleSize(sampleSize);
+}
+
 status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
     *sampleFlags = 0;
 
@@ -505,6 +509,28 @@
     return (jlong) sampleTimeUs;
 }
 
+static jlong android_media_MediaExtractor_getSampleSize(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return -1ll;
+    }
+
+    size_t sampleSize;
+    status_t err = extractor->getSampleSize(&sampleSize);
+
+    if (err == ERROR_END_OF_STREAM) {
+        return -1ll;
+    } else if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return -1ll;
+    }
+
+    return (jlong) sampleSize;
+}
+
 static jint android_media_MediaExtractor_getSampleFlags(
         JNIEnv *env, jobject thiz) {
     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -884,6 +910,9 @@
     { "getSampleTime", "()J",
         (void *)android_media_MediaExtractor_getSampleTime },
 
+    { "getSampleSize", "()J",
+        (void *)android_media_MediaExtractor_getSampleSize },
+
     { "getSampleFlags", "()I",
         (void *)android_media_MediaExtractor_getSampleFlags },
 
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index a4638ac..aaa8421 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -60,6 +60,7 @@
     status_t readSampleData(jobject byteBuf, size_t offset, size_t *sampleSize);
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
+    status_t getSampleSize(size_t *sampleSize);
     status_t getSampleFlags(uint32_t *sampleFlags);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
     status_t getMetrics(Parcel *reply) const;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d001e66..1f67dfb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -44,7 +44,11 @@
         com.android.internal.R.drawable.ic_wifi_signal_4
     };
 
-    public static void updateLocationEnabled(Context context, boolean enabled, int userId) {
+    public static void updateLocationEnabled(Context context, boolean enabled, int userId,
+            int source) {
+        Settings.Secure.putIntForUser(
+                context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
+                userId);
         Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
 
         final int oldMode = Settings.Secure.getIntForUser(context.getContentResolver(),
@@ -62,7 +66,11 @@
         wrapper.setLocationEnabledForUser(enabled, UserHandle.of(userId));
     }
 
-    public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) {
+    public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId,
+            int source) {
+        Settings.Secure.putIntForUser(
+                context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
+                userId);
         Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
         intent.putExtra(CURRENT_MODE_KEY, oldMode);
         intent.putExtra(NEW_MODE_KEY, newMode);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 327c1c8..5459fb7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -84,23 +84,31 @@
                 mContext,
                 Secure.LOCATION_MODE_OFF,
                 Secure.LOCATION_MODE_HIGH_ACCURACY,
-                currentUserId);
+                currentUserId,
+                Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
 
         verify(mContext).sendBroadcastAsUser(
                 argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
                 ArgumentMatchers.eq(UserHandle.of(currentUserId)),
                 ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+        assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
+                .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
     }
 
     @Test
     public void testUpdateLocationEnabled_sendBroadcast() {
         int currentUserId = ActivityManager.getCurrentUser();
-        Utils.updateLocationEnabled(mContext, true, currentUserId);
+        Utils.updateLocationEnabled(mContext, true, currentUserId,
+                Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
 
         verify(mContext).sendBroadcastAsUser(
             argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
             ArgumentMatchers.eq(UserHandle.of(currentUserId)),
             ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+        assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
+                .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
     }
 
     @Test
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index a648345e..30d1352 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.plugins.qs;
 
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -65,6 +66,18 @@
     default void setHasNotifications(boolean hasNotifications) {
     }
 
+    /**
+     * We need this to handle nested scrolling for QS..
+     * Normally we would do this with requestDisallowInterceptTouchEvent, but when both the
+     * scroll containers are using the same touch slop, they try to start scrolling at the
+     * same time and NotificationPanelView wins, this lets QS win.
+     *
+     * TODO: Do this using NestedScroll capabilities.
+     */
+    default boolean onInterceptTouchEvent(MotionEvent event) {
+        return isCustomizing();
+    }
+
     @ProvidesInterface(version = HeightListener.VERSION)
     interface HeightListener {
         int VERSION = 1;
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7ee9eda..d58c725 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -336,6 +336,8 @@
     <dimen name="qs_footer_padding_end">24dp</dimen>
     <dimen name="qs_footer_icon_size">16dp</dimen>
 
+    <dimen name="qs_notif_collapsed_space">64dp</dimen>
+
     <!-- Desired qs icon overlay size. -->
     <dimen name="qs_detail_icon_overlay_size">24dp</dimen>
 
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 351a1fd..38f469e 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,4 +20,6 @@
     <!-- Date format for display: should match the lockscreen in /policy.  -->
     <string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
 
+    <!-- Date format for the always on display.  -->
+    <item type="string" name="system_ui_aod_date_pattern">eeeMMMd</item>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 209d444..6d61a0c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1506,6 +1506,10 @@
     <string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
 
     <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
+    <string name="inline_blocking_helper">You usually dismiss these notifications.
+    \nKeep showing them?</string>
+
+    <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
     <string name="inline_keep_showing">Keep showing these notifications?</string>
 
     <!-- Notification inline controls: block notifications button -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index bcce6d1..2497d20 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -306,6 +306,7 @@
         <item name="darkIconTheme">@style/DualToneDarkTheme</item>
         <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
         <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
+        <item name="android:colorError">@*android:color/error_color_material_dark</item>
         <item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
         <item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
         <item name="passwordStyle">@style/PasswordTheme</item>
@@ -317,6 +318,7 @@
     <style name="Theme.SystemUI.Light" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
         <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
         <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
+        <item name="android:colorError">@*android:color/error_color_material_light</item>
         <item name="android:colorControlHighlight">@*android:color/primary_text_material_light</item>
         <item name="passwordStyle">@style/PasswordTheme.Light</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 9ff6815..cb732c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -51,6 +51,8 @@
 import androidx.app.slice.Slice;
 import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.widget.ListContent;
+import androidx.app.slice.widget.RowContent;
 import androidx.app.slice.widget.SliceLiveData;
 
 /**
@@ -115,25 +117,17 @@
 
     private void showSlice(Slice slice) {
 
-        // Main area
-        SliceItem mainItem = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_SLICE,
-                null /* hints */, new String[]{android.app.slice.Slice.HINT_LIST_ITEM});
-        mHasHeader = mainItem != null;
-
-        List<SliceItem> subItems = SliceQuery.findAll(slice,
-                android.app.slice.SliceItem.FORMAT_SLICE,
-                new String[]{android.app.slice.Slice.HINT_LIST_ITEM},
-                null /* nonHints */);
-
+        ListContent lc = new ListContent(slice);
+        mHasHeader = lc.hasHeader();
+        List<SliceItem> subItems = lc.getRowItems();
         if (!mHasHeader) {
             mTitle.setVisibility(GONE);
         } else {
             mTitle.setVisibility(VISIBLE);
-            SliceItem mainTitle = SliceQuery.find(mainItem.getSlice(),
-                    android.app.slice.SliceItem.FORMAT_TEXT,
-                    new String[]{android.app.slice.Slice.HINT_TITLE},
-                    null /* nonHints */);
-            CharSequence title = mainTitle.getText();
+            // If there's a header it'll be the first subitem
+            RowContent header = new RowContent(subItems.get(0), true /* showStartItem */);
+            SliceItem mainTitle = header.getTitleItem();
+            CharSequence title = mainTitle != null ? mainTitle.getText() : null;
             mTitle.setText(title);
 
             // Check if we're already ellipsizing the text.
@@ -152,9 +146,10 @@
         mClickActions.clear();
         final int subItemsCount = subItems.size();
         final int blendedColor = getTextColor();
-
-        for (int i = 0; i < subItemsCount; i++) {
+        final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
+        for (int i = startIndex; i < subItemsCount; i++) {
             SliceItem item = subItems.get(i);
+            RowContent rc = new RowContent(item, true /* showStartItem */);
             final Uri itemTag = item.getSlice().getUri();
             // Try to reuse the view if already exists in the layout
             KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
@@ -168,20 +163,13 @@
             button.setHasDivider(i < subItemsCount - 1);
             mRow.addView(button, i);
 
-            PendingIntent pendingIntent;
-            try {
-                pendingIntent = item.getAction();
-            } catch (RuntimeException e) {
-                Log.w(TAG, "Cannot retrieve action from keyguard slice", e);
-                pendingIntent = null;
+            PendingIntent pendingIntent = null;
+            if (rc.getContentIntent() != null) {
+                pendingIntent = rc.getContentIntent().getAction();
             }
             mClickActions.put(button, pendingIntent);
 
-            SliceItem title = SliceQuery.find(item.getSlice(),
-                    android.app.slice.SliceItem.FORMAT_TEXT,
-                    new String[]{android.app.slice.Slice.HINT_TITLE},
-                    null /* nonHints */);
-            button.setText(title.getText());
+            button.setText(rc.getTitleItem().getText());
 
             Drawable iconDrawable = null;
             SliceItem icon = SliceQuery.find(item.getSlice(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 2b656c2..e440731 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -330,7 +330,7 @@
 
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
-        mKeyguardSlice.setVisibility(pulsing ? GONE : VISIBLE);
+        mKeyguardSlice.setVisibility(pulsing ? INVISIBLE : VISIBLE);
         onSliceContentChanged(mKeyguardSlice.hasHeader());
         updateDozeVisibleViews();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 3538327..2c0e95b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -61,7 +61,7 @@
  */
 public class SystemUIApplication extends Application implements SysUiServiceProvider {
 
-    private static final String TAG = "SystemUIService";
+    public static final String TAG = "SystemUIService";
     private static final boolean DEBUG = false;
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 11e0f28..ddf0bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -20,11 +20,15 @@
 import android.content.Intent;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.SystemProperties;
+import android.util.Slog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import com.android.internal.os.BinderInternal;
+
 public class SystemUIService extends Service {
 
     @Override
@@ -36,6 +40,21 @@
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
             throw new RuntimeException();
         }
+
+        if (Build.IS_DEBUGGABLE) {
+            // b/71353150 - looking for leaked binder proxies
+            BinderInternal.nSetBinderProxyCountEnabled(true);
+            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+            BinderInternal.setBinderProxyCountCallback(
+                    new BinderInternal.BinderProxyLimitListener() {
+                        @Override
+                        public void onLimitReached(int uid) {
+                            Slog.w(SystemUIApplication.TAG,
+                                    "uid " + uid + " sent too many Binder proxies to uid "
+                                    + Process.myUid());
+                        }
+                    }, Dependency.get(Dependency.MAIN_HANDLER));
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index e49e80d..c7d276c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -118,7 +118,7 @@
     public boolean onCreateSliceProvider() {
         mNextAlarmController = new NextAlarmControllerImpl(getContext());
         mNextAlarmController.addCallback(this);
-        mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
+        mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
         registerClockUpdate(false /* everyMinute */);
         updateClock();
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 8f18800..95185c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -244,10 +244,8 @@
             mFirstPageDelayedAnimator = new TouchAnimator.Builder()
                     .setStartDelay(EXPANDED_TILE_DELAY)
                     .addFloat(tileLayout, "alpha", 0, 1)
-                    .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
                     .addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
                     .addFloat(mQsPanel.getFooter().getView(), "alpha", 0, 1).build();
-            mAllViews.add(mQsPanel.getPageIndicator());
             mAllViews.add(mQsPanel.getDivider());
             mAllViews.add(mQsPanel.getFooter().getView());
             float px = 0;
@@ -265,7 +263,6 @@
         }
         mNonfirstPageAnimator = new TouchAnimator.Builder()
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
-                .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
                 .addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
                 .setListener(mNonFirstPageListener)
                 .setEndDelay(.5f)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7320b86..6b0d592 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -17,11 +17,11 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -80,11 +80,22 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        getDisplay().getRealSize(mSizePoint);
+
         // Since we control our own bottom, be whatever size we want.
         // Otherwise the QSPanel ends up with 0 height when the window is only the
         // size of the status bar.
-        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
-                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
+        Configuration config = getResources().getConfiguration();
+        boolean navBelow = config.smallestScreenWidthDp >= 600
+                || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
+        MarginLayoutParams params = (MarginLayoutParams) mQSPanel.getLayoutParams();
+        int maxQs = mSizePoint.y - params.topMargin - params.bottomMargin - getPaddingBottom()
+                - getResources().getDimensionPixelSize(R.dimen.qs_notif_collapsed_space);
+        if (navBelow) {
+            maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
+        }
+        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+
         int width = mQSPanel.getMeasuredWidth();
         LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
         int height = layoutParams.topMargin + layoutParams.bottomMargin
@@ -94,7 +105,6 @@
 
         // QSCustomizer will always be the height of the screen, but do this after
         // other measuring to avoid changing the height of the QS.
-        getDisplay().getRealSize(mSizePoint);
         mQSCustomizer.measure(widthMeasureSpec,
                 MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index cdf0c0f..29a8f16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -207,6 +208,11 @@
     }
 
     @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return isCustomizing() || mQSPanel.onInterceptTouchEvent(event);
+    }
+
+    @Override
     public void setHeaderClickable(boolean clickable) {
         if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 310e12e..00b6c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -28,8 +28,8 @@
 import android.service.quicksettings.Tile;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -62,11 +62,8 @@
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
     protected final View mBrightnessView;
     private final H mHandler = new H();
-    private final View mPageIndicator;
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
-    private int mPanelPaddingBottom;
-    private int mBrightnessPaddingTop;
     protected boolean mExpanded;
     protected boolean mListening;
 
@@ -77,6 +74,7 @@
     protected QSSecurityFooter mFooter;
     private boolean mGridContentVisible = true;
 
+    private QSScrollLayout mScrollLayout;
     protected QSTileLayout mTileLayout;
 
     private QSCustomizer mCustomizePanel;
@@ -95,18 +93,12 @@
 
         setOrientation(VERTICAL);
 
-        mBrightnessView = LayoutInflater.from(context).inflate(
-                R.layout.quick_settings_brightness_dialog, this, false);
-        addView(mBrightnessView);
-
-        setupTileLayout();
-
-        mPageIndicator = LayoutInflater.from(context).inflate(
-                R.layout.qs_page_indicator, this, false);
-        addView(mPageIndicator);
-        if (mTileLayout instanceof PagedTileLayout) {
-            ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
-        }
+        mBrightnessView = LayoutInflater.from(mContext).inflate(
+            R.layout.quick_settings_brightness_dialog, this, false);
+        mTileLayout = new TileLayout(mContext);
+        mTileLayout.setListening(mListening);
+        mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout);
+        addView(mScrollLayout);
 
         addDivider();
 
@@ -131,17 +123,6 @@
         return mDivider;
     }
 
-    public View getPageIndicator() {
-        return mPageIndicator;
-    }
-
-    protected void setupTileLayout() {
-        mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
-                R.layout.qs_paged_tile_layout, this, false);
-        mTileLayout.setListening(mListening);
-        addView((View) mTileLayout);
-    }
-
     public boolean isShowingCustomize() {
         return mCustomizePanel != null && mCustomizePanel.isCustomizing();
     }
@@ -241,9 +222,13 @@
 
     public void updateResources() {
         final Resources res = mContext.getResources();
-        mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
-        mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
-        setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
+        mBrightnessView.setPadding(
+            mBrightnessView.getPaddingLeft(),
+            res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top),
+            mBrightnessView.getPaddingRight(),
+            mBrightnessView.getPaddingBottom());
+        setPadding(
+            0, 0, 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
         for (TileRecord r : mRecords) {
             r.tile.clearState();
         }
@@ -282,8 +267,11 @@
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
-        if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
-            ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+        if (!mExpanded) {
+            if (mTileLayout instanceof PagedTileLayout) {
+                ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+            }
+            mScrollLayout.setScrollY(0);
         }
         mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded);
         if (!mExpanded) {
@@ -565,6 +553,11 @@
         mFooter.showDeviceMonitoringDialog();
     }
 
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mExpanded && mScrollLayout.shouldIntercept(event);
+    }
+
     private class H extends Handler {
         private static final int SHOW_DETAIL = 1;
         private static final int SET_TILE_VISIBILITY = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
new file mode 100644
index 0000000..9a74787
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.v4.widget.NestedScrollView;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+
+/**
+ * Quick setting scroll view containing the brightness slider and the QS tiles.
+ *
+ * <p>Call {@link #shouldIntercept(MotionEvent)} from parent views'
+ * {@link #onInterceptTouchEvent(MotionEvent)} method to determine whether this view should
+ * consume the touch event.
+ */
+public class QSScrollLayout extends NestedScrollView {
+    private final int mTouchSlop;
+    private int mLastMotionY;
+    private Rect mHitRect = new Rect();
+
+    public QSScrollLayout(Context context, View... children) {
+        super(context);
+        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(
+            LinearLayout.LayoutParams.MATCH_PARENT,
+            LinearLayout.LayoutParams.WRAP_CONTENT));
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        for (View view : children) {
+            linearLayout.addView(view);
+        }
+        addView(linearLayout);
+    }
+
+    public boolean shouldIntercept(MotionEvent ev) {
+        getHitRect(mHitRect);
+        if (!mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+            // Do not intercept touches that are not within this view's bounds.
+            return false;
+        }
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mLastMotionY = (int) ev.getY();
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
+            // Do not allow NotificationPanelView to intercept touch events when this
+            // view can be scrolled down.
+            if (mLastMotionY >= 0 && Math.abs(ev.getY() - mLastMotionY) > mTouchSlop
+                    && canScrollVertically(1)) {
+                requestParentDisallowInterceptTouchEvent(true);
+                mLastMotionY = (int) ev.getY();
+                return true;
+            }
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+            || ev.getActionMasked() == MotionEvent.ACTION_UP) {
+            mLastMotionY = -1;
+            requestParentDisallowInterceptTouchEvent(false);
+        }
+        return false;
+    }
+
+    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 947b23f..8314855 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -20,6 +20,7 @@
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.Space;
 
@@ -50,13 +51,14 @@
     public QuickQSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
         if (mFooter != null) {
-            removeView((View) mFooter.getView());
+            removeView(mFooter.getView());
         }
         if (mTileLayout != null) {
             for (int i = 0; i < mRecords.size(); i++) {
                 mTileLayout.removeTile(mRecords.get(i));
             }
-            removeView((View) mTileLayout);
+            View tileLayoutView = (View) mTileLayout;
+            ((ViewGroup) tileLayoutView.getParent()).removeView(tileLayoutView);
         }
         mTileLayout = new HeaderTileLayout(context);
         mTileLayout.setListening(mListening);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index b9e6725..1aaa3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -15,6 +15,9 @@
  */
 package com.android.systemui.statusbar;
 
+import static android.service.notification.NotificationListenerService.Ranking
+        .USER_SENTIMENT_NEGATIVE;
+
 import android.app.INotificationManager;
 import android.app.NotificationChannel;
 import android.content.Context;
@@ -230,7 +233,8 @@
             try {
                 info.bindNotification(pmUser, iNotificationManager, pkg, row.getEntry().channel,
                         channels.size(), sbn, mCheckSaveListener, onSettingsClick,
-                        onAppSettingsClick, mNonBlockablePkgs);
+                        onAppSettingsClick, mNonBlockablePkgs,
+                        row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 6279fdc..735f4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -79,6 +79,7 @@
     private OnSettingsClickListener mOnSettingsClickListener;
     private OnAppSettingsClickListener mAppSettingsClickListener;
     private NotificationGuts mGutsContainer;
+    private boolean mNegativeUserSentiment;
 
     private OnClickListener mOnKeepShowing = v -> {
         closeControls(v);
@@ -122,6 +123,22 @@
             final OnAppSettingsClickListener onAppSettingsClick,
             final Set<String> nonBlockablePkgs)
             throws RemoteException {
+        bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
+                checkSaveListener, onSettingsClick, onAppSettingsClick, nonBlockablePkgs,
+                false /* negative sentiment */);
+    }
+
+    public void bindNotification(final PackageManager pm,
+            final INotificationManager iNotificationManager,
+            final String pkg,
+            final NotificationChannel notificationChannel,
+            final int numChannels,
+            final StatusBarNotification sbn,
+            final CheckSaveListener checkSaveListener,
+            final OnSettingsClickListener onSettingsClick,
+            final OnAppSettingsClickListener onAppSettingsClick,
+            final Set<String> nonBlockablePkgs,
+            boolean negativeUserSentiment)  throws RemoteException {
         mINotificationManager = iNotificationManager;
         mPkg = pkg;
         mNumNotificationChannels = numChannels;
@@ -133,6 +150,7 @@
         mOnSettingsClickListener = onSettingsClick;
         mSingleNotificationChannel = notificationChannel;
         mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
+        mNegativeUserSentiment = negativeUserSentiment;
 
         int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                 pkg, mAppUid, false /* includeDeleted */);
@@ -227,27 +245,30 @@
     }
 
     private void bindPrompt() {
-        final TextView channelName = findViewById(R.id.channel_name);
         final TextView blockPrompt = findViewById(R.id.block_prompt);
+        bindName();
         if (mNonblockable) {
-            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
-                channelName.setVisibility(View.GONE);
-            } else {
-                channelName.setText(mSingleNotificationChannel.getName());
-            }
-
             blockPrompt.setText(R.string.notification_unblockable_desc);
         } else {
-            if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
-                channelName.setVisibility(View.GONE);
+            if (mNegativeUserSentiment) {
+                blockPrompt.setText(R.string.inline_blocking_helper);
+            }  else if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
                 blockPrompt.setText(R.string.inline_keep_showing_app);
             } else {
-                channelName.setText(mSingleNotificationChannel.getName());
                 blockPrompt.setText(R.string.inline_keep_showing);
             }
         }
     }
 
+    private void bindName() {
+        final TextView channelName = findViewById(R.id.channel_name);
+        if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+            channelName.setVisibility(View.GONE);
+        } else {
+            channelName.setText(mSingleNotificationChannel.getName());
+        }
+    }
+
     private boolean hasImportanceChanged() {
         return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index dc51b1c..61c8027 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -124,6 +124,7 @@
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private int mDisabledFlags1;
     private StatusBar mStatusBar;
@@ -224,7 +225,7 @@
         mNavigationBarView = (NavigationBarView) view;
 
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
-        mNavigationBarView.setComponents(mRecents, mDivider);
+        mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
         if (savedInstanceState != null) {
@@ -355,6 +356,7 @@
             mLastRotationSuggestion = rotation; // Remember rotation for click
             setRotateSuggestionButtonState(true);
             rescheduleRotationTimeout(false);
+            mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
         }
     }
 
@@ -612,7 +614,7 @@
         if (shouldDisableNavbarGestures()) {
             return false;
         }
-        MetricsLogger.action(getContext(), MetricsEvent.ACTION_ASSIST_LONG_PRESS);
+        mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
         mAssistManager.startAssist(new Bundle() /* args */);
         mStatusBar.awakenDreams();
 
@@ -768,6 +770,7 @@
     }
 
     private void onRotateSuggestionClick(View v) {
+        mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
         mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index ff923e5..0954fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -34,6 +34,7 @@
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
@@ -78,6 +79,7 @@
     private final int mScrollTouchSlop;
     private final Matrix mTransformGlobalMatrix = new Matrix();
     private final Matrix mTransformLocalMatrix = new Matrix();
+    private final StatusBar mStatusBar;
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mDownOnRecents;
@@ -90,6 +92,7 @@
 
     public NavigationBarGestureHelper(Context context) {
         mContext = context;
+        mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
         Resources r = context.getResources();
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
         mQuickScrubController = new QuickScrubController(context);
@@ -146,7 +149,8 @@
                 break;
             }
         }
-        if (!mQuickScrubController.onInterceptTouchEvent(event)) {
+        if (mStatusBar.isPresenterFullyCollapsed()
+                && !mQuickScrubController.onInterceptTouchEvent(event)) {
             proxyMotionEvents(event);
             return false;
         }
@@ -304,7 +308,8 @@
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        boolean result = mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event);
+        boolean result = mStatusBar.isPresenterFullyCollapsed()
+                && (mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event));
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9bef0ee..9f4d35e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -126,6 +126,7 @@
     private RecentsComponent mRecentsComponent;
     private Divider mDivider;
     private SwipeUpOnboarding mSwipeUpOnboarding;
+    private NotificationPanelView mPanelView;
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -206,7 +207,7 @@
     }
 
     private final OverviewProxyListener mOverviewProxyListener = isConnected -> {
-        setSlippery(!isConnected);
+        updateSlippery();
         setDisabledFlags(mDisabledFlags, true);
         setUpSwipeUpOnboarding(isConnected);
     };
@@ -251,9 +252,11 @@
         return mBarTransitions.getLightTransitionsController();
     }
 
-    public void setComponents(RecentsComponent recentsComponent, Divider divider) {
+    public void setComponents(RecentsComponent recentsComponent, Divider divider,
+            NotificationPanelView panel) {
         mRecentsComponent = recentsComponent;
         mDivider = divider;
+        mPanelView = panel;
         if (mGestureHelper instanceof NavigationBarGestureHelper) {
             ((NavigationBarGestureHelper) mGestureHelper).setComponents(
                     recentsComponent, divider, this);
@@ -571,6 +574,14 @@
         }
     }
 
+    public void onPanelExpandedChange(boolean expanded) {
+        updateSlippery();
+    }
+
+    private void updateSlippery() {
+        setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
+    }
+
     private void setSlippery(boolean slippery) {
         boolean changed = false;
         final ViewGroup navbarView = ((ViewGroup) getParent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5d3cc34..31b8159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -47,7 +47,6 @@
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardStatusView;
@@ -675,7 +674,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mBlockTouches || mQs.isCustomizing()) {
+        if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
             return false;
         }
         initDownStates(event);
@@ -2633,6 +2632,7 @@
 
     public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
         mKeyguardStatusView.setPulsing(pulsing != null);
+        positionClockAndNotifications();
         mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1]
                 + mKeyguardStatusView.getClockBottom());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index b181212..cc5a93c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -250,6 +250,9 @@
         super.panelExpansionChanged(frac, expanded);
         mPanelFraction = frac;
         updateScrimFraction();
+        if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
+            mBar.getNavigationBarView().onPanelExpandedChange(expanded);
+        }
     }
 
     private void updateScrimFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index ee1d088..001a1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -82,7 +83,10 @@
     private boolean mDragPositive;
     private boolean mIsVertical;
     private boolean mIsRTL;
-    private float mMaxTrackPaintAlpha;
+    private float mTrackAlpha;
+    private int mLightTrackColor;
+    private int mDarkTrackColor;
+    private float mDarkIntensity;
 
     private final Handler mHandler = new Handler();
     private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
@@ -98,9 +102,10 @@
     private final ValueAnimator mButtonAnimator;
     private final AnimatorSet mQuickScrubEndAnimator;
     private final Context mContext;
+    private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
 
     private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
-        mTrackPaint.setAlpha(Math.round((float) valueAnimator.getAnimatedValue() * 255));
+        mTrackAlpha = (float) valueAnimator.getAnimatedValue();
         mNavigationBarView.invalidate();
     };
 
@@ -167,6 +172,7 @@
         mGestureDetector = new GestureDetector(mContext, mGestureListener);
         mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
         mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
+        mTrackPaint.setAlpha(0);
 
         mTrackAnimator = ObjectAnimator.ofFloat();
         mTrackAnimator.addUpdateListener(mTrackAnimatorListener);
@@ -291,6 +297,10 @@
 
     @Override
     public void onDraw(Canvas canvas) {
+        int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
+                mDarkTrackColor);
+        mTrackPaint.setColor(color);
+        mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
         canvas.drawRect(mTrackRect, mTrackPaint);
     }
 
@@ -326,13 +336,8 @@
 
     @Override
     public void onDarkIntensityChange(float intensity) {
-        if (intensity == 0) {
-            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_light));
-        } else if (intensity == 1) {
-            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_dark));
-        }
-        mMaxTrackPaintAlpha = mTrackPaint.getAlpha() * 1f / 255;
-        mTrackPaint.setAlpha(0);
+        mDarkIntensity = intensity;
+        mNavigationBarView.invalidate();
     }
 
     @Override
@@ -365,7 +370,9 @@
     private void startQuickScrub() {
         if (!mQuickScrubActive) {
             mQuickScrubActive = true;
-            mTrackAnimator.setFloatValues(0, mMaxTrackPaintAlpha);
+            mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
+            mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
+            mTrackAnimator.setFloatValues(0, 1);
             mTrackAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubStart();
@@ -382,7 +389,7 @@
         mHandler.removeCallbacks(mLongPressRunnable);
         if (mDraggingActive || mQuickScrubActive) {
             mButtonAnimator.setIntValues((int) mTranslation, 0);
-            mTrackAnimator.setFloatValues(mTrackPaint.getAlpha() * 1f / 255, 0);
+            mTrackAnimator.setFloatValues(mTrackAlpha, 0);
             mQuickScrubEndAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 0b666a6..1e894ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -32,6 +32,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
 import com.android.systemui.util.Utils;
 import java.util.ArrayList;
@@ -105,7 +106,8 @@
         }
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
-        updateLocationEnabled(mContext, enabled, currentUserId);
+        updateLocationEnabled(mContext, enabled, currentUserId,
+                Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
         return true;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index d77bf69..8e8b3e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -281,6 +281,16 @@
     }
 
     @Test
+    public void testbindNotification_BlockingHelper() throws Exception {
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
+                null, null, true);
+        final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
+        assertEquals(View.VISIBLE, view.getVisibility());
+        assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
+    }
+
+    @Test
     public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 699231f..03dfd46 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5158,6 +5158,16 @@
     // OS: P
     NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286;
 
+    // ACTION: Rotate suggestion accepted in rotation locked mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: P
+    ACTION_ROTATION_SUGGESTION_ACCEPTED = 1287;
+
+    // OPEN: Rotation suggestion shown in rotation locked mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: P
+    ROTATION_SUGGESTION_SHOWN = 1288;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9aa588f..bd93b179 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -67,6 +67,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -829,7 +830,7 @@
             }
             mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
             mIdentity = new Identity(uid, pid, packageName);
-            if (workSource != null && workSource.size() <= 0) {
+            if (workSource != null && workSource.isEmpty()) {
                 workSource = null;
             }
             mWorkSource = workSource;
@@ -1814,13 +1815,11 @@
 
                         if (locationRequest.getInterval() <= thresholdInterval) {
                             if (record.mReceiver.mWorkSource != null
-                                    && record.mReceiver.mWorkSource.size() > 0
-                                    && record.mReceiver.mWorkSource.getName(0) != null) {
-                                // Assign blame to another work source.
-                                // Can only assign blame if the WorkSource contains names.
+                                    && isValidWorkSource(record.mReceiver.mWorkSource)) {
                                 worksource.add(record.mReceiver.mWorkSource);
                             } else {
-                                // Assign blame to caller.
+                                // Assign blame to caller if there's no WorkSource associated with
+                                // the request or if it's invalid.
                                 worksource.add(
                                         record.mReceiver.mIdentity.mUid,
                                         record.mReceiver.mIdentity.mPackageName);
@@ -1835,6 +1834,23 @@
         p.setRequest(providerRequest, worksource);
     }
 
+    /**
+     * Whether a given {@code WorkSource} associated with a Location request is valid.
+     */
+    private static boolean isValidWorkSource(WorkSource workSource) {
+        if (workSource.size() > 0) {
+            // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
+            // by tags.
+            return workSource.getName(0) != null;
+        } else {
+            // For now, make sure callers have supplied an attribution tag for use with
+            // AppOpsManager. This might be relaxed in the future.
+            final ArrayList<WorkChain> workChains = workSource.getWorkChains();
+            return workChains != null && !workChains.isEmpty() &&
+                    workChains.get(0).getAttributionTag() != null;
+        }
+    }
+
     @Override
     public String[] getBackgroundThrottlingWhitelist() {
         synchronized (mLock) {
@@ -2057,7 +2073,7 @@
         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                 request.getProvider());
         WorkSource workSource = request.getWorkSource();
-        if (workSource != null && workSource.size() > 0) {
+        if (workSource != null && !workSource.isEmpty()) {
             checkDeviceStatsAllowed();
         }
         boolean hideFromAppOps = request.getHideFromAppOps();
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 7cd3406..39fc019 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -701,7 +701,8 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        if (args.length == 0) {  // Dump all users' data
+        if (args.length == 0 || (args.length == 1 && args[0].equals("-a"))) {
+            // Dump all users' data
             synchronized (mLock) {
                 pw.println("Current Text Services Manager state:");
                 pw.println("  Users:");
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index db21ef1..427ccba 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -410,7 +410,7 @@
             }
         } finally {
             final ActivityStack topFullscreenStack =
-                    getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+                    getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
             if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
                 // Whenever split-screen is dismissed we want the home stack directly behind the
                 // current top fullscreen stack so it shows up when the top stack is finished.
@@ -566,6 +566,16 @@
         return false;
     }
 
+    ActivityStack getTopStackInWindowingMode(int windowingMode) {
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            final ActivityStack current = mStacks.get(i);
+            if (windowingMode == current.getWindowingMode()) {
+                return current;
+            }
+        }
+        return null;
+    }
+
     int getIndexOf(ActivityStack stack) {
         return mStacks.indexOf(stack);
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 364d5d5..1f5bfe6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -46,6 +46,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -228,6 +229,7 @@
 import android.app.BroadcastOptions;
 import android.app.ContentProviderHolder;
 import android.app.Dialog;
+import android.app.GrantedUriPermission;
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -10204,7 +10206,8 @@
                 if (perms == null) {
                     Slog.w(TAG, "No permission grants found for " + packageName);
                 } else {
-                    for (UriPermission perm : perms.values()) {
+                    for (int j = 0; j < perms.size(); j++) {
+                        final UriPermission perm = perms.valueAt(j);
                         if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
@@ -10215,7 +10218,8 @@
                 for (int i = 0; i < size; i++) {
                     final ArrayMap<GrantUri, UriPermission> perms =
                             mGrantedUriPermissions.valueAt(i);
-                    for (UriPermission perm : perms.values()) {
+                    for (int j = 0; j < perms.size(); j++) {
+                        final UriPermission perm = perms.valueAt(j);
                         if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
@@ -10227,25 +10231,27 @@
     }
 
     @Override
-    public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions(
-            String packageName, int userId) {
+    public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+            @Nullable String packageName, int userId) {
         enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
                 "getGrantedUriPermissions");
 
-        final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+        final List<GrantedUriPermission> result = new ArrayList<>();
         synchronized (this) {
             final int size = mGrantedUriPermissions.size();
             for (int i = 0; i < size; i++) {
                 final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
-                for (UriPermission perm : perms.values()) {
-                    if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId
+                for (int j = 0; j < perms.size(); j++) {
+                    final UriPermission perm = perms.valueAt(j);
+                    if ((packageName == null || packageName.equals(perm.targetPkg))
+                            && perm.targetUserId == userId
                             && perm.persistedModeFlags != 0) {
-                        result.add(perm.buildPersistedPublicApiObject());
+                        result.add(perm.buildGrantedUriPermission());
                     }
                 }
             }
         }
-        return new ParceledListSlice<android.content.UriPermission>(result);
+        return new ParceledListSlice<>(result);
     }
 
     @Override
@@ -11037,8 +11043,20 @@
                 }
 
                 if (toTop) {
+                    // Caller wants the current split-screen primary stack to be the top stack after
+                    // it goes fullscreen, so move it to the front.
                     stack.moveToFront("dismissSplitScreenMode");
+                } else if (mStackSupervisor.isFocusedStack(stack)) {
+                    // In this case the current split-screen primary stack shouldn't be the top
+                    // stack after it goes fullscreen, but it current has focus, so we move the
+                    // focus to the top-most split-screen secondary stack next to it.
+                    final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode(
+                            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                    if (otherStack != null) {
+                        otherStack.moveToFront("dismissSplitScreenMode_other");
+                    }
                 }
+
                 stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
             }
         } finally {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 04b49ba..0d96468 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -353,10 +354,12 @@
         }
     }
 
+    /** @param state Process state from ActivityManager.java. */
     void noteUidProcessState(int uid, int state) {
         synchronized (mStats) {
             // TODO: remove this once we figure out properly where and how
-            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid, state);
+            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid,
+                    ActivityManager.processStateAmToProto(state));
 
             mStats.noteUidProcessStateLocked(uid, state);
         }
@@ -582,17 +585,11 @@
         }
     }
 
-    public void noteStartGps(int uid) {
+    @Override
+    public void noteGpsChanged(WorkSource oldWs, WorkSource newWs) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartGpsLocked(uid);
-        }
-    }
-
-    public void noteStopGps(int uid) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStopGpsLocked(uid);
+            mStats.noteGpsChangedLocked(oldWs, newWs);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 29bfebe..a50d069 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -24,7 +24,7 @@
 import java.nio.ByteBuffer;
 
 import android.app.ActivityManager;
-import android.app.ActivityManagerProto;
+import android.app.AppProtoEnums;
 import android.os.Build;
 import android.os.SystemClock;
 import com.android.internal.util.MemInfoReader;
@@ -420,47 +420,49 @@
     public static int makeProcStateProtoEnum(int curProcState) {
         switch (curProcState) {
             case ActivityManager.PROCESS_STATE_PERSISTENT:
-                return ActivityManagerProto.PROCESS_STATE_PERSISTENT;
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT;
             case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
-                return ActivityManagerProto.PROCESS_STATE_PERSISTENT_UI;
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
             case ActivityManager.PROCESS_STATE_TOP:
-                return ActivityManagerProto.PROCESS_STATE_TOP;
+                return AppProtoEnums.PROCESS_STATE_TOP;
             case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_FOREGROUND_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
             case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
-                return ActivityManagerProto.PROCESS_STATE_TOP_SLEEPING;
+                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
-                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
             case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
-                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
             case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
-                return ActivityManagerProto.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
             case ActivityManager.PROCESS_STATE_BACKUP:
-                return ActivityManagerProto.PROCESS_STATE_BACKUP;
+                return AppProtoEnums.PROCESS_STATE_BACKUP;
             case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
-                return ActivityManagerProto.PROCESS_STATE_HEAVY_WEIGHT;
+                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
             case ActivityManager.PROCESS_STATE_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_SERVICE;
             case ActivityManager.PROCESS_STATE_RECEIVER:
-                return ActivityManagerProto.PROCESS_STATE_RECEIVER;
+                return AppProtoEnums.PROCESS_STATE_RECEIVER;
             case ActivityManager.PROCESS_STATE_HOME:
-                return ActivityManagerProto.PROCESS_STATE_HOME;
+                return AppProtoEnums.PROCESS_STATE_HOME;
             case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
-                return ActivityManagerProto.PROCESS_STATE_LAST_ACTIVITY;
+                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY;
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
             case ActivityManager.PROCESS_STATE_CACHED_RECENT:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_RECENT;
+                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
             case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_EMPTY;
+                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
             case ActivityManager.PROCESS_STATE_NONEXISTENT:
-                return ActivityManagerProto.PROCESS_STATE_NONEXISTENT;
+                return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+            case ActivityManager.PROCESS_STATE_UNKNOWN:
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN;
             default:
-                return -1;
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 90577e3..1e071aa 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.GrantedUriPermission;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.UserHandle;
@@ -387,4 +388,8 @@
     public android.content.UriPermission buildPersistedPublicApiObject() {
         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
     }
+
+    public GrantedUriPermission buildGrantedUriPermission() {
+        return new GrantedUriPermission(uri.uri, targetPkg);
+    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index f9b35f5..e77cb7a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -48,7 +48,7 @@
 
     private boolean mIsClosed = false;
     private boolean mIsMuted = false;
-    private int mRegion;  // TODO(b/62710330): find better solution to handle regions
+    private int mRegion;
     private final boolean mWithAudio;
 
     Tuner(@NonNull ITunerCallback clientCallback, int halRev,
@@ -89,7 +89,6 @@
 
     private native void nativeCancelAnnouncement(long nativeContext);
 
-    private native RadioManager.ProgramInfo nativeGetProgramInformation(long nativeContext);
     private native boolean nativeStartBackgroundScan(long nativeContext);
     private native List<RadioManager.ProgramInfo> nativeGetProgramList(long nativeContext,
             Map<String, String> vendorFilter);
@@ -103,8 +102,6 @@
             Map<String, String> parameters);
     private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys);
 
-    private native boolean nativeIsAntennaConnected(long nativeContext);
-
     @Override
     public void close() {
         synchronized (mLock) {
@@ -218,14 +215,6 @@
     }
 
     @Override
-    public RadioManager.ProgramInfo getProgramInformation() {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            return nativeGetProgramInformation(mNativeContext);
-        }
-    }
-
-    @Override
     public Bitmap getImage(int id) {
         if (id == 0) {
             throw new IllegalArgumentException("Image ID is missing");
@@ -324,12 +313,4 @@
         if (results == null) return Collections.emptyMap();
         return results;
     }
-
-    @Override
-    public boolean isAntennaConnected() {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            return nativeIsAntennaConnected(mNativeContext);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 18f56ed..04c0e57 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -20,6 +20,7 @@
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioMetadata;
 import android.hardware.radio.RadioTuner;
@@ -100,6 +101,11 @@
     }
 
     @Override
+    public void onTuneFailed(int result, ProgramSelector selector) {
+        Slog.e(TAG, "Not applicable for HAL 1.x");
+    }
+
+    @Override
     public void onConfigurationChanged(RadioManager.BandConfig config) {
         dispatch(() -> mClientCallback.onConfigurationChanged(config));
     }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 7a95971..3bb3d1f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -73,7 +73,26 @@
         }
     }
 
-    private static @NonNull Map<String, String>
+    static @NonNull ArrayList<VendorKeyValue>
+    vendorInfoToHal(@Nullable Map<String, String> info) {
+        if (info == null) return new ArrayList<>();
+
+        ArrayList<VendorKeyValue> list = new ArrayList<>();
+        for (Map.Entry<String, String> entry : info.entrySet()) {
+            VendorKeyValue elem = new VendorKeyValue();
+            elem.key = entry.getKey();
+            elem.value = entry.getValue();
+            if (elem.key == null || elem.value == null) {
+                Slog.w(TAG, "VendorKeyValue contains null pointers");
+                continue;
+            }
+            list.add(elem);
+        }
+
+        return list;
+    }
+
+    static @NonNull Map<String, String>
     vendorInfoFromHal(@Nullable List<VendorKeyValue> info) {
         if (info == null) return Collections.emptyMap();
 
@@ -206,18 +225,23 @@
                 false,  // isCaptureSupported
 
                 amfmConfigToBands(amfmConfig),
-                false,  // isBgScanSupported is deprecated
+                true,  // isBgScanSupported is deprecated
                 supportedProgramTypes,
                 supportedIdentifierTypes,
                 vendorInfoFromHal(prop.vendorInfo)
         );
     }
 
+    static void programIdentifierToHal(@NonNull ProgramIdentifier hwId,
+            @NonNull ProgramSelector.Identifier id) {
+        hwId.type = id.getType();
+        hwId.value = id.getValue();
+    }
+
     static @NonNull ProgramIdentifier programIdentifierToHal(
             @NonNull ProgramSelector.Identifier id) {
         ProgramIdentifier hwId = new ProgramIdentifier();
-        hwId.type = id.getType();
-        hwId.value = id.getValue();
+        programIdentifierToHal(hwId, id);
         return hwId;
     }
 
@@ -227,10 +251,22 @@
         return new ProgramSelector.Identifier(id.type, id.value);
     }
 
+    static @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector programSelectorToHal(
+            @NonNull ProgramSelector sel) {
+        android.hardware.broadcastradio.V2_0.ProgramSelector hwSel =
+            new android.hardware.broadcastradio.V2_0.ProgramSelector();
+
+        programIdentifierToHal(hwSel.primaryId, sel.getPrimaryId());
+        Arrays.stream(sel.getSecondaryIds()).map(Convert::programIdentifierToHal).
+                forEachOrdered(hwSel.secondaryIds::add);
+
+        return hwSel;
+    }
+
     static @NonNull ProgramSelector programSelectorFromHal(
             @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) {
         ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream().
-                map(id -> Objects.requireNonNull(programIdentifierFromHal(id))).
+                map(Convert::programIdentifierFromHal).map(Objects::requireNonNull).
                 toArray(ProgramSelector.Identifier[]::new);
 
         return new ProgramSelector(
@@ -286,4 +322,10 @@
             vendorInfoFromHal(hwAnnouncement.vendorInfo)
         );
     }
+
+    static <T> @Nullable ArrayList<T> listToArrayList(@Nullable List<T> list) {
+        if (list == null) return null;
+        if (list instanceof ArrayList) return (ArrayList) list;
+        return new ArrayList<>(list);
+    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 4dff9e0..50f032d 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.RadioManager;
 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
@@ -76,15 +78,17 @@
         Mutable<ITunerSession> hwSession = new Mutable<>();
         MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
 
-        mService.openSession(cb, (int result, ITunerSession session) -> {
-            hwSession.value = session;
-            halResult.value = result;
-        });
+        synchronized (mService) {
+            mService.openSession(cb, (result, session) -> {
+                hwSession.value = session;
+                halResult.value = result;
+            });
+        }
 
         Convert.throwOnError("openSession", halResult.value);
         Objects.requireNonNull(hwSession.value);
 
-        return new TunerSession(hwSession.value, cb);
+        return new TunerSession(this, hwSession.value, cb);
     }
 
     public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
@@ -103,10 +107,13 @@
                     map(a -> Convert.announcementFromHal(a)).collect(Collectors.toList()));
             }
         };
-        mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHandle) -> {
-            halResult.value = result;
-            hwCloseHandle.value = closeHandle;
-        });
+
+        synchronized (mService) {
+            mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
+                halResult.value = result;
+                hwCloseHandle.value = closeHnd;
+            });
+        }
         Convert.throwOnError("addAnnouncementListener", halResult.value);
 
         return new android.hardware.radio.ICloseHandle.Stub() {
@@ -119,4 +126,21 @@
             }
         };
     }
+
+    Bitmap getImage(int id) {
+        if (id == 0) throw new IllegalArgumentException("Image ID is missing");
+
+        byte[] rawImage;
+        synchronized (mService) {
+            List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
+            rawImage = new byte[rawList.size()];
+            for (int i = 0; i < rawList.size(); i++) {
+                rawImage[i] = rawList.get(i);
+            }
+        }
+
+        if (rawImage == null || rawImage.length == 0) return null;
+
+        return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
+    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
index ed2a1b3..3c4b49c 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
@@ -50,10 +50,14 @@
     }
 
     @Override
-    public void onTuneFailed(int result, ProgramSelector selector) {}
+    public void onTuneFailed(int result, ProgramSelector selector) {
+        dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector)));
+    }
 
     @Override
-    public void onCurrentProgramInfoChanged(ProgramInfo info) {}
+    public void onCurrentProgramInfoChanged(ProgramInfo info) {
+        dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info)));
+    }
 
     @Override
     public void onProgramListUpdated(ProgramListChunk chunk) {
@@ -61,8 +65,12 @@
     }
 
     @Override
-    public void onAntennaStateChange(boolean connected) {}
+    public void onAntennaStateChange(boolean connected) {
+        dispatch(() -> mClientCb.onAntennaState(connected));
+    }
 
     @Override
-    public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {}
+    public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
+        dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 1ae7d20..8efaa2a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -41,6 +41,7 @@
 
     private final Object mLock = new Object();
 
+    private final RadioModule mModule;
     private final ITunerSession mHwSession;
     private final TunerCallback mCallback;
     private boolean mIsClosed = false;
@@ -50,7 +51,9 @@
     // necessary only for older APIs compatibility
     private RadioManager.BandConfig mDummyConfig = null;
 
-    TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) {
+    TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
+            @NonNull TunerCallback callback) {
+        mModule = Objects.requireNonNull(module);
         mHwSession = Objects.requireNonNull(hwSession);
         mCallback = Objects.requireNonNull(callback);
         notifyAudioServiceLocked(true);
@@ -128,23 +131,29 @@
     }
 
     @Override
-    public void step(boolean directionDown, boolean skipSubChannel) {
+    public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
+            int halResult = mHwSession.step(!directionDown);
+            Convert.throwOnError("step", halResult);
         }
     }
 
     @Override
-    public void scan(boolean directionDown, boolean skipSubChannel) {
+    public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
+            int halResult = mHwSession.scan(!directionDown, skipSubChannel);
+            Convert.throwOnError("step", halResult);
         }
     }
 
     @Override
-    public void tune(ProgramSelector selector) {
+    public void tune(ProgramSelector selector) throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
+            int halResult = mHwSession.tune(Convert.programSelectorToHal(selector));
+            Convert.throwOnError("tune", halResult);
         }
     }
 
@@ -152,36 +161,25 @@
     public void cancel() {
         synchronized (mLock) {
             checkNotClosedLocked();
+            Utils.maybeRethrow(mHwSession::cancel);
         }
     }
 
     @Override
     public void cancelAnnouncement() {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-        }
-    }
-
-    @Override
-    public RadioManager.ProgramInfo getProgramInformation() {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            return null;
-        }
+        Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in 2.x");
     }
 
     @Override
     public Bitmap getImage(int id) {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            return null;
-        }
+        return mModule.getImage(id);
     }
 
     @Override
     public boolean startBackgroundScan() {
         Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x");
-        return false;
+        TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete());
+        return true;
     }
 
     @Override
@@ -240,7 +238,6 @@
         Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
         synchronized (mLock) {
             checkNotClosedLocked();
-
             int halResult = mHwSession.setConfigFlag(flag, value);
             Convert.throwOnError("setConfigFlag", halResult);
         }
@@ -250,7 +247,8 @@
     public Map setParameters(Map parameters) {
         synchronized (mLock) {
             checkNotClosedLocked();
-            return null;
+            return Convert.vendorInfoFromHal(Utils.maybeRethrow(
+                    () -> mHwSession.setParameters(Convert.vendorInfoToHal(parameters))));
         }
     }
 
@@ -258,15 +256,8 @@
     public Map getParameters(List<String> keys) {
         synchronized (mLock) {
             checkNotClosedLocked();
-            return null;
-        }
-    }
-
-    @Override
-    public boolean isAntennaConnected() {
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            return true;
+            return Convert.vendorInfoFromHal(Utils.maybeRethrow(
+                    () -> mHwSession.getParameters(Convert.listToArrayList(keys))));
         }
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
index 3520f37..384c9ba 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
@@ -16,6 +16,9 @@
 
 package com.android.server.broadcastradio.hal2;
 
+import android.annotation.NonNull;
+import android.os.RemoteException;
+
 enum FrequencyBand {
     UNKNOWN,
     FM,
@@ -37,4 +40,29 @@
         if (freq < 110000) return FrequencyBand.FM;
         return FrequencyBand.UNKNOWN;
     }
+
+    interface FuncThrowingRemoteException<T> {
+        T exec() throws RemoteException;
+    }
+
+    static <T> T maybeRethrow(@NonNull FuncThrowingRemoteException<T> r) {
+        try {
+            return r.exec();
+        } catch (RemoteException ex) {
+            ex.rethrowFromSystemServer();
+            return null;  // unreachable
+        }
+    }
+
+    interface VoidFuncThrowingRemoteException {
+        void exec() throws RemoteException;
+    }
+
+    static void maybeRethrow(@NonNull VoidFuncThrowingRemoteException r) {
+        try {
+            r.exec();
+        } catch (RemoteException ex) {
+            ex.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ad2cf6c..422d0cb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -20,6 +20,8 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerInternal;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.Notification;
@@ -32,6 +34,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ISyncAdapter;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
 import android.content.ISyncContext;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -212,6 +215,10 @@
     private static final int SYNC_OP_STATE_INVALID = 1;
     private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
 
+    /** Flags used when connecting to a sync adapter service */
+    private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
+            | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
+
     private Context mContext;
 
     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -876,7 +883,7 @@
     public void scheduleSync(Account requestedAccount, int userId, int reason,
                              String requestedAuthority, Bundle extras, int targetSyncState) {
         scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
-                0 /* min delay */);
+                0 /* min delay */, true /* checkIfAccountReady */);
     }
 
     /**
@@ -884,7 +891,7 @@
      */
     private void scheduleSync(Account requestedAccount, int userId, int reason,
                              String requestedAuthority, Bundle extras, int targetSyncState,
-                             final long minDelayMillis) {
+                             final long minDelayMillis, boolean checkIfAccountReady) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -963,7 +970,8 @@
             }
 
             for (String authority : syncableAuthorities) {
-                int isSyncable = computeSyncable(account.account, account.userId, authority);
+                int isSyncable = computeSyncable(account.account, account.userId, authority,
+                        !checkIfAccountReady);
 
                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
                     continue;
@@ -1000,7 +1008,8 @@
                                 if (result != null
                                         && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
                                     scheduleSync(account.account, userId, reason, authority,
-                                            finalExtras, targetSyncState, minDelayMillis);
+                                            finalExtras, targetSyncState, minDelayMillis,
+                                            true /* checkIfAccountReady */);
                                 }
                             }
                         ));
@@ -1009,7 +1018,7 @@
 
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
-                if (isSyncable < 0 && isAlwaysSyncable) {
+                if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
                     mSyncStorageEngine.setIsSyncable(
                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
                     isSyncable = AuthorityInfo.SYNCABLE;
@@ -1045,25 +1054,34 @@
                 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
 
                 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
-                    // Initialisation sync.
-                    Bundle newExtras = new Bundle();
-                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
-                    if (isLoggable) {
-                        Slog.v(TAG, "schedule initialisation Sync:"
-                                + ", delay until " + delayUntil
-                                + ", run by " + 0
-                                + ", flexMillis " + 0
-                                + ", source " + source
-                                + ", account " + account
-                                + ", authority " + authority
-                                + ", extras " + newExtras);
+                    if (checkIfAccountReady) {
+                        Bundle finalExtras = new Bundle(extras);
+
+                        sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
+                                () -> scheduleSync(account.account, account.userId, reason,
+                                        authority, finalExtras, targetSyncState, minDelayMillis,
+                                        false));
+                    } else {
+                        // Initialisation sync.
+                        Bundle newExtras = new Bundle();
+                        newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+                        if (isLoggable) {
+                            Slog.v(TAG, "schedule initialisation Sync:"
+                                    + ", delay until " + delayUntil
+                                    + ", run by " + 0
+                                    + ", flexMillis " + 0
+                                    + ", source " + source
+                                    + ", account " + account
+                                    + ", authority " + authority
+                                    + ", extras " + newExtras);
+                        }
+                        postScheduleSyncMessage(
+                                new SyncOperation(account.account, account.userId,
+                                        owningUid, owningPackage, reason, source,
+                                        authority, newExtras, allowParallelSyncs),
+                                minDelayMillis
+                        );
                     }
-                    postScheduleSyncMessage(
-                            new SyncOperation(account.account, account.userId,
-                                    owningUid, owningPackage, reason, source,
-                                    authority, newExtras, allowParallelSyncs),
-                            minDelayMillis
-                    );
                 } else if (targetSyncState == AuthorityInfo.UNDEFINED
                         || targetSyncState == isSyncable) {
                     if (isLoggable) {
@@ -1085,10 +1103,6 @@
         }
     }
 
-    private int computeSyncable(Account account, int userId, String authority) {
-        return computeSyncable(account, userId, authority, true);
-    }
-
     public int computeSyncable(Account account, int userId, String authority,
             boolean checkAccountAccess) {
         final int status = getIsSyncable(account, userId, authority);
@@ -1198,7 +1212,7 @@
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
-                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
+                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */);
     }
 
     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1706,6 +1720,28 @@
     }
 
     /**
+     * Construct intent used to bind to an adapter.
+     *
+     * @param context Context to create intent for
+     * @param syncAdapterComponent The adapter description
+     * @param userId The user the adapter belongs to
+     *
+     * @return The intent required to bind to the adapter
+     */
+    static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
+            @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
+        final Intent intent = new Intent();
+        intent.setAction("android.content.SyncAdapter");
+        intent.setComponent(syncAdapterComponent);
+        intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+                com.android.internal.R.string.sync_binding_label);
+        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
+                new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
+
+        return intent;
+    }
+
+    /**
      * @hide
      */
     class ActiveSyncContext extends ISyncContext.Stub
@@ -1793,19 +1829,11 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
             }
-            Intent intent = new Intent();
-            intent.setAction("android.content.SyncAdapter");
-            intent.setComponent(serviceComponent);
-            intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
-                    com.android.internal.R.string.sync_binding_label);
-            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
-                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,
-                    null, new UserHandle(userId)));
+            Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
+
             mBound = true;
             final boolean bindResult = mContext.bindServiceAsUser(intent, this,
-                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
-                            | Context.BIND_ALLOW_OOM_MANAGEMENT,
-                    new UserHandle(mSyncOperation.target.userId));
+                    SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
             mLogger.log("bindService() returned=", mBound, " for ", this);
             if (!bindResult) {
                 mBound = false;
@@ -2528,6 +2556,92 @@
         }
     }
 
+    interface OnReadyCallback {
+        void onReady();
+    }
+
+    static void sendOnUnsyncableAccount(@NonNull Context context,
+            @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+            @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
+        OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
+                onReadyCallback);
+
+        boolean isBound = context.bindServiceAsUser(
+                getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
+                connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
+
+        if (isBound) {
+            // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
+            (new Handler(Looper.getMainLooper())).postDelayed(
+                    () -> context.unbindService(connection),
+                    OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
+        } else {
+                /*
+                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+                 * there the service cannot be bound, assume the default behavior.
+                 */
+            connection.onReady();
+        }
+    }
+
+
+    /**
+     * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
+     *
+     * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
+     */
+    private static class OnUnsyncableAccountCheck implements ServiceConnection {
+        static final long SERVICE_BOUND_TIME_MILLIS = 5000;
+
+        private final @NonNull OnReadyCallback mOnReadyCallback;
+        private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+                mSyncAdapterInfo;
+
+        OnUnsyncableAccountCheck(
+                @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+                @NonNull OnReadyCallback onReadyCallback) {
+            mSyncAdapterInfo = syncAdapterInfo;
+            mOnReadyCallback = onReadyCallback;
+        }
+
+        private void onReady() {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mOnReadyCallback.onReady();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+
+            try {
+                adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
+                    @Override
+                    public void onUnsyncableAccountDone(boolean isReady) {
+                        if (isReady) {
+                            onReady();
+                        }
+                    }
+                });
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
+                /*
+                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+                 * there is a crash in the implementation, assume the default behavior.
+                 */
+                onReady();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // Wait until the service connects again
+        }
+    }
+
     /**
      * A helper object to keep track of the time we have spent syncing since the last boot
      */
@@ -3199,7 +3313,7 @@
                 return SYNC_OP_STATE_INVALID;
             }
             // Drop this sync request if it isn't syncable.
-            state = computeSyncable(target.account, target.userId, target.provider);
+            state = computeSyncable(target.account, target.userId, target.provider, true);
             if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: "
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 6da783c..a24a4ac 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -1052,13 +1052,18 @@
             final ArraySet<JobStatus> jobs = mJobs.get(uid);
             final int sourceUid = job.getSourceUid();
             final ArraySet<JobStatus> jobsForSourceUid = mJobsPerSourceUid.get(sourceUid);
-            boolean didRemove = jobs != null && jobs.remove(job) && jobsForSourceUid.remove(job);
-            if (didRemove) {
-                if (jobs.size() == 0) {
-                    // no more jobs for this uid; let the now-empty set object be GC'd.
+            final boolean didRemove = jobs != null && jobs.remove(job);
+            final boolean sourceRemove = jobsForSourceUid != null && jobsForSourceUid.remove(job);
+            if (didRemove != sourceRemove) {
+                Slog.wtf(TAG, "Job presence mismatch; caller=" + didRemove
+                        + " source=" + sourceRemove);
+            }
+            if (didRemove || sourceRemove) {
+                // no more jobs for this uid?  let the now-empty set objects be GC'd.
+                if (jobs != null && jobs.size() == 0) {
                     mJobs.remove(uid);
                 }
-                if (jobsForSourceUid.size() == 0) {
+                if (jobsForSourceUid != null && jobsForSourceUid.size() == 0) {
                     mJobsPerSourceUid.remove(sourceUid);
                 }
                 return true;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 48d275c..55c0f5a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -64,6 +64,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
 import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
@@ -346,7 +347,8 @@
 
     // Current request from underlying location clients.
     private ProviderRequest mProviderRequest = null;
-    // Current list of underlying location clients.
+    // The WorkSource associated with the most recent client request (i.e, most recent call to
+    // setRequest).
     private WorkSource mWorkSource = null;
     // True if gps should be disabled (used to support battery saver mode in settings).
     private boolean mDisableGps = false;
@@ -408,6 +410,7 @@
     private final IAppOpsService mAppOpsService;
     private final IBatteryStats mBatteryStats;
 
+    // Current list of underlying location clients.
     // only modified on handler thread
     private WorkSource mClientSource = new WorkSource();
 
@@ -1345,46 +1348,80 @@
     }
 
     private void updateClientUids(WorkSource source) {
-        // Update work source.
-        WorkSource[] changes = mClientSource.setReturningDiffs(source);
-        if (changes == null) {
+        if (source.equals(mClientSource)) {
             return;
         }
-        WorkSource newWork = changes[0];
-        WorkSource goneWork = changes[1];
 
-        // Update sources that were not previously tracked.
-        if (newWork != null) {
-            int lastuid = -1;
-            for (int i = 0; i < newWork.size(); i++) {
-                try {
-                    int uid = newWork.get(i);
-                    mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
-                            AppOpsManager.OP_GPS, uid, newWork.getName(i));
-                    if (uid != lastuid) {
-                        lastuid = uid;
-                        mBatteryStats.noteStartGps(uid);
-                    }
-                } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException", e);
-                }
-            }
+        // (1) Inform BatteryStats that the list of IDs we're tracking changed.
+        try {
+            mBatteryStats.noteGpsChanged(mClientSource, source);
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException", e);
         }
 
-        // Update sources that are no longer tracked.
-        if (goneWork != null) {
-            int lastuid = -1;
-            for (int i = 0; i < goneWork.size(); i++) {
-                try {
-                    int uid = goneWork.get(i);
-                    mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
-                            AppOpsManager.OP_GPS, uid, goneWork.getName(i));
-                    if (uid != lastuid) {
-                        lastuid = uid;
-                        mBatteryStats.noteStopGps(uid);
+        // (2) Inform AppOps service about the list of changes to UIDs.
+
+        List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source);
+        if (diffs != null) {
+            List<WorkChain> newChains = diffs[0];
+            List<WorkChain> goneChains = diffs[1];
+
+            if (newChains != null) {
+                for (int i = 0; i < newChains.size(); ++i) {
+                    final WorkChain newChain = newChains.get(i);
+                    try {
+                        mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+                                AppOpsManager.OP_GPS, newChain.getAttributionUid(),
+                                newChain.getAttributionTag());
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException", e);
                     }
-                } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException", e);
+                }
+            }
+
+            if (goneChains != null) {
+                for (int i = 0; i < goneChains.size(); i++) {
+                    final WorkChain goneChain = goneChains.get(i);
+                    try {
+                        mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+                                AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
+                                goneChain.getAttributionTag());
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException", e);
+                    }
+                }
+            }
+
+            mClientSource.transferWorkChains(source);
+        }
+
+        // Update the flat UIDs and names list and inform app-ops of all changes.
+        WorkSource[] changes = mClientSource.setReturningDiffs(source);
+        if (changes != null) {
+            WorkSource newWork = changes[0];
+            WorkSource goneWork = changes[1];
+
+            // Update sources that were not previously tracked.
+            if (newWork != null) {
+                for (int i = 0; i < newWork.size(); i++) {
+                    try {
+                        mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+                                AppOpsManager.OP_GPS, newWork.get(i), newWork.getName(i));
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException", e);
+                    }
+                }
+            }
+
+            // Update sources that are no longer tracked.
+            if (goneWork != null) {
+                for (int i = 0; i < goneWork.size(); i++) {
+                    try {
+                        mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+                                AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException", e);
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 824b148..4000a11 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -137,7 +137,7 @@
 
     final MediaController2 createMediaController(SessionToken2 token) {
         mControllerCallback = new ControllerCallback();
-        return new MediaController2(mContext, token, mControllerCallback, mMainExecutor);
+        return new MediaController2(mContext, token, mMainExecutor, mControllerCallback);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c04cdf6..c3f20af 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.annotation.AppIdInt;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Context;
@@ -288,43 +289,44 @@
     public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
             String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
-            @Nullable String seInfo, boolean downgrade, int targetSdkVersion)
-            throws InstallerException {
+            @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
+            @Nullable String profileName) throws InstallerException {
         assertValidInstructionSet(instructionSet);
         if (!checkBeforeRemote()) return;
         try {
             mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
                     dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
-                    targetSdkVersion);
+                    targetSdkVersion, profileName);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
-        if (!checkBeforeRemote()) return false;
-        try {
-            return mInstalld.mergeProfiles(uid, packageName);
-        } catch (Exception e) {
-            throw InstallerException.from(e);
-        }
-    }
-
-    public boolean dumpProfiles(int uid, String packageName, String codePaths)
+    public boolean mergeProfiles(int uid, String packageName, String profileName)
             throws InstallerException {
         if (!checkBeforeRemote()) return false;
         try {
-            return mInstalld.dumpProfiles(uid, packageName, codePaths);
+            return mInstalld.mergeProfiles(uid, packageName, profileName);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public boolean copySystemProfile(String systemProfile, int uid, String packageName)
+    public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath)
             throws InstallerException {
         if (!checkBeforeRemote()) return false;
         try {
-            return mInstalld.copySystemProfile(systemProfile, uid, packageName);
+            return mInstalld.dumpProfiles(uid, packageName, profileName, codePath);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    public boolean copySystemProfile(String systemProfile, int uid, String packageName,
+                String profileName) throws InstallerException {
+        if (!checkBeforeRemote()) return false;
+        try {
+            return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -368,10 +370,10 @@
         }
     }
 
-    public void clearAppProfiles(String packageName) throws InstallerException {
+    public void clearAppProfiles(String packageName, String profileName) throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.clearAppProfiles(packageName);
+            mInstalld.clearAppProfiles(packageName, profileName);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -490,6 +492,16 @@
         }
     }
 
+    public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
+            throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
             String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
         for (int i = 0; i < isas.length; i++) {
@@ -514,21 +526,21 @@
         }
     }
 
-    public boolean createProfileSnapshot(int appId, String packageName, String codePath)
-            throws InstallerException {
+    public boolean createProfileSnapshot(int appId, String packageName, String profileName,
+            String classpath) throws InstallerException {
         if (!checkBeforeRemote()) return false;
         try {
-            return mInstalld.createProfileSnapshot(appId, packageName, codePath);
+            return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
-    public void destroyProfileSnapshot(String packageName, String codePath)
+    public void destroyProfileSnapshot(String packageName, String profileName)
             throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.destroyProfileSnapshot(packageName, codePath);
+            mInstalld.destroyProfileSnapshot(packageName, profileName);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 0395011..5bf38dc 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -261,12 +261,12 @@
                     String instructionSet, int dexoptNeeded, @Nullable String outputPath,
                     int dexFlags, String compilerFilter, @Nullable String volumeUuid,
                     @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
-                    int targetSdkVersion)
+                    int targetSdkVersion, @Nullable String profileName)
                     throws InstallerException {
                 final StringBuilder builder = new StringBuilder();
 
-                // The version. Right now it's 4.
-                builder.append("4 ");
+                // The version. Right now it's 5.
+                builder.append("5 ");
 
                 builder.append("dexopt");
 
@@ -283,6 +283,7 @@
                 encodeParameter(builder, seInfo);
                 encodeParameter(builder, downgrade);
                 encodeParameter(builder, targetSdkVersion);
+                encodeParameter(builder, profileName);
 
                 commands.add(builder.toString());
             }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 324dc5f..cde8cb7 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.dex.ArtManager;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -206,12 +207,14 @@
                 }
             }
 
+            String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+
             final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
                     || packageUseInfo.isUsedByOtherApps(path);
             final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
                 options.getCompilerFilter(), isUsedByOtherApps);
             final boolean profileUpdated = options.isCheckForProfileUpdates() &&
-                isProfileUpdated(pkg, sharedGid, compilerFilter);
+                isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
 
             // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
             // flags.
@@ -220,7 +223,7 @@
             for (String dexCodeIsa : dexCodeInstructionSets) {
                 int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
                         profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
-                        packageStats, options.isDowngrade());
+                        packageStats, options.isDowngrade(), profileName);
                 // The end result is:
                 //  - FAILED if any path failed,
                 //  - PERFORMED if at least one path needed compilation,
@@ -244,7 +247,8 @@
     @GuardedBy("mInstallLock")
     private int dexOptPath(PackageParser.Package pkg, String path, String isa,
             String compilerFilter, boolean profileUpdated, String classLoaderContext,
-            int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) {
+            int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
+            String profileName) {
         int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
                 profileUpdated, downgrade);
         if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -270,7 +274,8 @@
             // primary dex files.
             mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
                     compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
-                    false /* downgrade*/, pkg.applicationInfo.targetSdkVersion);
+                    false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+                    profileName);
 
             if (packageStats != null) {
                 long endTime = System.currentTimeMillis();
@@ -391,7 +396,7 @@
                 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                         /*oatDir*/ null, dexoptFlags,
                         compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
-                        options.isDowngrade(), info.targetSdkVersion);
+                        options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null);
             }
 
             return DEX_OPT_PERFORMED;
@@ -550,14 +555,15 @@
      * current profile and the reference profile will be merged and subsequent calls
      * may return a different result.
      */
-    private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter) {
+    private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+            String compilerFilter) {
         // Check if we are allowed to merge and if the compiler filter is profile guided.
         if (!isProfileGuidedCompilerFilter(compilerFilter)) {
             return false;
         }
         // Merge profiles. It returns whether or not there was an updated in the profile info.
         try {
-            return mInstaller.mergeProfiles(uid, pkg.packageName);
+            return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
         } catch (InstallerException e) {
             Slog.w(TAG, "Failed to merge profiles", e);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5dfd3ae..837a118 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -193,6 +193,7 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
 import android.content.res.Resources;
@@ -337,6 +338,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
+import java.security.DigestException;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -8291,11 +8293,13 @@
     }
 
     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
-            final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException {
+            boolean forceCollect) throws PackageManagerException {
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
                 ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
+        // Note that currently skipVerify skips verification on both base and splits for simplicity.
+        final boolean skipVerify = forceCollect && canSkipFullPackageVerification(pkg);
         if (ps != null && !forceCollect
                 && ps.codePathString.equals(pkg.codePath)
                 && ps.timeStamp == lastModifiedTime
@@ -8321,7 +8325,7 @@
 
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-            PackageParser.collectCertificates(pkg, parseFlags);
+            PackageParser.collectCertificates(pkg, skipVerify);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8415,6 +8419,48 @@
         return scannedPkg;
     }
 
+    /**
+     * Returns if full apk verification can be skipped for the whole package, including the splits.
+     */
+    private boolean canSkipFullPackageVerification(PackageParser.Package pkg) {
+        if (!canSkipFullApkVerification(pkg.baseCodePath)) {
+            return false;
+        }
+        // TODO: Allow base and splits to be verified individually.
+        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+                if (!canSkipFullApkVerification(pkg.splitCodePaths[i])) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns if full apk verification can be skipped, depending on current FSVerity setup and
+     * whether the apk contains signed root hash.  Note that the signer's certificate still needs to
+     * match one in a trusted source, and should be done separately.
+     */
+    private boolean canSkipFullApkVerification(String apkPath) {
+        byte[] rootHashObserved = null;
+        try {
+            rootHashObserved = VerityUtils.generateFsverityRootHash(apkPath);
+            if (rootHashObserved == null) {
+                return false;  // APK does not contain Merkle tree root hash.
+            }
+            synchronized (mInstallLock) {
+                // Returns whether the observed root hash matches what kernel has.
+                mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+                return true;
+            }
+        } catch (InstallerException | IOException | DigestException |
+                NoSuchAlgorithmException e) {
+            Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
+        }
+        return false;
+    }
+
     // Temporary to catch potential issues with refactoring
     private static boolean REFACTOR_DEBUG = true;
     /**
@@ -8626,10 +8672,11 @@
         }
 
         // Verify certificates against what was last scanned. If it is an updated priv app, we will
-        // force the verification. Full apk verification will happen unless apk verity is set up for
-        // the file. In that case, only small part of the apk is verified upfront.
-        collectCertificatesLI(pkgSetting, pkg, parseFlags,
-                PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting));
+        // force re-collecting certificate. Full apk verification will happen unless apk verity is
+        // set up for the file. In that case, only small part of the apk is verified upfront.
+        final boolean forceCollect = PackageManagerServiceUtils.isApkVerificationForced(
+                disabledPkgSetting);
+        collectCertificatesLI(pkgSetting, pkg, forceCollect);
 
         boolean shouldHideSystemApp = false;
         // A new application appeared on /system, but, we already have a copy of
@@ -8870,7 +8917,8 @@
                         // PackageDexOptimizer to prevent this happening on first boot. The issue
                         // is that we don't have a good way to say "do this only once".
                         if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                pkg.applicationInfo.uid, pkg.packageName)) {
+                                pkg.applicationInfo.uid, pkg.packageName,
+                                ArtManager.getProfileName(null))) {
                             Log.e(TAG, "Installer failed to copy system profile!");
                         } else {
                             // Disabled as this causes speed-profile compilation during first boot
@@ -8905,7 +8953,8 @@
                                 // issue is that we don't have a good way to say "do this only
                                 // once".
                                 if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                        pkg.applicationInfo.uid, pkg.packageName)) {
+                                        pkg.applicationInfo.uid, pkg.packageName,
+                                        ArtManager.getProfileName(null))) {
                                     Log.e(TAG, "Failed to copy system profile for stub package!");
                                 } else {
                                     useProfileForDexopt = true;
@@ -9330,14 +9379,7 @@
 
         synchronized (mInstallLock) {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
-            final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-            try {
-                List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly();
-                String codePaths = TextUtils.join(";", allCodePaths);
-                mInstaller.dumpProfiles(sharedGid, packageName, codePaths);
-            } catch (InstallerException e) {
-                Slog.w(TAG, "Failed to dump profiles", e);
-            }
+            mArtManagerService.dumpProfiles(pkg);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
@@ -9413,6 +9455,8 @@
         for (int i = 0; i < childCount; i++) {
             clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
         }
+
+        clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
     }
 
     private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -9485,18 +9529,10 @@
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
-        clearAppProfilesLeafLIF(pkg);
+        mArtManagerService.clearAppProfiles(pkg);
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
-            clearAppProfilesLeafLIF(pkg.childPackages.get(i));
-        }
-    }
-
-    private void clearAppProfilesLeafLIF(PackageParser.Package pkg) {
-        try {
-            mInstaller.clearAppProfiles(pkg.packageName);
-        } catch (InstallerException e) {
-            Slog.w(TAG, String.valueOf(e));
+            mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
         }
     }
 
@@ -16156,7 +16192,6 @@
 
             clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
                     | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-            clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
 
             try {
                 final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
@@ -16295,7 +16330,6 @@
         // Successfully disabled the old package. Now proceed with re-installation
         clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
                 | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-        clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
 
         res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
         pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
@@ -16755,7 +16789,7 @@
             if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                 pkg.setSigningDetails(args.signingDetails);
             } else {
-                PackageParser.collectCertificates(pkg, parseFlags);
+                PackageParser.collectCertificates(pkg, false /* skipVerify */);
             }
         } catch (PackageParserException e) {
             res.setError("Failed collect during installPackageLI", e);
@@ -20368,7 +20402,6 @@
                     }
                     clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
                             | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-                    clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
                     mDexManager.notifyPackageUpdated(pkg.packageName,
                             pkg.baseCodePath, pkg.splitCodePaths);
                 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index bf3eb8e..76c199b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -562,8 +562,7 @@
     private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
             PackageSetting disabledPkgSetting) {
         try {
-            PackageParser.collectCertificates(disabledPkgSetting.pkg,
-                    PackageParser.PARSE_IS_SYSTEM_DIR);
+            PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
             if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures,
                         disabledPkgSetting.signatures.mSigningDetails.signatures)
                     != PackageManager.SIGNATURE_MATCH) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 8178689..e290272 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -23,9 +23,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.dex.ArtManager;
+import android.content.pm.dex.ArtManager.ProfileType;
 import android.content.pm.dex.DexMetadataHelper;
 import android.os.Binder;
-import android.os.Environment;
+import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -33,6 +34,7 @@
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.system.Os;
 import android.util.ArrayMap;
 import android.util.Slog;
 
@@ -44,6 +46,9 @@
 import com.android.server.pm.Installer.InstallerException;
 import java.io.File;
 import java.io.FileNotFoundException;
+import libcore.io.IoUtils;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
 
 /**
  * A system service that provides access to runtime and compiler artifacts.
@@ -63,6 +68,12 @@
     private static boolean DEBUG = false;
     private static boolean DEBUG_IGNORE_PERMISSIONS = false;
 
+    // Package name used to create the profile directory layout when
+    // taking a snapshot of the boot image profile.
+    private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android";
+    // Profile name used for the boot image profile.
+    private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
+
     private final IPackageManager mPackageManager;
     private final Object mInstallLock;
     @GuardedBy("mInstallLock")
@@ -78,20 +89,36 @@
     }
 
     @Override
-    public void snapshotRuntimeProfile(String packageName, String codePath,
-            ISnapshotRuntimeProfileCallback callback) {
+    public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
+            @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) {
         // Sanity checks on the arguments.
-        Preconditions.checkStringNotEmpty(packageName);
-        Preconditions.checkStringNotEmpty(codePath);
         Preconditions.checkNotNull(callback);
 
-        // Verify that the caller has the right permissions.
-        checkReadRuntimeProfilePermission();
+        boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
+        if (!bootImageProfile) {
+            Preconditions.checkStringNotEmpty(codePath);
+            Preconditions.checkStringNotEmpty(packageName);
+        }
+
+        // Verify that the caller has the right permissions and that the runtime profiling is
+        // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission.
+        if (!isRuntimeProfilingEnabled(profileType)) {
+            throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
+        }
 
         if (DEBUG) {
             Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
         }
 
+        if (bootImageProfile) {
+            snapshotBootImageProfile(callback);
+        } else {
+            snapshotAppProfile(packageName, codePath, callback);
+        }
+    }
+
+    private void snapshotAppProfile(String packageName, String codePath,
+            ISnapshotRuntimeProfileCallback callback) {
         PackageInfo info = null;
         try {
             // Note that we use the default user 0 to retrieve the package info.
@@ -111,11 +138,13 @@
         }
 
         boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
+        String splitName = null;
         String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
         if (!pathFound && (splitCodePaths != null)) {
-            for (String path : splitCodePaths) {
-                if (path.equals(codePath)) {
+            for (int i = splitCodePaths.length - 1; i >= 0; i--) {
+                if (splitCodePaths[i].equals(codePath)) {
                     pathFound = true;
+                    splitName = info.applicationInfo.splitNames[i];
                     break;
                 }
             }
@@ -126,18 +155,25 @@
         }
 
         // All good, create the profile snapshot.
-        createProfileSnapshot(packageName, codePath, callback, info);
+        int appId = UserHandle.getAppId(info.applicationInfo.uid);
+        if (appId < 0) {
+            postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+            Slog.wtf(TAG, "AppId is -1 for package: " + packageName);
+            return;
+        }
+
+        createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath,
+                appId, callback);
         // Destroy the snapshot, we no longer need it.
-        destroyProfileSnapshot(packageName, codePath);
+        destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName));
     }
 
-    private void createProfileSnapshot(String packageName, String codePath,
-            ISnapshotRuntimeProfileCallback callback, PackageInfo info) {
+    private void createProfileSnapshot(String packageName, String profileName, String classpath,
+            int appId, ISnapshotRuntimeProfileCallback callback) {
         // Ask the installer to snapshot the profile.
         synchronized (mInstallLock) {
             try {
-                if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid),
-                        packageName, codePath)) {
+                if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) {
                     postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
                     return;
                 }
@@ -148,38 +184,64 @@
         }
 
         // Open the snapshot and invoke the callback.
-        File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath);
-        ParcelFileDescriptor fd;
+        File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName);
+
+        ParcelFileDescriptor fd = null;
         try {
             fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
             postSuccess(packageName, fd, callback);
         } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + codePath, e);
+            Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
+                    + snapshotProfile, e);
             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+        } finally {
+            IoUtils.closeQuietly(fd);
         }
     }
 
-    private void destroyProfileSnapshot(String packageName, String codePath) {
+    private void destroyProfileSnapshot(String packageName, String profileName) {
         if (DEBUG) {
-            Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath);
+            Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName);
         }
 
         synchronized (mInstallLock) {
             try {
-                mInstaller.destroyProfileSnapshot(packageName, codePath);
+                mInstaller.destroyProfileSnapshot(packageName, profileName);
             } catch (InstallerException e) {
                 Slog.e(TAG, "Failed to destroy profile snapshot for " +
-                    packageName + ":" + codePath, e);
+                    packageName + ":" + profileName, e);
             }
         }
     }
 
     @Override
-    public boolean isRuntimeProfilingEnabled() {
+    public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
         // Verify that the caller has the right permissions.
         checkReadRuntimeProfilePermission();
 
-        return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+        switch (profileType) {
+            case ArtManager.PROFILE_APPS :
+                return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+            case ArtManager.PROFILE_BOOT_IMAGE:
+                return (Build.IS_USERDEBUG || Build.IS_ENG) &&
+                        SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
+                        SystemProperties.getBoolean("dalvik.vm.profilebootimage", false);
+            default:
+                throw new IllegalArgumentException("Invalid profile type:" + profileType);
+        }
+    }
+
+    private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) {
+        // Combine the profiles for boot classpath and system server classpath.
+        // This avoids having yet another type of profiles and simplifies the processing.
+        String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"),
+                Os.getenv("SYSTEMSERVERCLASSPATH"));
+
+        // Create the snapshot.
+        createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath,
+                /*appId*/ -1, callback);
+        // Destroy the snapshot, we no longer need it.
+        destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME);
     }
 
     /**
@@ -284,6 +346,40 @@
     }
 
     /**
+     * Clear the profiles for the given package.
+     */
+    public void clearAppProfiles(PackageParser.Package pkg) {
+        try {
+            ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+            for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+                String profileName = packageProfileNames.valueAt(i);
+                mInstaller.clearAppProfiles(pkg.packageName, profileName);
+            }
+        } catch (InstallerException e) {
+            Slog.w(TAG, String.valueOf(e));
+        }
+    }
+
+    /**
+     * Dumps the profiles for the given package.
+     */
+    public void dumpProfiles(PackageParser.Package pkg) {
+        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+        try {
+            ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+            for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+                String codePath = packageProfileNames.keyAt(i);
+                String profileName = packageProfileNames.valueAt(i);
+                synchronized (mInstallLock) {
+                    mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+                }
+            }
+        } catch (InstallerException e) {
+            Slog.w(TAG, "Failed to dump profiles", e);
+        }
+    }
+
+    /**
      * Build the profiles names for all the package code paths (excluding resource only paths).
      * Return the map [code path -> profile name].
      */
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cf36166..db83158 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3763,12 +3763,8 @@
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.UID_STRING, UserHandle.formatUid(uid));
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_ACTIVE, state.mActive);
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
-                if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
-                    proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_PROCESS_STATE_UNKNOWN, true);
-                } else {
-                    proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
-                            ActivityManager.processStateAmToProto(state.mProcState));
-                }
+                proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
+                        ActivityManager.processStateAmToProto(state.mProcState));
                 proto.end(uIDToken);
             }
 
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 3908df4..d2d0e60 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -77,6 +77,14 @@
     }
 
     /**
+     * {@see ApkSignatureVerifier#generateFsverityRootHash(String)}.
+     */
+    public static byte[] generateFsverityRootHash(@NonNull String apkPath)
+            throws NoSuchAlgorithmException, DigestException, IOException {
+        return ApkSignatureVerifier.generateFsverityRootHash(apkPath);
+    }
+
+    /**
      * Returns a {@code SharedMemory} that contains Merkle tree and fsverity headers for the given
      * apk, in the form that can immediately be used for fsverity setup.
      */
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index baea964..faafb39 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -706,6 +706,8 @@
         enforceCallingPermission();
         if (DEBUG) Slog.d(TAG, "learned that statsdReady");
         sayHiToStatsd(); // tell statsd that we're ready too and link to it
+        mContext.sendBroadcast(new Intent(StatsManager.ACTION_STATSD_STARTED),
+                android.Manifest.permission.DUMP);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ba5156b..1cfa956 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -238,15 +238,6 @@
         return mWin.isAnimating();
     }
 
-    /**
-     * Is this window currently waiting to run an opening animation?
-     */
-    boolean isWaitingForOpening() {
-        return mService.mAppTransition.isTransitionSet()
-                && (mWin.mAppToken != null && mWin.mAppToken.isHidden())
-                && mService.mOpeningApps.contains(mWin.mAppToken);
-    }
-
     void cancelExitAnimationForNextAnimationLocked() {
         if (DEBUG_ANIM) Slog.d(TAG,
                 "cancelExitAnimationForNextAnimationLocked: " + mWin);
@@ -1057,17 +1048,6 @@
             return;
         }
 
-        // Do not change surface properties of opening apps if we are waiting for the
-        // transition to be ready. transitionGoodToGo could be not ready even after all
-        // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs()
-        // to get the animation spec. (For example, go into Recents and immediately open
-        // the same app again before the app's surface is destroyed or saved, the surface
-        // is always ready in the whole process.) If we go ahead here, the opening app
-        // will be shown with the full size before the correct animation spec arrives.
-        if (isWaitingForOpening()) {
-            return;
-        }
-
         boolean displayed = false;
 
         computeShownFrameLocked();
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index 9892146..176ae81 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -249,6 +249,15 @@
 
     Tuner::assignHalInterfaces(env, tuner, module.radioModule, halTuner);
     ALOGD("Opened tuner %p", halTuner.get());
+
+    bool isConnected = true;
+    halTuner->getConfiguration([&](Result result, const BandConfig& config) {
+        if (result == Result::OK) isConnected = config.antennaConnected;
+    });
+    if (!isConnected) {
+        tunerCb->antennaStateChange(false);
+    }
+
     return tuner.release();
 }
 
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 42eb873..42c1332 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -352,39 +352,6 @@
     convert::ThrowIfFailed(env, halTuner->cancelAnnouncement());
 }
 
-static jobject nativeGetProgramInformation(JNIEnv *env, jobject obj, jlong nativeContext) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(gContextMutex);
-    auto& ctx = getNativeContext(nativeContext);
-
-    auto halTuner10 = getHalTuner(ctx);
-    auto halTuner11 = ctx.mHalTuner11;
-    if (halTuner10 == nullptr) return nullptr;
-
-    JavaRef<jobject> jInfo;
-    Result halResult;
-    Return<void> hidlResult;
-    if (halTuner11 != nullptr) {
-        hidlResult = halTuner11->getProgramInformation_1_1([&](Result result,
-                const V1_1::ProgramInfo& info) {
-            halResult = result;
-            if (result != Result::OK) return;
-            jInfo = convert::ProgramInfoFromHal(env, info);
-        });
-    } else {
-        hidlResult = halTuner10->getProgramInformation([&](Result result,
-                const V1_0::ProgramInfo& info) {
-            halResult = result;
-            if (result != Result::OK) return;
-            jInfo = convert::ProgramInfoFromHal(env, info, ctx.mBand);
-        });
-    }
-
-    if (jInfo != nullptr) return jInfo.release();
-    convert::ThrowIfFailed(env, hidlResult, halResult);
-    return nullptr;
-}
-
 static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) {
     ALOGV("%s", __func__);
     auto halTuner = getHalTuner11(nativeContext);
@@ -541,21 +508,6 @@
     return jResults.release();
 }
 
-static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
-    ALOGV("%s", __func__);
-    auto halTuner = getHalTuner(nativeContext);
-    if (halTuner == nullptr) return false;
-
-    bool isConnected = false;
-    Result halResult;
-    auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
-        halResult = result;
-        isConnected = config.antennaConnected;
-    });
-    convert::ThrowIfFailed(env, hidlResult, halResult);
-    return isConnected;
-}
-
 static const JNINativeMethod gTunerMethods[] = {
     { "nativeInit", "(IZI)J", (void*)nativeInit },
     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
@@ -570,8 +522,6 @@
     { "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune },
     { "nativeCancel", "(J)V", (void*)nativeCancel },
     { "nativeCancelAnnouncement", "(J)V", (void*)nativeCancelAnnouncement },
-    { "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
-            (void*)nativeGetProgramInformation },
     { "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
     { "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;",
             (void*)nativeGetProgramList },
@@ -580,7 +530,6 @@
     { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
     { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
     { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
-    { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
 };
 
 } // namespace Tuner
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 0cd9ac3..feb7b76 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -10,5 +10,6 @@
     static_libs: [
         "android.hardware.usb-V1.0-java",
         "android.hardware.usb-V1.1-java",
+        "android.hardware.usb.gadget-V1.0-java",
     ],
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 4a7072d..e3e5e3e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -41,13 +41,21 @@
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.gadget.V1_0.GadgetFunction;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_0.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
 import android.os.BatteryManager;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.HwBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
@@ -75,8 +83,10 @@
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Scanner;
 import java.util.Set;
+import java.util.StringJoiner;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -87,22 +97,6 @@
     private static final boolean DEBUG = false;
 
     /**
-     * The persistent property which stores whether adb is enabled or not.
-     * May also contain vendor-specific default functions for testing purposes.
-     */
-    private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
-
-    /**
-     * The non-persistent property which stores the current USB settings.
-     */
-    private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
-
-    /**
-     * The non-persistent property which stores the current USB actual state.
-     */
-    private static final String USB_STATE_PROPERTY = "sys.usb.state";
-
-    /**
      * The SharedPreference setting per user that stores the screen unlocked functions between
      * sessions.
      */
@@ -142,6 +136,10 @@
     private static final int MSG_LOCALE_CHANGED = 11;
     private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12;
     private static final int MSG_UPDATE_SCREEN_LOCK = 13;
+    private static final int MSG_SET_CHARGING_FUNCTIONS = 14;
+    private static final int MSG_SET_FUNCTIONS_TIMEOUT = 15;
+    private static final int MSG_GET_CURRENT_USB_FUNCTIONS = 16;
+    private static final int MSG_FUNCTION_SWITCH_TIMEOUT = 17;
 
     private static final int AUDIO_MODE_SOURCE = 1;
 
@@ -157,9 +155,9 @@
     private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
 
     private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
-
     private UsbHandler mHandler;
     private boolean mBootCompleted;
+    private boolean mSystemReady;
 
     private final Object mLock = new Object();
 
@@ -175,7 +173,6 @@
     private boolean mMidiEnabled;
     private int mMidiCard;
     private int mMidiDevice;
-    private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap;
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
     private final UsbAlsaManager mUsbAlsaManager;
@@ -267,9 +264,27 @@
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
 
-        readOemUsbOverrideConfig();
+        boolean halNotPresent = false;
+        try {
+            IUsbGadget.getService(true);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
+        } catch (NoSuchElementException e) {
+            halNotPresent = true;
+            Slog.i(TAG, "USB GADGET HAL not present in the device", e);
+        }
 
-        mHandler = new UsbHandler(FgThread.get().getLooper());
+        if (halNotPresent) {
+            /**
+             * Initialze the legacy UsbHandler
+             */
+            mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext);
+        } else {
+            /**
+             * Initialize HAL based UsbHandler
+             */
+            mHandler = new UsbHandlerHal(FgThread.get().getLooper());
+        }
 
         if (nativeIsStartRequested()) {
             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
@@ -367,15 +382,6 @@
         massStorageSupported = primary != null && primary.allowMassStorage();
         mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_usbChargingMessage);
-
-        // make sure the ADB_ENABLED setting value matches the current state
-        try {
-            Settings.Global.putInt(mContentResolver,
-                    Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
-        } catch (SecurityException e) {
-            // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
-            Slog.d(TAG, "ADB_ENABLED is restricted.");
-        }
         mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
     }
 
@@ -457,7 +463,7 @@
         return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
     }
 
-    private final class UsbHandler extends Handler {
+    private abstract class UsbHandler extends Handler {
 
         // current USB state
         private boolean mConnected;
@@ -465,78 +471,53 @@
         private boolean mSourcePower;
         private boolean mSinkPower;
         private boolean mConfigured;
-        private boolean mUsbDataUnlocked;
+        protected boolean mUsbDataUnlocked;
         private boolean mAudioAccessoryConnected;
         private boolean mAudioAccessorySupported;
-        private String mCurrentFunctions;
-        private boolean mCurrentFunctionsApplied;
+        protected String mCurrentFunctions;
+        protected boolean mCurrentFunctionsApplied;
         private UsbAccessory mCurrentAccessory;
         private int mUsbNotificationId;
         private boolean mAdbNotificationShown;
         private int mCurrentUser;
         private boolean mUsbCharging;
-        private String mCurrentOemFunctions;
         private boolean mHideUsbNotification;
         private boolean mSupportsAllCombinations;
         private String mScreenUnlockedFunctions = UsbManager.USB_FUNCTION_NONE;
         private boolean mScreenLocked;
+        protected boolean mCurrentUsbFunctionsRequested;
+        protected boolean mCurrentUsbFunctionsReceived;
+
+        /**
+         * The persistent property which stores whether adb is enabled or not.
+         * May also contain vendor-specific default functions for testing purposes.
+         */
+        protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
 
         public UsbHandler(Looper looper) {
             super(looper);
-            try {
-                // Restore default functions.
 
-                mCurrentOemFunctions = SystemProperties.get(UsbDeviceManager.getPersistProp(false),
-                        UsbManager.USB_FUNCTION_NONE);
-                if (isNormalBoot()) {
-                    mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
-                            UsbManager.USB_FUNCTION_NONE);
-                    mCurrentFunctionsApplied = mCurrentFunctions.equals(
-                            SystemProperties.get(USB_STATE_PROPERTY));
-                } else {
-                    mCurrentFunctions = SystemProperties.get(getPersistProp(true),
-                            UsbManager.USB_FUNCTION_NONE);
-                    mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY,
-                            UsbManager.USB_FUNCTION_NONE).equals(
-                            SystemProperties.get(USB_STATE_PROPERTY));
-                }
+            mCurrentUser = ActivityManager.getCurrentUser();
+            mScreenLocked = true;
 
-                mCurrentUser = ActivityManager.getCurrentUser();
-                mScreenLocked = true;
+            /*
+             * Use the normal bootmode persistent prop to maintain state of adb across
+             * all boot modes.
+             */
+            mAdbEnabled = UsbManager.containsFunction(
+                    SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
+                    UsbManager.USB_FUNCTION_ADB);
 
-                /*
-                 * Use the normal bootmode persistent prop to maintain state of adb across
-                 * all boot modes.
-                 */
-                mAdbEnabled = UsbManager.containsFunction(
-                        SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
-                        UsbManager.USB_FUNCTION_ADB);
-
-                /*
-                 * Previous versions can set persist config to mtp/ptp but it does not
-                 * get reset on OTA. Reset the property here instead.
-                 */
-                String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
-                if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)
-                        || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) {
-                    SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
-                            UsbManager.removeFunction(UsbManager.removeFunction(persisted,
-                                    UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
-                }
-
-                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
-                updateState(state);
-
-                // register observer to listen for settings changes
-                mContentResolver.registerContentObserver(
-                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
-                        false, new AdbSettingsObserver());
-
-                // Watch for USB configuration changes
-                mUEventObserver.startObserving(USB_STATE_MATCH);
-                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
-            } catch (Exception e) {
-                Slog.e(TAG, "Error initializing UsbHandler", e);
+            /*
+             * Previous versions can set persist config to mtp/ptp but it does not
+             * get reset on OTA. Reset the property here instead.
+             */
+            String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
+            if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)
+                    || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) {
+                SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
+                        UsbManager.removeFunction(UsbManager.removeFunction(persisted,
+                                UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
             }
         }
 
@@ -562,6 +543,21 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, boolean arg1, boolean arg2) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg1 ? 1 : 0);
+            m.arg2 = (arg2 ? 1 : 0);
+            sendMessage(m);
+        }
+
+        public void sendMessageDelayed(int what, boolean arg, long delayMillis) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg ? 1 : 0);
+            sendMessageDelayed(m, delayMillis);
+        }
+
         public void updateState(String state) {
             int connected, configured;
 
@@ -579,6 +575,7 @@
                 return;
             }
             removeMessages(MSG_UPDATE_STATE);
+            if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
             Message msg = Message.obtain(this, MSG_UPDATE_STATE);
             msg.arg1 = connected;
             msg.arg2 = configured;
@@ -601,28 +598,6 @@
             sendMessageDelayed(msg, UPDATE_DELAY);
         }
 
-        private boolean waitForState(String state) {
-            // wait for the transition to complete.
-            // give up after 1 second.
-            String value = null;
-            for (int i = 0; i < 20; i++) {
-                // State transition is done when sys.usb.state is set to the new configuration
-                value = SystemProperties.get(USB_STATE_PROPERTY);
-                if (state.equals(value)) return true;
-                SystemClock.sleep(50);
-            }
-            Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
-            return false;
-        }
-
-        private void setUsbConfig(String config) {
-            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
-            // set the new configuration
-            // we always set it due to b/23631400, where adbd was getting killed
-            // and not restarted due to property timeouts on some devices
-            SystemProperties.set(USB_CONFIG_PROPERTY, config);
-        }
-
         private void setAdbEnabled(boolean enable) {
             if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
             if (enable != mAdbEnabled) {
@@ -649,114 +624,7 @@
             }
         }
 
-        /**
-         * Evaluates USB function policies and applies the change accordingly.
-         */
-        private void setEnabledFunctions(String functions, boolean forceRestart,
-                boolean usbDataUnlocked) {
-            if (DEBUG) {
-                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
-                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
-            }
-
-            if (usbDataUnlocked != mUsbDataUnlocked) {
-                mUsbDataUnlocked = usbDataUnlocked;
-                updateUsbNotification(false);
-                forceRestart = true;
-            }
-
-            // Try to set the enabled functions.
-            final String oldFunctions = mCurrentFunctions;
-            final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
-            if (trySetEnabledFunctions(functions, forceRestart)) {
-                return;
-            }
-
-            // Didn't work.  Try to revert changes.
-            // We always reapply the policy in case certain constraints changed such as
-            // user restrictions independently of any other new functions we were
-            // trying to activate.
-            if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
-                Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
-                if (trySetEnabledFunctions(oldFunctions, false)) {
-                    return;
-                }
-            }
-
-            // Still didn't work.  Try to restore the default functions.
-            Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
-            if (trySetEnabledFunctions(null, false)) {
-                return;
-            }
-
-            // Now we're desperate.  Ignore the default functions.
-            // Try to get ADB working if enabled.
-            Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
-            if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
-                return;
-            }
-
-            // Ouch.
-            Slog.e(TAG, "Unable to set any USB functions!");
-        }
-
-        private boolean isNormalBoot() {
-            String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
-            return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
-        }
-
-        private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
-            if (functions == null || applyAdbFunction(functions)
-                    .equals(UsbManager.USB_FUNCTION_NONE)) {
-                functions = getChargingFunctions();
-            }
-            functions = applyAdbFunction(functions);
-
-            String oemFunctions = applyOemOverrideFunction(functions);
-
-            if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) {
-                SystemProperties.set(getPersistProp(true), functions);
-            }
-
-            if ((!functions.equals(oemFunctions) &&
-                            !mCurrentOemFunctions.equals(oemFunctions))
-                    || !mCurrentFunctions.equals(functions)
-                    || !mCurrentFunctionsApplied
-                    || forceRestart) {
-                Slog.i(TAG, "Setting USB config to " + functions);
-                mCurrentFunctions = functions;
-                mCurrentOemFunctions = oemFunctions;
-                mCurrentFunctionsApplied = false;
-
-                // Kick the USB stack to close existing connections.
-                setUsbConfig(UsbManager.USB_FUNCTION_NONE);
-
-                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
-                    Slog.e(TAG, "Failed to kick USB config");
-                    return false;
-                }
-
-                // Set the new USB configuration.
-                setUsbConfig(oemFunctions);
-
-                if (mBootCompleted
-                        && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
-                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
-                    // Start up dependent services.
-                    updateUsbStateBroadcastIfNeeded(true);
-                }
-
-                if (!waitForState(oemFunctions)) {
-                    Slog.e(TAG, "Failed to switch USB config to " + functions);
-                    return false;
-                }
-
-                mCurrentFunctionsApplied = true;
-            }
-            return true;
-        }
-
-        private String applyAdbFunction(String functions) {
+        protected String applyAdbFunction(String functions) {
             // Do not pass null pointer to the UsbManager.
             // There isnt a check there.
             if (functions == null) {
@@ -838,7 +706,7 @@
             return false;
         }
 
-        private void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
+        protected void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -956,7 +824,8 @@
                         updateCurrentAccessory();
                     }
                     if (mBootCompleted) {
-                        if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) {
+                        if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)
+                                && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) {
                             // restore defaults when USB is disconnected
                             if (!mScreenLocked
                                     && !UsbManager.USB_FUNCTION_NONE.equals(
@@ -1082,7 +951,7 @@
                         if (!UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)
                                 && (UsbManager.USB_FUNCTION_ADB.equals(mCurrentFunctions)
                                 || (UsbManager.USB_FUNCTION_MTP.equals(mCurrentFunctions)
-                                        && !mUsbDataUnlocked))) {
+                                && !mUsbDataUnlocked))) {
                             // Set the screen unlocked functions if current function is charging.
                             setScreenUnlockedFunctions();
                         }
@@ -1097,9 +966,8 @@
                             mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart);
                     break;
                 case MSG_SYSTEM_READY:
-                    updateUsbNotification(false);
-                    updateAdbNotification(false);
-                    updateUsbFunctions();
+                    mSystemReady = true;
+                    finishBoot();
                     break;
                 case MSG_LOCALE_CHANGED:
                     updateAdbNotification(true);
@@ -1107,23 +975,7 @@
                     break;
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
-                    if (mPendingBootBroadcast) {
-                        updateUsbStateBroadcastIfNeeded(false);
-                        mPendingBootBroadcast = false;
-                    }
-
-                    if (!mScreenLocked
-                            && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) {
-                        setScreenUnlockedFunctions();
-                    } else {
-                        setEnabledFunctions(null, false, false);
-                    }
-                    if (mCurrentAccessory != null) {
-                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
-                    }
-                    if (mDebuggingManager != null) {
-                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
-                    }
+                    finishBoot();
                     break;
                 case MSG_USER_SWITCHED: {
                     if (mCurrentUser != msg.arg1) {
@@ -1153,6 +1005,41 @@
             }
         }
 
+        protected void finishBoot() {
+            if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
+                if (mPendingBootBroadcast) {
+                    updateUsbStateBroadcastIfNeeded(false);
+                    mPendingBootBroadcast = false;
+                }
+                if (!mScreenLocked
+                        && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) {
+                    setScreenUnlockedFunctions();
+                } else {
+                    setEnabledFunctions(null, false, false);
+                }
+                if (mCurrentAccessory != null) {
+                    getCurrentSettings().accessoryAttached(mCurrentAccessory);
+                }
+                if (mDebuggingManager != null) {
+                    mDebuggingManager.setAdbEnabled(mAdbEnabled);
+                }
+
+                // make sure the ADB_ENABLED setting value matches the current state
+                try {
+                    Settings.Global.putInt(mContentResolver,
+                            Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
+                } catch (SecurityException e) {
+                    // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't
+                    // be changed.
+                    Slog.d(TAG, "ADB_ENABLED is restricted.");
+                }
+
+                updateUsbNotification(false);
+                updateAdbNotification(false);
+                updateUsbFunctions();
+            }
+        }
+
         private boolean isUsbDataTransferActive() {
             return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
                     || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
@@ -1162,7 +1049,7 @@
             return mCurrentAccessory;
         }
 
-        private void updateUsbNotification(boolean force) {
+        protected void updateUsbNotification(boolean force) {
             if (mNotificationManager == null || !mUseUsbNotification
                     || ("0".equals(SystemProperties.get("persist.charging.notify")))) {
                 return;
@@ -1262,18 +1149,18 @@
                     }
 
                     Notification.Builder builder = new Notification.Builder(mContext, channel)
-                                    .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                                    .setWhen(0)
-                                    .setOngoing(true)
-                                    .setTicker(title)
-                                    .setDefaults(0)  // please be quiet
-                                    .setColor(mContext.getColor(
-                                            com.android.internal.R.color
-                                                    .system_notification_accent_color))
-                                    .setContentTitle(title)
-                                    .setContentText(message)
-                                    .setContentIntent(pi)
-                                    .setVisibility(Notification.VISIBILITY_PUBLIC);
+                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                            .setWhen(0)
+                            .setOngoing(true)
+                            .setTicker(title)
+                            .setDefaults(0)  // please be quiet
+                            .setColor(mContext.getColor(
+                                    com.android.internal.R.color
+                                            .system_notification_accent_color))
+                            .setContentTitle(title)
+                            .setContentText(message)
+                            .setContentIntent(pi)
+                            .setVisibility(Notification.VISIBILITY_PUBLIC);
 
                     if (titleRes
                             == com.android.internal.R.string
@@ -1291,7 +1178,7 @@
             }
         }
 
-        private void updateAdbNotification(boolean force) {
+        protected void updateAdbNotification(boolean force) {
             if (mNotificationManager == null) return;
             final int id = SystemMessage.NOTE_ADB_ACTIVE;
             final int titleRes = com.android.internal.R.string.adb_active_notification_title;
@@ -1343,22 +1230,23 @@
             }
         }
 
-        private String getChargingFunctions() {
-            String func = SystemProperties.get(getPersistProp(true),
-                    UsbManager.USB_FUNCTION_NONE);
+        protected String getChargingFunctions() {
             // if ADB is enabled, reset functions to ADB
             // else enable MTP as usual.
-            if (UsbManager.containsFunction(func, UsbManager.USB_FUNCTION_ADB)) {
+            if (mAdbEnabled) {
                 return UsbManager.USB_FUNCTION_ADB;
             } else {
                 return UsbManager.USB_FUNCTION_MTP;
             }
         }
 
+        public boolean isFunctionEnabled(String function) {
+            return UsbManager.containsFunction(mCurrentFunctions, function);
+        }
+
         public void dump(IndentingPrintWriter pw) {
             pw.println("USB Device State:");
             pw.println("  mCurrentFunctions: " + mCurrentFunctions);
-            pw.println("  mCurrentOemFunctions: " + mCurrentOemFunctions);
             pw.println("  mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
             pw.println("  mScreenUnlockedFunctions: " + mScreenUnlockedFunctions);
             pw.println("  mScreenLocked: " + mScreenLocked);
@@ -1372,6 +1260,7 @@
             pw.println("  mUsbCharging: " + mUsbCharging);
             pw.println("  mHideUsbNotification: " + mHideUsbNotification);
             pw.println("  mAudioAccessoryConnected: " + mAudioAccessoryConnected);
+            pw.println("  mAdbEnabled: " + mAdbEnabled);
 
             try {
                 pw.println("  Kernel state: "
@@ -1382,6 +1271,675 @@
                 pw.println("IOException: " + e);
             }
         }
+
+        /**
+         * Evaluates USB function policies and applies the change accordingly.
+         */
+        protected abstract void setEnabledFunctions(String functions, boolean forceRestart,
+                boolean usbDataUnlocked);
+
+    }
+
+    private final class UsbHandlerLegacy extends UsbHandler {
+        /**
+         * The non-persistent property which stores the current USB settings.
+         */
+        private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
+
+        /**
+         * The non-persistent property which stores the current USB actual state.
+         */
+        private static final String USB_STATE_PROPERTY = "sys.usb.state";
+
+        private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap;
+        private String mCurrentOemFunctions;
+
+        UsbHandlerLegacy(Looper looper, Context context) {
+            super(looper);
+            try {
+                readOemUsbOverrideConfig(context);
+                // Restore default functions.
+                mCurrentOemFunctions = SystemProperties.get(getPersistProp(false),
+                        UsbManager.USB_FUNCTION_NONE);
+                if (isNormalBoot()) {
+                    mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
+                            UsbManager.USB_FUNCTION_NONE);
+                    mCurrentFunctionsApplied = mCurrentFunctions.equals(
+                            SystemProperties.get(USB_STATE_PROPERTY));
+                } else {
+                    mCurrentFunctions = SystemProperties.get(getPersistProp(true),
+                            UsbManager.USB_FUNCTION_NONE);
+                    mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY,
+                            UsbManager.USB_FUNCTION_NONE).equals(
+                            SystemProperties.get(USB_STATE_PROPERTY));
+                }
+                mCurrentUsbFunctionsReceived = true;
+
+                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+                updateState(state);
+
+                // register observer to listen for settings changes
+                mContentResolver.registerContentObserver(
+                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
+                        false, new AdbSettingsObserver());
+
+                // Watch for USB configuration changes
+                mUEventObserver.startObserving(USB_STATE_MATCH);
+                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+            } catch (Exception e) {
+                Slog.e(TAG, "Error initializing UsbHandler", e);
+            }
+        }
+
+        private void readOemUsbOverrideConfig(Context context) {
+            String[] configList = mContext.getResources().getStringArray(
+                    com.android.internal.R.array.config_oemUsbModeOverride);
+
+            if (configList != null) {
+                for (String config : configList) {
+                    String[] items = config.split(":");
+                    if (items.length == 3 || items.length == 4) {
+                        if (mOemModeMap == null) {
+                            mOemModeMap = new HashMap<>();
+                        }
+                        HashMap<String, Pair<String, String>> overrideMap =
+                                mOemModeMap.get(items[0]);
+                        if (overrideMap == null) {
+                            overrideMap = new HashMap<>();
+                            mOemModeMap.put(items[0], overrideMap);
+                        }
+
+                        // Favoring the first combination if duplicate exists
+                        if (!overrideMap.containsKey(items[1])) {
+                            if (items.length == 3) {
+                                overrideMap.put(items[1], new Pair<>(items[2], ""));
+                            } else {
+                                overrideMap.put(items[1], new Pair<>(items[2], items[3]));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private String applyOemOverrideFunction(String usbFunctions) {
+            if ((usbFunctions == null) || (mOemModeMap == null)) {
+                return usbFunctions;
+            }
+
+            String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+            Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);
+
+            Map<String, Pair<String, String>> overridesMap =
+                    mOemModeMap.get(bootMode);
+            // Check to ensure that the oem is not overriding in the normal
+            // boot mode
+            if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT)
+                    || bootMode.equals("unknown"))) {
+                Pair<String, String> overrideFunctions =
+                        overridesMap.get(usbFunctions);
+                if (overrideFunctions != null) {
+                    Slog.d(TAG, "OEM USB override: " + usbFunctions
+                            + " ==> " + overrideFunctions.first
+                            + " persist across reboot "
+                            + overrideFunctions.second);
+                    if (!overrideFunctions.second.equals("")) {
+                        String newFunction;
+                        if (mAdbEnabled) {
+                            newFunction = UsbManager.addFunction(overrideFunctions.second,
+                                    UsbManager.USB_FUNCTION_ADB);
+                        } else {
+                            newFunction = overrideFunctions.second;
+                        }
+                        Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
+                                + getPersistProp(false));
+                        SystemProperties.set(getPersistProp(false),
+                                newFunction);
+                    }
+                    return overrideFunctions.first;
+                } else if (mAdbEnabled) {
+                    String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE,
+                            UsbManager.USB_FUNCTION_ADB);
+                    SystemProperties.set(getPersistProp(false),
+                            newFunction);
+                } else {
+                    SystemProperties.set(getPersistProp(false),
+                            UsbManager.USB_FUNCTION_NONE);
+                }
+            }
+            // return passed in functions as is.
+            return usbFunctions;
+        }
+
+        private boolean waitForState(String state) {
+            // wait for the transition to complete.
+            // give up after 1 second.
+            String value = null;
+            for (int i = 0; i < 20; i++) {
+                // State transition is done when sys.usb.state is set to the new configuration
+                value = SystemProperties.get(USB_STATE_PROPERTY);
+                if (state.equals(value)) return true;
+                SystemClock.sleep(50);
+            }
+            Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
+            return false;
+        }
+
+        private void setUsbConfig(String config) {
+            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
+            /**
+             * set the new configuration
+             * we always set it due to b/23631400, where adbd was getting killed
+             * and not restarted due to property timeouts on some devices
+             */
+            SystemProperties.set(USB_CONFIG_PROPERTY, config);
+        }
+
+        @Override
+        protected void setEnabledFunctions(String functions, boolean forceRestart,
+                boolean usbDataUnlocked) {
+            if (DEBUG) {
+                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+            }
+
+            if (usbDataUnlocked != mUsbDataUnlocked) {
+                mUsbDataUnlocked = usbDataUnlocked;
+                updateUsbNotification(false);
+                forceRestart = true;
+            }
+
+            /**
+             * Try to set the enabled functions.
+             */
+            final String oldFunctions = mCurrentFunctions;
+            final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
+            if (trySetEnabledFunctions(functions, forceRestart)) {
+                return;
+            }
+
+            /**
+             * Didn't work.  Try to revert changes.
+             * We always reapply the policy in case certain constraints changed such as
+             * user restrictions independently of any other new functions we were
+             * trying to activate.
+             */
+            if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
+                Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
+                if (trySetEnabledFunctions(oldFunctions, false)) {
+                    return;
+                }
+            }
+
+            /**
+             * Still didn't work.  Try to restore the default functions.
+             */
+            Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
+            if (trySetEnabledFunctions(null, false)) {
+                return;
+            }
+
+            /**
+             * Now we're desperate.  Ignore the default functions.
+             * Try to get ADB working if enabled.
+             */
+            Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
+            if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
+                return;
+            }
+
+            /**
+             * Ouch.
+             */
+            Slog.e(TAG, "Unable to set any USB functions!");
+        }
+
+        private boolean isNormalBoot() {
+            String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+            return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
+        }
+
+        private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
+            if (functions == null || applyAdbFunction(functions)
+                    .equals(UsbManager.USB_FUNCTION_NONE)) {
+                functions = getChargingFunctions();
+            }
+            functions = applyAdbFunction(functions);
+
+            String oemFunctions = applyOemOverrideFunction(functions);
+
+            if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) {
+                SystemProperties.set(getPersistProp(true), functions);
+            }
+
+            if ((!functions.equals(oemFunctions)
+                    && !mCurrentOemFunctions.equals(oemFunctions))
+                    || !mCurrentFunctions.equals(functions)
+                    || !mCurrentFunctionsApplied
+                    || forceRestart) {
+                Slog.i(TAG, "Setting USB config to " + functions);
+                mCurrentFunctions = functions;
+                mCurrentOemFunctions = oemFunctions;
+                mCurrentFunctionsApplied = false;
+
+                /**
+                 * Kick the USB stack to close existing connections.
+                 */
+                setUsbConfig(UsbManager.USB_FUNCTION_NONE);
+
+                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
+                    Slog.e(TAG, "Failed to kick USB config");
+                    return false;
+                }
+
+                /**
+                 * Set the new USB configuration.
+                 */
+                setUsbConfig(oemFunctions);
+
+                if (mBootCompleted
+                        && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
+                    /**
+                     * Start up dependent services.
+                     */
+                    updateUsbStateBroadcastIfNeeded(true);
+                }
+
+                if (!waitForState(oemFunctions)) {
+                    Slog.e(TAG, "Failed to switch USB config to " + functions);
+                    return false;
+                }
+
+                mCurrentFunctionsApplied = true;
+            }
+            return true;
+        }
+
+        private String getPersistProp(boolean functions) {
+            String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+            String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
+            if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
+                if (functions) {
+                    persistProp = "persist.sys.usb." + bootMode + ".func";
+                } else {
+                    persistProp = "persist.sys.usb." + bootMode + ".config";
+                }
+            }
+            return persistProp;
+        }
+    }
+
+    private final class UsbHandlerHal extends UsbHandler {
+
+        /**
+         * Proxy object for the usb gadget hal daemon.
+         */
+        @GuardedBy("mGadgetProxyLock")
+        private IUsbGadget mGadgetProxy;
+
+        private final Object mGadgetProxyLock = new Object();
+
+        /**
+         * Cookie sent for usb gadget hal death notification.
+         */
+        private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+
+        /**
+         * Keeps track of the latest setCurrentUsbFunctions request number.
+         */
+        private int mCurrentRequest = 0;
+
+        /**
+         * The maximum time for which the UsbDeviceManager would wait once
+         * setCurrentUsbFunctions is called.
+         */
+        private static final int SET_FUNCTIONS_TIMEOUT_MS = 3000;
+
+        /**
+         * Conseration leeway to make sure that the hal callback arrives before
+         * SET_FUNCTIONS_TIMEOUT_MS expires. If the callback does not arrive
+         * within SET_FUNCTIONS_TIMEOUT_MS, UsbDeviceManager retries enabling
+         * default functions.
+         */
+        private static final int SET_FUNCTIONS_LEEWAY_MS = 500;
+
+        /**
+         * While switching functions, a disconnect is excpect as the usb gadget
+         * us torn down and brought back up. Wait for SET_FUNCTIONS_TIMEOUT_MS +
+         * ENUMERATION_TIME_OUT_MS before switching back to default fumctions when
+         * switching functions.
+         */
+        private static final int ENUMERATION_TIME_OUT_MS = 2000;
+
+        /**
+         * Command to start native service.
+         */
+        protected static final String CTL_START = "ctl.start";
+
+        /**
+         * Command to start native service.
+         */
+        protected static final String CTL_STOP = "ctl.stop";
+
+        /**
+         * Adb natvie daemon
+         */
+        protected static final String ADBD = "adbd";
+
+
+        UsbHandlerHal(Looper looper) {
+            super(looper);
+            try {
+                ServiceNotification serviceNotification = new ServiceNotification();
+
+                boolean ret = IServiceManager.getService()
+                        .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+                                "", serviceNotification);
+                if (!ret) {
+                    Slog.e(TAG, "Failed to register usb gadget service start notification");
+                    return;
+                }
+
+                synchronized (mGadgetProxyLock) {
+                    mGadgetProxy = IUsbGadget.getService(true);
+                    mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
+                            USB_GADGET_HAL_DEATH_COOKIE);
+                    mCurrentFunctions = UsbManager.USB_FUNCTION_NONE;
+                    mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+                    mCurrentUsbFunctionsRequested = true;
+                }
+                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+                updateState(state);
+
+                /**
+                 * Register observer to listen for settings changes.
+                 */
+                mContentResolver.registerContentObserver(
+                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
+                        false, new AdbSettingsObserver());
+
+                /**
+                 * Watch for USB configuration changes.
+                 */
+                mUEventObserver.startObserving(USB_STATE_MATCH);
+                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+            } catch (NoSuchElementException e) {
+                Slog.e(TAG, "Usb gadget hal not found", e);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Usb Gadget hal not responding", e);
+            } catch (Exception e) {
+                Slog.e(TAG, "Error initializing UsbHandler", e);
+            }
+        }
+
+
+        final class UsbGadgetDeathRecipient implements HwBinder.DeathRecipient {
+            @Override
+            public void serviceDied(long cookie) {
+                if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+                    Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
+                    synchronized (mGadgetProxyLock) {
+                        mGadgetProxy = null;
+                    }
+                }
+            }
+        }
+
+        final class ServiceNotification extends IServiceNotification.Stub {
+            @Override
+            public void onRegistration(String fqName, String name, boolean preexisting) {
+                Slog.i(TAG, "Usb gadget hal service started " + fqName + " " + name);
+                synchronized (mGadgetProxyLock) {
+                    try {
+                        mGadgetProxy = IUsbGadget.getService();
+                        mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
+                                USB_GADGET_HAL_DEATH_COOKIE);
+                        if (!mCurrentFunctionsApplied) {
+                            setCurrentFunctions(mCurrentFunctions, mUsbDataUnlocked);
+                        }
+                    } catch (NoSuchElementException e) {
+                        Slog.e(TAG, "Usb gadget hal not found", e);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Usb Gadget hal not responding", e);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CHARGING_FUNCTIONS:
+                    setEnabledFunctions(null, false, mUsbDataUnlocked);
+                    break;
+                case MSG_SET_FUNCTIONS_TIMEOUT:
+                    Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+                    if (msg.arg1 != 1) {
+                        setEnabledFunctions(null, false, mUsbDataUnlocked);
+                    }
+                    break;
+                case MSG_GET_CURRENT_USB_FUNCTIONS:
+                    Slog.e(TAG, "prcessing MSG_GET_CURRENT_USB_FUNCTIONS");
+                    mCurrentUsbFunctionsReceived = true;
+
+                    if (mCurrentUsbFunctionsRequested) {
+                        Slog.e(TAG, "updating mCurrentFunctions");
+                        mCurrentFunctions = functionListToString((Long) msg.obj);
+                        Slog.e(TAG,
+                                "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
+                        mCurrentFunctionsApplied = msg.arg1 == 1;
+                    }
+                    finishBoot();
+                    break;
+                case MSG_FUNCTION_SWITCH_TIMEOUT:
+                    /**
+                     * Dont force to default when the configuration is already set to default.
+                     */
+                    if (msg.arg1 != 1) {
+                        setEnabledFunctions(null, !mAdbEnabled, false);
+                    }
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+
+        private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+            int mRequest;
+            long mFunctions;
+            boolean mChargingFunctions;
+
+            UsbGadgetCallback() {
+            }
+
+            UsbGadgetCallback(int request, long functions,
+                    boolean chargingFunctions) {
+                mRequest = request;
+                mFunctions = functions;
+                mChargingFunctions = chargingFunctions;
+            }
+
+            @Override
+            public void setCurrentUsbFunctionsCb(long functions,
+                    int status) {
+                /**
+                 * Callback called for a previous setCurrenUsbFunction
+                 */
+                if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+                        || (mFunctions != functions)) {
+                    return;
+                }
+
+                removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+                Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+                if (status == Status.SUCCESS) {
+                    mCurrentFunctionsApplied = true;
+                } else if (!mChargingFunctions) {
+                    Slog.e(TAG, "Setting default fuctions");
+                    sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
+                }
+            }
+
+            @Override
+            public void getCurrentUsbFunctionsCb(long functions,
+                    int status) {
+                sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+                        status == Status.FUNCTIONS_APPLIED);
+            }
+        }
+
+        private long stringToFunctionList(String config) {
+            long functionsMask = 0;
+            String[] functions = config.split(",");
+            for (int i = 0; i < functions.length; i++) {
+                switch (functions[i]) {
+                    case "none":
+                        functionsMask |= GadgetFunction.NONE;
+                        break;
+                    case "adb":
+                        functionsMask |= GadgetFunction.ADB;
+                        break;
+                    case "mtp":
+                        functionsMask |= GadgetFunction.MTP;
+                        break;
+                    case "ptp":
+                        functionsMask |= GadgetFunction.PTP;
+                        break;
+                    case "midi":
+                        functionsMask |= GadgetFunction.MIDI;
+                        break;
+                    case "accessory":
+                        functionsMask |= GadgetFunction.ACCESSORY;
+                        break;
+                    case "rndis":
+                        functionsMask |= GadgetFunction.RNDIS;
+                        break;
+                }
+            }
+            return functionsMask;
+        }
+
+        private String functionListToString(Long functionList) {
+            StringJoiner functions = new StringJoiner(",");
+            if (functionList == GadgetFunction.NONE) {
+                functions.add("none");
+                return functions.toString();
+            }
+            if ((functionList & GadgetFunction.ADB) != 0) {
+                functions.add("adb");
+            }
+            if ((functionList & GadgetFunction.MTP) != 0) {
+                functions.add("mtp");
+            }
+            if ((functionList & GadgetFunction.PTP) != 0) {
+                functions.add("ptp");
+            }
+            if ((functionList & GadgetFunction.MIDI) != 0) {
+                functions.add("midi");
+            }
+            if ((functionList & GadgetFunction.ACCESSORY) != 0) {
+                functions.add("accessory");
+            }
+            if ((functionList & GadgetFunction.RNDIS) != 0) {
+                functions.add("rndis");
+            }
+            /**
+             * Remove the trailing comma.
+             */
+            return functions.toString();
+        }
+
+
+        private void setUsbConfig(String config, boolean chargingFunctions) {
+            Long functions = stringToFunctionList(config);
+            if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
+            /**
+             * Cancel any ongoing requests, if present.
+             */
+            removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
+            removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+            removeMessages(MSG_SET_CHARGING_FUNCTIONS);
+
+            synchronized (mGadgetProxyLock) {
+                if (mGadgetProxy == null) {
+                    Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+                    return;
+                }
+                try {
+                    if ((functions & GadgetFunction.ADB) != 0) {
+                        /**
+                         * Start adbd if ADB function is included in the configuration.
+                         */
+                        SystemProperties.set(CTL_START, ADBD);
+                    } else {
+                        /**
+                         * Stop adbd otherwise.
+                         */
+                        SystemProperties.set(CTL_STOP, ADBD);
+                    }
+                    UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
+                            functions, chargingFunctions);
+                    mGadgetProxy.setCurrentUsbFunctions(functions, usbGadgetCallback,
+                            SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+                    sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
+                            SET_FUNCTIONS_TIMEOUT_MS);
+                    sendMessageDelayed(MSG_FUNCTION_SWITCH_TIMEOUT, chargingFunctions,
+                            SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
+                    if (DEBUG) Slog.d(TAG, "timeout message queued");
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
+                }
+            }
+        }
+
+        @Override
+        protected void setEnabledFunctions(String functions, boolean forceRestart,
+                boolean usbDataUnlocked) {
+            if (DEBUG) {
+                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+            }
+
+            if (usbDataUnlocked != mUsbDataUnlocked) {
+                mUsbDataUnlocked = usbDataUnlocked;
+                updateUsbNotification(false);
+                forceRestart = true;
+            }
+
+            trySetEnabledFunctions(functions, forceRestart);
+        }
+
+        private void trySetEnabledFunctions(String functions, boolean forceRestart) {
+            boolean chargingFunctions = false;
+
+            if (functions == null || applyAdbFunction(functions)
+                    .equals(UsbManager.USB_FUNCTION_NONE)) {
+                functions = getChargingFunctions();
+                chargingFunctions = true;
+            }
+            functions = applyAdbFunction(functions);
+
+            if (!mCurrentFunctions.equals(functions)
+                    || !mCurrentFunctionsApplied
+                    || forceRestart) {
+                Slog.i(TAG, "Setting USB config to " + functions);
+                mCurrentFunctions = functions;
+                mCurrentFunctionsApplied = false;
+                // set the flag to false as that would be stale value
+                mCurrentUsbFunctionsRequested = false;
+
+                // Set the new USB configuration.
+                setUsbConfig(mCurrentFunctions, chargingFunctions);
+
+                if (mBootCompleted
+                        && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
+                    // Start up dependent services.
+                    updateUsbStateBroadcastIfNeeded(true);
+                }
+            }
+        }
     }
 
     /* returns the currently attached USB accessory */
@@ -1389,7 +1947,11 @@
         return mHandler.getCurrentAccessory();
     }
 
-    /* opens the currently attached USB accessory */
+    /**
+     * opens the currently attached USB accessory.
+     *
+     * @param accessory accessory to be openened.
+     */
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
             UsbUserSettingsManager settings) {
         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
@@ -1406,20 +1968,32 @@
         return nativeOpenAccessory();
     }
 
+    /**
+     * Checks whether the function is present in the USB configuration.
+     *
+     * @param function function to be checked.
+     */
     public boolean isFunctionEnabled(String function) {
-        return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
+        return mHandler.isFunctionEnabled(function);
     }
 
+    /**
+     * Adds function to the current USB configuration.
+     *
+     * @param functions name of the USB function, or null to restore the default function.
+     * @param usbDataUnlocked whether user data is accessible.
+     */
     public void setCurrentFunctions(String functions, boolean usbDataUnlocked) {
         if (DEBUG) {
-            Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
-                    usbDataUnlocked + ")");
+            Slog.d(TAG, "setCurrentFunctions(" + functions + ", "
+                    + usbDataUnlocked + ")");
         }
         mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked);
     }
 
     /**
      * Sets the functions which are set when the screen is unlocked.
+     *
      * @param functions Functions to set.
      */
     public void setScreenUnlockedFunctions(String functions) {
@@ -1429,101 +2003,6 @@
         mHandler.sendMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, functions);
     }
 
-    private void readOemUsbOverrideConfig() {
-        String[] configList = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_oemUsbModeOverride);
-
-        if (configList != null) {
-            for (String config : configList) {
-                String[] items = config.split(":");
-                if (items.length == 3 || items.length == 4) {
-                    if (mOemModeMap == null) {
-                        mOemModeMap = new HashMap<>();
-                    }
-                    HashMap<String, Pair<String, String>> overrideMap
-                            = mOemModeMap.get(items[0]);
-                    if (overrideMap == null) {
-                        overrideMap = new HashMap<>();
-                        mOemModeMap.put(items[0], overrideMap);
-                    }
-
-                    // Favoring the first combination if duplicate exists
-                    if (!overrideMap.containsKey(items[1])) {
-                        if (items.length == 3) {
-                            overrideMap.put(items[1], new Pair<>(items[2], ""));
-                        } else {
-                            overrideMap.put(items[1], new Pair<>(items[2], items[3]));
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private String applyOemOverrideFunction(String usbFunctions) {
-        if ((usbFunctions == null) || (mOemModeMap == null)) {
-            return usbFunctions;
-        }
-
-        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
-        Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);
-
-        Map<String, Pair<String, String>> overridesMap =
-                mOemModeMap.get(bootMode);
-        // Check to ensure that the oem is not overriding in the normal
-        // boot mode
-        if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT) ||
-                bootMode.equals("unknown"))) {
-            Pair<String, String> overrideFunctions =
-                    overridesMap.get(usbFunctions);
-            if (overrideFunctions != null) {
-                Slog.d(TAG, "OEM USB override: " + usbFunctions
-                        + " ==> " + overrideFunctions.first
-                        + " persist across reboot "
-                        + overrideFunctions.second);
-                if (!overrideFunctions.second.equals("")) {
-                    String newFunction;
-                    if (mAdbEnabled) {
-                        newFunction = UsbManager.addFunction(overrideFunctions.second,
-                                UsbManager.USB_FUNCTION_ADB);
-                    } else {
-                        newFunction = overrideFunctions.second;
-                    }
-                    Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
-                            + UsbDeviceManager.getPersistProp(false));
-                    SystemProperties.set(UsbDeviceManager.getPersistProp(false),
-                            newFunction);
-                }
-                return overrideFunctions.first;
-            } else if (mAdbEnabled) {
-                String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE,
-                        UsbManager.USB_FUNCTION_ADB);
-                SystemProperties.set(UsbDeviceManager.getPersistProp(false),
-                        newFunction);
-            } else {
-                SystemProperties.set(UsbDeviceManager.getPersistProp(false),
-                        UsbManager.USB_FUNCTION_NONE);
-            }
-        }
-        // return passed in functions as is.
-        return usbFunctions;
-    }
-
-    public static String getPersistProp(boolean functions) {
-        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
-        String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
-        if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
-            if (functions) {
-                persistProp = "persist.sys.usb." + bootMode + ".func";
-            } else {
-                persistProp = "persist.sys.usb." + bootMode + ".config";
-            }
-        }
-
-        return persistProp;
-    }
-
-
     public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
         if (mDebuggingManager != null) {
             mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 88bae33..a1a6a5a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -110,6 +110,9 @@
     /** Result code of execution with no error. */
     public static final int RESULT_OK = 0;
 
+    /** Result code of an unknown error. */
+    public static final int RESULT_UNKNOWN_ERROR = -1;
+
     /**
      * Callback to receive the result of an eUICC card API.
      *