Merge "Simplify the memory metrics atoms."
diff --git a/Android.bp b/Android.bp
index 9e9faf2..8db952e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -147,9 +147,10 @@
         "core/java/android/hardware/display/IDisplayManager.aidl",
         "core/java/android/hardware/display/IDisplayManagerCallback.aidl",
         "core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
+        "core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
+        "core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl",
         "core/java/android/hardware/fingerprint/IFingerprintService.aidl",
         "core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl",
-        "core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
         "core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl",
         "core/java/android/hardware/hdmi/IHdmiControlCallback.aidl",
         "core/java/android/hardware/hdmi/IHdmiControlService.aidl",
@@ -630,6 +631,11 @@
         ],
     },
 
+    // See comment on framework-oahl-backward-compatibility module below
+    exclude_srcs: [
+        "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
+    ],
+
     no_framework_libs: true,
     libs: [
         "conscrypt",
@@ -665,6 +671,18 @@
     ],
 }
 
+// A temporary build target that is conditionally included on the bootclasspath if
+// org.apache.http.legacy library has been removed and which provides support for
+// maintaining backwards compatibility for APKs that target pre-P and depend on
+// org.apache.http.legacy classes. This is used iff REMOVE_OAHL_FROM_BCP=true is
+// specified on the build command line.
+java_library {
+    name: "framework-oahl-backward-compatibility",
+    srcs: [
+        "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
+    ],
+}
+
 genrule {
     name: "framework-statslog-gen",
     tools: ["stats-log-api-gen"],
diff --git a/api/current.txt b/api/current.txt
index bef160c..fa896eb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5693,6 +5693,7 @@
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
+    field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
@@ -6377,6 +6378,7 @@
   public class DevicePolicyManager {
     method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
+    method public int addOverrideApn(android.content.ComponentName, android.telephony.data.ApnSetting);
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
     method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
@@ -6423,6 +6425,7 @@
     method public java.util.List<java.lang.String> getMeteredDataDisabled(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
+    method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(android.content.ComponentName);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public java.lang.String getPasswordBlacklistName(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -6474,6 +6477,7 @@
     method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
     method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
+    method public boolean isOverrideApnEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isPrintingEnabled();
     method public boolean isProfileOwnerApp(java.lang.String);
@@ -6489,6 +6493,7 @@
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
+    method public boolean removeOverrideApn(android.content.ComponentName, int);
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -6529,6 +6534,7 @@
     method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean);
     method public void setOrganizationColor(android.content.ComponentName, int);
     method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
+    method public void setOverrideApnsEnabled(android.content.ComponentName, boolean);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
     method public boolean setPasswordBlacklist(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
@@ -6573,6 +6579,7 @@
     method public void transferOwnership(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
+    method public boolean updateOverrideApn(android.content.ComponentName, int, android.telephony.data.ApnSetting);
     method public void wipeData(int);
     method public void wipeDataWithReason(int, java.lang.CharSequence);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -10873,7 +10880,8 @@
     field public android.content.pm.ServiceInfo[] services;
     field public java.lang.String sharedUserId;
     field public int sharedUserLabel;
-    field public android.content.pm.Signature[] signatures;
+    field public deprecated android.content.pm.Signature[] signatures;
+    field public android.content.pm.Signature[][] signingCertificateHistory;
     field public java.lang.String[] splitNames;
     field public int[] splitRevisionCodes;
     field public deprecated int versionCode;
@@ -11076,6 +11084,8 @@
     method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
     method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
+    method public boolean hasSigningCertificate(java.lang.String, byte[], int);
+    method public boolean hasSigningCertificate(int, byte[], int);
     method public abstract boolean hasSystemFeature(java.lang.String);
     method public abstract boolean hasSystemFeature(java.lang.String, int);
     method public abstract boolean isInstantApp();
@@ -11101,6 +11111,8 @@
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
     method public abstract void updateInstantAppCookie(byte[]);
     method public abstract void verifyPendingInstall(int, int);
+    field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
+    field public static final int CERT_INPUT_SHA256 = 1; // 0x1
     field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
     field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
     field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4
@@ -11219,7 +11231,8 @@
     field public static final int GET_RESOLVED_FILTER = 64; // 0x40
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
-    field public static final int GET_SIGNATURES = 64; // 0x40
+    field public static final deprecated int GET_SIGNATURES = 64; // 0x40
+    field public static final int GET_SIGNING_CERTIFICATES = 134217728; // 0x8000000
     field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
@@ -11533,15 +11546,15 @@
 
   public final class AssetManager implements java.lang.AutoCloseable {
     method public void close();
-    method public java.lang.String[] getLocales();
-    method public java.lang.String[] list(java.lang.String) throws java.io.IOException;
-    method public java.io.InputStream open(java.lang.String) throws java.io.IOException;
-    method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
-    method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
-    method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
+    method public final java.lang.String[] getLocales();
+    method public final java.lang.String[] list(java.lang.String) throws java.io.IOException;
+    method public final java.io.InputStream open(java.lang.String) throws java.io.IOException;
+    method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
+    method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
+    method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
+    method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
+    method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
+    method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
     field public static final int ACCESS_BUFFER = 3; // 0x3
     field public static final int ACCESS_RANDOM = 1; // 0x1
     field public static final int ACCESS_STREAMING = 2; // 0x2
@@ -16396,6 +16409,20 @@
 
 package android.hardware.fingerprint {
 
+  public class FingerprintDialog {
+    method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
+    method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
+  }
+
+  public static class FingerprintDialog.Builder {
+    ctor public FingerprintDialog.Builder();
+    method public android.hardware.fingerprint.FingerprintDialog build(android.content.Context);
+    method public android.hardware.fingerprint.FingerprintDialog.Builder setDescription(java.lang.CharSequence);
+    method public android.hardware.fingerprint.FingerprintDialog.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+    method public android.hardware.fingerprint.FingerprintDialog.Builder setSubtitle(java.lang.CharSequence);
+    method public android.hardware.fingerprint.FingerprintDialog.Builder setTitle(java.lang.CharSequence);
+  }
+
   public class FingerprintManager {
     method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
     method public boolean hasEnrolledFingerprints();
@@ -21587,6 +21614,7 @@
     method public android.location.LocationProvider getProvider(java.lang.String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
+    method public boolean isLocationEnabled();
     method public boolean isProviderEnabled(java.lang.String);
     method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
@@ -23213,8 +23241,10 @@
     method public java.lang.String getDefaultUrl();
     method public int getRequestType();
     field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
+    field public static final int REQUEST_TYPE_NONE = 3; // 0x3
     field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
     field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
+    field public static final int REQUEST_TYPE_UPDATE = 4; // 0x4
   }
 
   public static final class MediaDrm.KeyStatus {
@@ -35903,6 +35933,7 @@
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
+    field public static final java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
     field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
@@ -36034,11 +36065,11 @@
     field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
     field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    field public static final java.lang.String LOCATION_MODE = "location_mode";
-    field public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
-    field public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
-    field public static final int LOCATION_MODE_OFF = 0; // 0x0
-    field public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
+    field public static final deprecated java.lang.String LOCATION_MODE = "location_mode";
+    field public static final deprecated int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
+    field public static final deprecated int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
+    field public static final deprecated int LOCATION_MODE_OFF = 0; // 0x0
+    field public static final deprecated int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
     field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
     field public static final deprecated java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
     field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
@@ -36454,6 +36485,7 @@
     field public static final int RESULT_SMS_HANDLED = 1; // 0x1
     field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
     field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
+    field public static final java.lang.String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
     field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
     field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
     field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
@@ -45743,6 +45775,7 @@
     field public static final int KEYCODE_PROG_YELLOW = 185; // 0xb9
     field public static final int KEYCODE_Q = 45; // 0x2d
     field public static final int KEYCODE_R = 46; // 0x2e
+    field public static final int KEYCODE_REFRESH = 285; // 0x11d
     field public static final int KEYCODE_RIGHT_BRACKET = 72; // 0x48
     field public static final int KEYCODE_RO = 217; // 0xd9
     field public static final int KEYCODE_S = 47; // 0x2f
diff --git a/api/system-current.txt b/api/system-current.txt
index f2c057e..14320c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2333,11 +2333,15 @@
     method public deprecated boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
     method public void flushGnssBatch();
     method public int getGnssBatchSize();
+    method public boolean isLocationEnabledForUser(android.os.UserHandle);
+    method public boolean isProviderEnabledForUser(java.lang.String, android.os.UserHandle);
     method public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
     method public deprecated void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
     method public deprecated void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
     method public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper);
     method public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent);
+    method public void setLocationEnabledForUser(boolean, android.os.UserHandle);
+    method public boolean setProviderEnabledForUser(java.lang.String, boolean, android.os.UserHandle);
     method public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
   }
 
@@ -2867,6 +2871,7 @@
   }
 
   public final class IpSecManager {
+    method public void applyTunnelModeTransform(android.net.IpSecManager.IpSecTunnelInterface, int, android.net.IpSecTransform) throws java.io.IOException;
     method public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(java.net.InetAddress, java.net.InetAddress, android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
   }
 
@@ -3898,6 +3903,120 @@
 
 }
 
+package android.security.keystore.recovery {
+
+  public class DecryptionFailedException extends java.security.GeneralSecurityException {
+    ctor public DecryptionFailedException(java.lang.String);
+  }
+
+  public class InternalRecoveryServiceException extends java.security.GeneralSecurityException {
+    ctor public InternalRecoveryServiceException(java.lang.String);
+    ctor public InternalRecoveryServiceException(java.lang.String, java.lang.Throwable);
+  }
+
+  public final class KeyChainProtectionParams implements android.os.Parcelable {
+    method public void clearSecret();
+    method public int describeContents();
+    method public android.security.keystore.recovery.KeyDerivationParams getKeyDerivationParams();
+    method public int getLockScreenUiFormat();
+    method public byte[] getSecret();
+    method public int getUserSecretType();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainProtectionParams> CREATOR;
+    field public static final int TYPE_CUSTOM_PASSWORD = 101; // 0x65
+    field public static final int TYPE_LOCKSCREEN = 100; // 0x64
+    field public static final int UI_FORMAT_PASSWORD = 2; // 0x2
+    field public static final int UI_FORMAT_PATTERN = 3; // 0x3
+    field public static final int UI_FORMAT_PIN = 1; // 0x1
+  }
+
+  public static class KeyChainProtectionParams.Builder {
+    ctor public KeyChainProtectionParams.Builder();
+    method public android.security.keystore.recovery.KeyChainProtectionParams build();
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setKeyDerivationParams(android.security.keystore.recovery.KeyDerivationParams);
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setLockScreenUiFormat(int);
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setSecret(byte[]);
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setUserSecretType(int);
+  }
+
+  public final class KeyChainSnapshot implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getCounterId();
+    method public byte[] getEncryptedRecoveryKeyBlob();
+    method public java.util.List<android.security.keystore.recovery.KeyChainProtectionParams> getKeyChainProtectionParams();
+    method public int getMaxAttempts();
+    method public byte[] getServerParams();
+    method public int getSnapshotVersion();
+    method public byte[] getTrustedHardwarePublicKey();
+    method public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainSnapshot> CREATOR;
+  }
+
+  public final class KeyDerivationParams implements android.os.Parcelable {
+    method public static android.security.keystore.recovery.KeyDerivationParams createSha256Params(byte[]);
+    method public int describeContents();
+    method public int getAlgorithm();
+    method public byte[] getSalt();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ALGORITHM_SHA256 = 1; // 0x1
+    field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyDerivationParams> CREATOR;
+  }
+
+  public class LockScreenRequiredException extends java.security.GeneralSecurityException {
+    ctor public LockScreenRequiredException(java.lang.String);
+  }
+
+  public class RecoveryController {
+    method public byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method public java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
+    method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
+    method public void setServerParams(byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public void setSnapshotCreatedPendingIntent(android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    field public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2; // 0x2
+    field public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; // 0x3
+    field public static final int RECOVERY_STATUS_SYNCED = 0; // 0x0
+    field public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; // 0x1
+  }
+
+  public class RecoverySession implements java.lang.AutoCloseable {
+    method public void close();
+    method public java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method public byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+  }
+
+  public class SessionExpiredException extends java.security.GeneralSecurityException {
+    ctor public SessionExpiredException(java.lang.String);
+  }
+
+  public final class WrappedApplicationKey implements android.os.Parcelable {
+    method public int describeContents();
+    method public byte[] getAccount();
+    method public java.lang.String getAlias();
+    method public byte[] getEncryptedKeyMaterial();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.WrappedApplicationKey> CREATOR;
+  }
+
+  public static class WrappedApplicationKey.Builder {
+    ctor public WrappedApplicationKey.Builder();
+    method public android.security.keystore.recovery.WrappedApplicationKey build();
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(java.lang.String);
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(byte[]);
+  }
+
+}
+
 package android.service.autofill {
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
diff --git a/api/test-current.txt b/api/test-current.txt
index acc819e..254fc15 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -521,6 +521,7 @@
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final java.lang.String LOW_POWER_MODE = "low_power";
     field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ca097d0..ba628b8 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -725,7 +725,7 @@
     if (checkCallingPermission(String16(kPermissionDump))) {
         ConfigKey configKey(ipc->getCallingUid(), key);
         StatsdConfig cfg;
-        if (!cfg.ParseFromArray(&config[0], config.size())) {
+        if (config.empty() || !cfg.ParseFromArray(&config[0], config.size())) {
             *success = false;
             return Status::ok();
         }
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index ef27210..0455f6a 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -112,6 +112,9 @@
 void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                              ProtoOutputStream* protoOutput) {
     flushIfNeededLocked(dumpTimeNs);
+    if (mPastBuckets.empty()) {
+        return;
+    }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 58dd464..e26fe56 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -168,6 +168,9 @@
 void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                                 ProtoOutputStream* protoOutput) {
     flushIfNeededLocked(dumpTimeNs);
+    if (mPastBuckets.empty()) {
+        return;
+    }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 821d8ea4..25c86d0 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -102,6 +102,9 @@
 
 void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                              ProtoOutputStream* protoOutput) {
+    if (mProto->size() <= 0) {
+        return;
+    }
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 17305e3..24dc5b0 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -125,6 +125,9 @@
     VLOG("gauge metric %lld report now...", (long long)mMetricId);
 
     flushIfNeededLocked(dumpTimeNs);
+    if (mPastBuckets.empty()) {
+        return;
+    }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index e985873..ae0c673 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -138,6 +138,9 @@
                                              ProtoOutputStream* protoOutput) {
     VLOG("metric %lld dump report now...", (long long)mMetricId);
     flushIfNeededLocked(dumpTimeNs);
+    if (mPastBuckets.empty()) {
+        return;
+    }
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk
index ed99f3e..e887539 100644
--- a/cmds/uiautomator/instrumentation/Android.mk
+++ b/cmds/uiautomator/instrumentation/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \
     $(call all-java-files-under, ../library/core-src)
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base.stubs
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
 LOCAL_STATIC_JAVA_LIBRARIES := junit
 LOCAL_MODULE := uiautomator-instrumentation
 # TODO: change this to 18 when it's available
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 49d5224..cc68c05 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -699,6 +699,26 @@
     }
 
     @Override
+    public boolean hasSigningCertificate(
+            String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        try {
+            return mPM.hasSigningCertificate(packageName, certificate, type);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public boolean hasSigningCertificate(
+            int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        try {
+            return mPM.hasUidSigningCertificate(uid, certificate, type);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public String[] getPackagesForUid(int uid) {
         try {
             return mPM.getPackagesForUid(uid);
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 024dbcb..553099f 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -167,10 +167,11 @@
      *                             clicking this button, the activity returns
      *                             {@link #RESULT_ALTERNATE}
      *
-     * @return  the intent for launching the activity or null if the credential of the previous
-     * owner can not be verified (e.g. because there was none, or the device does not support
-     * verifying credentials after a factory reset, or device setup has already been completed).
-     *
+     * @return the intent for launching the activity or null if the previous owner of the device
+     *         did not set a credential.
+     * @throws UnsupportedOperationException if the device does not support factory reset
+     *                                       credentials
+     * @throws IllegalStateException if the device has already been provisioned
      * @hide
      */
     @SystemApi
@@ -178,14 +179,14 @@
             CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
         if (!LockPatternUtils.frpCredentialEnabled(mContext)) {
             Log.w(TAG, "Factory reset credentials not supported.");
-            return null;
+            throw new UnsupportedOperationException("not supported on this device");
         }
 
         // Cannot verify credential if the device is provisioned
         if (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
             Log.e(TAG, "Factory reset credential cannot be verified after provisioning.");
-            return null;
+            throw new IllegalStateException("must not be provisioned yet");
         }
 
         // Make sure we have a credential
@@ -194,8 +195,10 @@
                     ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE));
             if (pdb == null) {
                 Log.e(TAG, "No persistent data block service");
-                return null;
+                throw new UnsupportedOperationException("not supported on this device");
             }
+            // The following will throw an UnsupportedOperationException if the device does not
+            // support factory reset credentials (or something went wrong retrieving it).
             if (!pdb.hasFrpCredentialHandle()) {
                 Log.i(TAG, "The persistent data block does not have a factory reset credential.");
                 return null;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2e3b8af..d6fddfc 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4130,7 +4130,7 @@
             final Bundle ex = mN.extras;
             updateBackgroundColor(contentView);
             bindNotificationHeader(contentView, p.ambient, p.headerTextSecondary);
-            bindLargeIcon(contentView, p.hideLargeIcon, p.alwaysShowReply);
+            bindLargeIcon(contentView, p.hideLargeIcon || p.ambient, p.alwaysShowReply);
             boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
             if (p.title != null) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index c06ad3f..30f2697 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -32,8 +32,6 @@
 
 import com.android.internal.util.Preconditions;
 
-import com.android.internal.util.Preconditions;
-
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParser;
@@ -936,7 +934,9 @@
     }
 
     /** @hide */
-    public void toProto(ProtoOutputStream proto) {
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
         proto.write(NotificationChannelProto.ID, mId);
         proto.write(NotificationChannelProto.NAME, mName);
         proto.write(NotificationChannelProto.DESCRIPTION, mDesc);
@@ -959,10 +959,10 @@
         proto.write(NotificationChannelProto.IS_DELETED, mDeleted);
         proto.write(NotificationChannelProto.GROUP, mGroup);
         if (mAudioAttributes != null) {
-            long aToken = proto.start(NotificationChannelProto.AUDIO_ATTRIBUTES);
-            mAudioAttributes.toProto(proto);
-            proto.end(aToken);
+            mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
+
+        proto.end(token);
     }
 }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 5cb7fb7..16166f7 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -298,13 +298,17 @@
     }
 
     /** @hide */
-    public void toProto(ProtoOutputStream proto) {
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
         proto.write(NotificationChannelGroupProto.ID, mId);
         proto.write(NotificationChannelGroupProto.NAME, mName.toString());
         proto.write(NotificationChannelGroupProto.DESCRIPTION, mDescription);
         proto.write(NotificationChannelGroupProto.IS_BLOCKED, mBlocked);
         for (NotificationChannel channel : mChannels) {
-            channel.toProto(proto);
+            channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS);
         }
+
+        proto.end(token);
     }
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 659cf16..49c03ab 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -93,6 +93,18 @@
     private static boolean localLOGV = false;
 
     /**
+     * Intent that is broadcast when an application is blocked or unblocked.
+     *
+     * This broadcast is only sent to the app whose block state has changed.
+     *
+     * Input: nothing
+     * Output: nothing
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_APP_BLOCK_STATE_CHANGED =
+            "android.app.action.APP_BLOCK_STATE_CHANGED";
+
+    /**
      * Intent that is broadcast when a {@link NotificationChannel} is blocked
      * (when {@link NotificationChannel#getImportance()} is {@link #IMPORTANCE_NONE}) or unblocked
      * (when {@link NotificationChannel#getImportance()} is anything other than
@@ -1133,7 +1145,7 @@
         }
 
         /** @hide */
-        public void toProto(ProtoOutputStream proto, long fieldId) {
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
             final long pToken = proto.start(fieldId);
 
             bitwiseToProtoEnum(proto, PolicyProto.PRIORITY_CATEGORIES, priorityCategories);
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index a295c4c..0ed1b08 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -20,6 +20,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.IOException;
 import java.util.Objects;
@@ -124,6 +125,20 @@
         out.writeBoolean(attachAgentDuringBind);
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(ProfilerInfoProto.PROFILE_FILE, profileFile);
+        if (profileFd != null) {
+            proto.write(ProfilerInfoProto.PROFILE_FD, profileFd.getFd());
+        }
+        proto.write(ProfilerInfoProto.SAMPLING_INTERVAL, samplingInterval);
+        proto.write(ProfilerInfoProto.AUTO_STOP_PROFILER, autoStopProfiler);
+        proto.write(ProfilerInfoProto.STREAMING_OUTPUT, streamingOutput);
+        proto.write(ProfilerInfoProto.AGENT, agent);
+        proto.end(token);
+    }
+
     public static final Parcelable.Creator<ProfilerInfo> CREATOR =
             new Parcelable.Creator<ProfilerInfo>() {
                 @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bad19e3..52870b3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -68,6 +68,7 @@
 import android.security.keystore.ParcelableKeyGenParameterSpec;
 import android.service.restrictions.RestrictionsReceiver;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -9298,4 +9299,138 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Called by device owner to add an override APN.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param apnSetting the override APN to insert
+     * @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into
+     *         the database.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     *
+     * @see #setOverrideApnsEnabled(ComponentName, boolean)
+     */
+    public int addOverrideApn(@NonNull ComponentName admin, @NonNull ApnSetting apnSetting) {
+        throwIfParentInstance("addOverrideApn");
+        if (mService != null) {
+            try {
+                return mService.addOverrideApn(admin, apnSetting);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Called by device owner to update an override APN.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param apnId the {@code id} of the override APN to update
+     * @param apnSetting the override APN to update
+     * @return {@code true} if the required override APN is successfully updated,
+     *         {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     *
+     * @see #setOverrideApnsEnabled(ComponentName, boolean)
+     */
+    public boolean updateOverrideApn(@NonNull ComponentName admin, int apnId,
+            @NonNull ApnSetting apnSetting) {
+        throwIfParentInstance("updateOverrideApn");
+        if (mService != null) {
+            try {
+                return mService.updateOverrideApn(admin, apnId, apnSetting);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device owner to remove an override APN.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param apnId the {@code id} of the override APN to remove
+     * @return {@code true} if the required override APN is successfully removed, {@code false}
+     *         otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     *
+     * @see #setOverrideApnsEnabled(ComponentName, boolean)
+     */
+    public boolean removeOverrideApn(@NonNull ComponentName admin, int apnId) {
+        throwIfParentInstance("removeOverrideApn");
+        if (mService != null) {
+            try {
+                return mService.removeOverrideApn(admin, apnId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device owner to get all override APNs inserted by device owner.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @return A list of override APNs inserted by device owner.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     *
+     * @see #setOverrideApnsEnabled(ComponentName, boolean)
+     */
+    public List<ApnSetting> getOverrideApns(@NonNull ComponentName admin) {
+        throwIfParentInstance("getOverrideApns");
+        if (mService != null) {
+            try {
+                return mService.getOverrideApns(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Called by device owner to set if override APNs should be enabled.
+     * <p> Override APNs are separated from other APNs on the device, and can only be inserted or
+     * modified by the device owner. When enabled, only override APNs are in use, any other APNs
+     * are ignored.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param enabled {@code true} if override APNs should be enabled, {@code false} otherwise
+     * @throws SecurityException if {@code admin} is not a device owner.
+     */
+    public void setOverrideApnsEnabled(@NonNull ComponentName admin, boolean enabled) {
+        throwIfParentInstance("setOverrideApnEnabled");
+        if (mService != null) {
+            try {
+                mService.setOverrideApnsEnabled(admin, enabled);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Called by device owner to check if override APNs are currently enabled.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @return {@code true} if override APNs are currently enabled, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     *
+     * @see #setOverrideApnsEnabled(ComponentName, boolean)
+     */
+    public boolean isOverrideApnEnabled(@NonNull ComponentName admin) {
+        throwIfParentInstance("isOverrideApnEnabled");
+        if (mService != null) {
+            try {
+                return mService.isOverrideApnEnabled(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 514dca9..a5ca4cf 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.telephony.data.ApnSetting;
 
 import java.util.List;
 
@@ -403,4 +404,11 @@
 
     List<String> setMeteredDataDisabled(in ComponentName admin, in List<String> packageNames);
     List<String> getMeteredDataDisabled(in ComponentName admin);
+
+    int addOverrideApn(in ComponentName admin, in ApnSetting apnSetting);
+    boolean updateOverrideApn(in ComponentName admin, int apnId, in ApnSetting apnSetting);
+    boolean removeOverrideApn(in ComponentName admin, int apnId);
+    List<ApnSetting> getOverrideApns(in ComponentName admin);
+    void setOverrideApnsEnabled(in ComponentName admin, boolean enabled);
+    boolean isOverrideApnEnabled(in ComponentName admin);
 }
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index ae4a98a..a91aded 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -172,6 +172,12 @@
   public static final int LOG_EVENT_ID_NO_PACKAGES = 49;
   public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50;
 
+    /**
+     * The transport returned {@link BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED}.
+     * @hide
+     */
+    public static final int LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = 51;
+
 
 
 
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 3558e34..266f58d 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -51,6 +51,20 @@
     public static final int AGENT_UNKNOWN = -1004;
     public static final int TRANSPORT_QUOTA_EXCEEDED = -1005;
 
+    /**
+     * Indicates that the transport cannot accept a diff backup for this package.
+     *
+     * <p>Backup manager should clear its state for this package and immediately retry a
+     * non-incremental backup. This might be used if the transport no longer has data for this
+     * package in its backing store.
+     *
+     * <p>This is only valid when backup manager called {@link
+     * #performBackup(PackageInfo, ParcelFileDescriptor, int)} with {@link #FLAG_INCREMENTAL}.
+     *
+     * @hide
+     */
+    public static final int TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = -1006;
+
     // Indicates that operation was initiated by user, not a scheduled one.
     // Transport should ignore its own moratoriums for call with this flag set.
     public static final int FLAG_USER_INITIATED = 1;
@@ -252,6 +266,13 @@
      * set then {@link BackupTransport#FLAG_NON_INCREMENTAL} will be set. Before P neither flag will
      * be set regardless of whether the backup is incremental or not.
      *
+     * <p>If {@link BackupTransport#FLAG_INCREMENTAL} is set and the transport does not have data
+     * for this package in its storage backend then it cannot apply the incremental diff. Thus it
+     * should return {@link BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED} to indicate
+     * that backup manager should delete its state and retry the package as a non-incremental
+     * backup. Before P, or if this is a non-incremental backup, then this return code is equivalent
+     * to {@link BackupTransport#TRANSPORT_ERROR}.
+     *
      * @param packageInfo The identity of the application whose data is being backed up.
      *   This specifically includes the signature list for the package.
      * @param inFd Descriptor of file with data that resulted from invoking the application's
@@ -262,9 +283,11 @@
      * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far),
      *  {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this
      *  specific package, but allow others to proceed),
-     *  {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure), or
-     *  {@link BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
-     *  become lost due to inactivity purge or some other reason and needs re-initializing)
+     *  {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure), {@link
+     *  BackupTransport#TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED} (if the transport cannot accept
+     *  an incremental backup for this package), or {@link
+     *  BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has become lost due to
+     *  inactivity purge or some other reason and needs re-initializing)
      */
     public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags) {
         return performBackup(packageInfo, inFd);
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index f04e907..edb992b 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -106,6 +106,12 @@
          */
         public static final int NOTIFICATION_SEEN = 10;
 
+        /**
+         * An event type denoting a change in App Standby Bucket.
+         * @hide
+         */
+        public static final int STANDBY_BUCKET_CHANGED = 11;
+
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
 
@@ -170,6 +176,13 @@
          */
         public String[] mContentAnnotations;
 
+        /**
+         * The app standby bucket assigned.
+         * Only present for {@link #STANDBY_BUCKET_CHANGED} event types
+         * {@hide}
+         */
+        public int mBucket;
+
         /** @hide */
         @EventFlags
         public int mFlags;
@@ -189,6 +202,7 @@
             mContentType = orig.mContentType;
             mContentAnnotations = orig.mContentAnnotations;
             mFlags = orig.mFlags;
+            mBucket = orig.mBucket;
         }
 
         /**
@@ -399,6 +413,9 @@
                 p.writeString(event.mContentType);
                 p.writeStringArray(event.mContentAnnotations);
                 break;
+            case Event.STANDBY_BUCKET_CHANGED:
+                p.writeInt(event.mBucket);
+                break;
         }
     }
 
@@ -442,6 +459,9 @@
                 eventOut.mContentType = p.readString();
                 eventOut.mContentAnnotations = p.createStringArray();
                 break;
+            case Event.STANDBY_BUCKET_CHANGED:
+                eventOut.mBucket = p.readInt();
+                break;
         }
     }
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 84cbdb4..7bdf72f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
 
@@ -1183,6 +1184,105 @@
         super.dumpBack(pw, prefix);
     }
 
+    /** {@hide} */
+    public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
+        long token = proto.start(fieldId);
+        super.writeToProto(proto, ApplicationInfoProto.PACKAGE);
+        proto.write(ApplicationInfoProto.PERMISSION, permission);
+        proto.write(ApplicationInfoProto.PROCESS_NAME, processName);
+        proto.write(ApplicationInfoProto.UID, uid);
+        proto.write(ApplicationInfoProto.FLAGS, flags);
+        proto.write(ApplicationInfoProto.PRIVATE_FLAGS, privateFlags);
+        proto.write(ApplicationInfoProto.THEME, theme);
+        proto.write(ApplicationInfoProto.SOURCE_DIR, sourceDir);
+        if (!Objects.equals(sourceDir, publicSourceDir)) {
+            proto.write(ApplicationInfoProto.PUBLIC_SOURCE_DIR, publicSourceDir);
+        }
+        if (!ArrayUtils.isEmpty(splitSourceDirs)) {
+            for (String dir : splitSourceDirs) {
+                proto.write(ApplicationInfoProto.SPLIT_SOURCE_DIRS, dir);
+            }
+        }
+        if (!ArrayUtils.isEmpty(splitPublicSourceDirs)
+                && !Arrays.equals(splitSourceDirs, splitPublicSourceDirs)) {
+            for (String dir : splitPublicSourceDirs) {
+                proto.write(ApplicationInfoProto.SPLIT_PUBLIC_SOURCE_DIRS, dir);
+            }
+        }
+        if (resourceDirs != null) {
+            for (String dir : resourceDirs) {
+                proto.write(ApplicationInfoProto.RESOURCE_DIRS, dir);
+            }
+        }
+        proto.write(ApplicationInfoProto.DATA_DIR, dataDir);
+        proto.write(ApplicationInfoProto.CLASS_LOADER_NAME, classLoaderName);
+        if (!ArrayUtils.isEmpty(splitClassLoaderNames)) {
+            for (String name : splitClassLoaderNames) {
+                proto.write(ApplicationInfoProto.SPLIT_CLASS_LOADER_NAMES, name);
+            }
+        }
+
+        long versionToken = proto.start(ApplicationInfoProto.VERSION);
+        proto.write(ApplicationInfoProto.Version.ENABLED, enabled);
+        proto.write(ApplicationInfoProto.Version.MIN_SDK_VERSION, minSdkVersion);
+        proto.write(ApplicationInfoProto.Version.TARGET_SDK_VERSION, targetSdkVersion);
+        proto.write(ApplicationInfoProto.Version.VERSION_CODE, versionCode);
+        proto.write(ApplicationInfoProto.Version.TARGET_SANDBOX_VERSION, targetSandboxVersion);
+        proto.end(versionToken);
+
+        if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
+            long detailToken = proto.start(ApplicationInfoProto.DETAIL);
+            if (className != null) {
+                proto.write(ApplicationInfoProto.Detail.CLASS_NAME, className);
+            }
+            proto.write(ApplicationInfoProto.Detail.TASK_AFFINITY, taskAffinity);
+            proto.write(ApplicationInfoProto.Detail.REQUIRES_SMALLEST_WIDTH_DP,
+                    requiresSmallestWidthDp);
+            proto.write(ApplicationInfoProto.Detail.COMPATIBLE_WIDTH_LIMIT_DP,
+                    compatibleWidthLimitDp);
+            proto.write(ApplicationInfoProto.Detail.LARGEST_WIDTH_LIMIT_DP,
+                    largestWidthLimitDp);
+            if (seInfo != null) {
+                proto.write(ApplicationInfoProto.Detail.SEINFO, seInfo);
+                proto.write(ApplicationInfoProto.Detail.SEINFO_USER, seInfoUser);
+            }
+            proto.write(ApplicationInfoProto.Detail.DEVICE_PROTECTED_DATA_DIR,
+                    deviceProtectedDataDir);
+            proto.write(ApplicationInfoProto.Detail.CREDENTIAL_PROTECTED_DATA_DIR,
+                    credentialProtectedDataDir);
+            if (sharedLibraryFiles != null) {
+                for (String f : sharedLibraryFiles) {
+                    proto.write(ApplicationInfoProto.Detail.SHARED_LIBRARY_FILES, f);
+                }
+            }
+            if (manageSpaceActivityName != null) {
+                proto.write(ApplicationInfoProto.Detail.MANAGE_SPACE_ACTIVITY_NAME,
+                        manageSpaceActivityName);
+            }
+            if (descriptionRes != 0) {
+                proto.write(ApplicationInfoProto.Detail.DESCRIPTION_RES, descriptionRes);
+            }
+            if (uiOptions != 0) {
+                proto.write(ApplicationInfoProto.Detail.UI_OPTIONS, uiOptions);
+            }
+            proto.write(ApplicationInfoProto.Detail.SUPPORTS_RTL, hasRtlSupport());
+            if (fullBackupContent > 0) {
+                proto.write(ApplicationInfoProto.Detail.CONTENT, "@xml/" + fullBackupContent);
+            } else {
+                proto.write(ApplicationInfoProto.Detail.IS_FULL_BACKUP, fullBackupContent == 0);
+            }
+            if (networkSecurityConfigRes != 0) {
+                proto.write(ApplicationInfoProto.Detail.NETWORK_SECURITY_CONFIG_RES,
+                        networkSecurityConfigRes);
+            }
+            if (category != CATEGORY_UNDEFINED) {
+                proto.write(ApplicationInfoProto.Detail.CATEGORY, category);
+            }
+            proto.end(detailToken);
+        }
+        proto.end(token);
+    }
+
     /**
      * @return true if "supportsRtl" has been set to true in the AndroidManifest
      * @hide
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index cce6b84..379bff4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -656,4 +656,8 @@
     void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);
 
     CharSequence getHarmfulAppWarning(String packageName, int userId);
+
+    boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);
+
+    boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
 }
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
new file mode 100644
index 0000000..81041e9
--- /dev/null
+++ b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
@@ -0,0 +1,66 @@
+/*
+ * 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.pm;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+
+/**
+ * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
+ * included by default.
+ *
+ * <p>This is separated out so that it can be conditionally included at build time depending on
+ * whether org.apache.http.legacy is on the bootclasspath or not. In order to include this at
+ * build time, and remove org.apache.http.legacy from the bootclasspath pass
+ * REMOVE_OAHL_FROM_BCP=true on the build command line, otherwise this class will not be included
+ * and the
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
+
+    private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+
+    @Override
+    public void updatePackage(Package pkg) {
+        ArrayList<String> usesLibraries = pkg.usesLibraries;
+        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+
+        // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
+        // to be accessible so this maintains backward compatibility by adding the
+        // org.apache.http.legacy library to those packages.
+        if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
+            boolean apacheHttpLegacyPresent = isLibraryPresent(
+                    usesLibraries, usesOptionalLibraries, APACHE_HTTP_LEGACY);
+            if (!apacheHttpLegacyPresent) {
+                usesLibraries = prefix(usesLibraries, APACHE_HTTP_LEGACY);
+            }
+        }
+
+        pkg.usesLibraries = usesLibraries;
+        pkg.usesOptionalLibraries = usesOptionalLibraries;
+    }
+
+    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
+        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+        return targetSdkVersion <= Build.VERSION_CODES.O_MR1;
+    }
+}
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index 8014c94..9bdb78b 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -16,15 +16,14 @@
 
 package android.content.pm;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.pm.PackageParser.Package;
-import android.os.Build;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Modifies {@link Package} in order to maintain backwards compatibility.
@@ -32,13 +31,60 @@
  * @hide
  */
 @VisibleForTesting
-public class PackageBackwardCompatibility {
+public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
+
+    private static final String TAG = PackageBackwardCompatibility.class.getSimpleName();
 
     private static final String ANDROID_TEST_MOCK = "android.test.mock";
 
     private static final String ANDROID_TEST_RUNNER = "android.test.runner";
 
-    private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+    private static final PackageBackwardCompatibility INSTANCE;
+
+    static {
+        String className = "android.content.pm.OrgApacheHttpLegacyUpdater";
+        Class<? extends PackageSharedLibraryUpdater> clazz;
+        try {
+            clazz = (PackageBackwardCompatibility.class.getClassLoader()
+                    .loadClass(className)
+                    .asSubclass(PackageSharedLibraryUpdater.class));
+        } catch (ClassNotFoundException e) {
+            Log.i(TAG, "Could not find " + className + ", ignoring");
+            clazz = null;
+        }
+
+        boolean hasOrgApacheHttpLegacy = false;
+        final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
+        if (clazz == null) {
+            // Add an updater that will remove any references to org.apache.http.library from the
+            // package so that it does not try and load the library when it is on the
+            // bootclasspath.
+            packageUpdaters.add(new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
+        } else {
+            try {
+                packageUpdaters.add(clazz.getConstructor().newInstance());
+                hasOrgApacheHttpLegacy = true;
+            } catch (ReflectiveOperationException e) {
+                throw new IllegalStateException("Could not create instance of " + className, e);
+            }
+        }
+
+        packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
+
+        PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
+                .toArray(new PackageSharedLibraryUpdater[0]);
+        INSTANCE = new PackageBackwardCompatibility(hasOrgApacheHttpLegacy, updaterArray);
+    }
+
+    private final boolean mRemovedOAHLFromBCP;
+
+    private final PackageSharedLibraryUpdater[] mPackageUpdaters;
+
+    public PackageBackwardCompatibility(boolean removedOAHLFromBCP,
+            PackageSharedLibraryUpdater[] packageUpdaters) {
+        this.mRemovedOAHLFromBCP = removedOAHLFromBCP;
+        this.mPackageUpdaters = packageUpdaters;
+    }
 
     /**
      * Modify the shared libraries in the supplied {@link Package} to maintain backwards
@@ -48,52 +94,74 @@
      */
     @VisibleForTesting
     public static void modifySharedLibraries(Package pkg) {
-        ArrayList<String> usesLibraries = pkg.usesLibraries;
-        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+        INSTANCE.updatePackage(pkg);
+    }
 
-        // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
-        // to be accessible so this maintains backward compatibility by adding the
-        // org.apache.http.legacy library to those packages.
-        if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
-            boolean apacheHttpLegacyPresent = isLibraryPresent(
-                    usesLibraries, usesOptionalLibraries, APACHE_HTTP_LEGACY);
-            if (!apacheHttpLegacyPresent) {
-                usesLibraries = prefix(usesLibraries, APACHE_HTTP_LEGACY);
+    @Override
+    public void updatePackage(Package pkg) {
+
+        for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
+            packageUpdater.updatePackage(pkg);
+        }
+    }
+
+    /**
+     * True if the org.apache.http.legacy has been removed the bootclasspath, false otherwise.
+     */
+    public static boolean removeOAHLFromBCP() {
+        return INSTANCE.mRemovedOAHLFromBCP;
+    }
+
+    /**
+     * Add android.test.mock dependency for any APK that depends on android.test.runner.
+     *
+     * <p>This is needed to maintain backwards compatibility as in previous versions of Android the
+     * android.test.runner library included the classes from android.test.mock which have since
+     * been split out into a separate library.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
+
+        @Override
+        public void updatePackage(Package pkg) {
+            ArrayList<String> usesLibraries = pkg.usesLibraries;
+            ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+
+            // android.test.runner has a dependency on android.test.mock so if android.test.runner
+            // is present but android.test.mock is not then add android.test.mock.
+            boolean androidTestMockPresent = isLibraryPresent(
+                    usesLibraries, usesOptionalLibraries, ANDROID_TEST_MOCK);
+            if (ArrayUtils.contains(usesLibraries, ANDROID_TEST_RUNNER)
+                    && !androidTestMockPresent) {
+                usesLibraries.add(ANDROID_TEST_MOCK);
             }
-        }
+            if (ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_RUNNER)
+                    && !androidTestMockPresent) {
+                usesOptionalLibraries.add(ANDROID_TEST_MOCK);
+            }
 
-        // android.test.runner has a dependency on android.test.mock so if android.test.runner
-        // is present but android.test.mock is not then add android.test.mock.
-        boolean androidTestMockPresent = isLibraryPresent(
-                usesLibraries, usesOptionalLibraries, ANDROID_TEST_MOCK);
-        if (ArrayUtils.contains(usesLibraries, ANDROID_TEST_RUNNER) && !androidTestMockPresent) {
-            usesLibraries.add(ANDROID_TEST_MOCK);
+            pkg.usesLibraries = usesLibraries;
+            pkg.usesOptionalLibraries = usesOptionalLibraries;
         }
-        if (ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_RUNNER)
-                && !androidTestMockPresent) {
-            usesOptionalLibraries.add(ANDROID_TEST_MOCK);
-        }
-
-        pkg.usesLibraries = usesLibraries;
-        pkg.usesOptionalLibraries = usesOptionalLibraries;
     }
 
-    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
-        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
-        return targetSdkVersion <= Build.VERSION_CODES.O_MR1;
-    }
+    /**
+     * Remove any usages of org.apache.http.legacy from the shared library as the library is on the
+     * bootclasspath.
+     */
+    @VisibleForTesting
+    public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary
+            extends PackageSharedLibraryUpdater {
 
-    private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
-            ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
-        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
-                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
-    }
+        private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy";
 
-    private static @NonNull <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
-        if (cur == null) {
-            cur = new ArrayList<>();
+        @Override
+        public void updatePackage(Package pkg) {
+            pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, APACHE_HTTP_LEGACY);
+            pkg.usesOptionalLibraries =
+                    ArrayUtils.remove(pkg.usesOptionalLibraries, APACHE_HTTP_LEGACY);
         }
-        cur.add(0, val);
-        return cur;
     }
 }
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 5a91e94..13ec4fd 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -246,9 +246,44 @@
      * equivalent to being signed with certificates B and A. This means that
      * in case multiple signatures are reported you cannot assume the one at
      * the first position to be the same across updates.
+     *
+     * <strong>Deprecated</strong> This has been replaced by the
+     * {@link PackageInfo#signingCertificateHistory} field, which takes into
+     * account signing certificate rotation.  For backwards compatibility in
+     * the event of signing certificate rotation, this will return the oldest
+     * reported signing certificate, so that an application will appear to
+     * callers as though no rotation occurred.
+     *
+     * @deprecated use {@code signingCertificateHistory} instead
      */
+    @Deprecated
     public Signature[] signatures;
-    
+
+    /**
+     * Array of all signatures arrays read from the package file, potentially
+     * including past signing certificates no longer used after signing
+     * certificate rotation.  Though signing certificate rotation is only
+     * available for apps with a single signing certificate, this provides an
+     * array of arrays so that packages signed with multiple signing
+     * certificates can still return all signers.  This is only filled in if
+     * the flag {@link PackageManager#GET_SIGNING_CERTIFICATES} was set.
+     *
+     * A package must be singed with at least one certificate, which is at
+     * position zero in the array.  An application may be signed by multiple
+     * certificates, which would be in the array at position zero in an
+     * indeterminate order.  A package may also have a history of certificates
+     * due to signing certificate rotation.  In this case, the array will be
+     * populated by a series of single-entry arrays corresponding to a signing
+     * certificate of the package.
+     *
+     * <strong>Note:</strong> Signature ordering is not guaranteed to be
+     * stable which means that a package signed with certificates A and B is
+     * equivalent to being signed with certificates B and A. This means that
+     * in case multiple signatures are reported you cannot assume the one at
+     * the first position will be the same across updates.
+     */
+    public Signature[][] signingCertificateHistory;
+
     /**
      * Application specified preferred configuration
      * {@link android.R.styleable#AndroidManifestUsesConfiguration
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 11830c2..2c0c6ad0 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.res.XmlResourceParser;
-
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -28,6 +27,8 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
+
 import java.text.Collator;
 import java.util.Comparator;
 
@@ -386,6 +387,24 @@
         dest.writeInt(showUserIcon);
     }
 
+    /**
+     * @hide
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        if (name != null) {
+            proto.write(PackageItemInfoProto.NAME, name);
+        }
+        proto.write(PackageItemInfoProto.PACKAGE_NAME, packageName);
+        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
+            proto.write(PackageItemInfoProto.LABEL_RES, labelRes);
+            proto.write(PackageItemInfoProto.NON_LOCALIZED_LABEL, nonLocalizedLabel.toString());
+            proto.write(PackageItemInfoProto.ICON, icon);
+            proto.write(PackageItemInfoProto.BANNER, banner);
+        }
+        proto.end(token);
+    }
+
     protected PackageItemInfo(Parcel source) {
         name = source.readString();
         packageName = source.readString();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b81267a..67c9584 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -133,6 +133,7 @@
             GET_SERVICES,
             GET_SHARED_LIBRARY_FILES,
             GET_SIGNATURES,
+            GET_SIGNING_CERTIFICATES,
             GET_URI_PERMISSION_PATTERNS,
             MATCH_UNINSTALLED_PACKAGES,
             MATCH_DISABLED_COMPONENTS,
@@ -272,7 +273,10 @@
     /**
      * {@link PackageInfo} flag: return information about the
      * signatures included in the package.
+     *
+     * @deprecated use {@code GET_SIGNING_CERTIFICATES} instead
      */
+    @Deprecated
     public static final int GET_SIGNATURES          = 0x00000040;
 
     /**
@@ -488,6 +492,14 @@
     public static final int MATCH_STATIC_SHARED_LIBRARIES = 0x04000000;
 
     /**
+     * {@link PackageInfo} flag: return the signing certificates associated with
+     * this package.  Each entry is a signing certificate that the package
+     * has proven it is authorized to use, usually a past signing certificate from
+     * which it has rotated.
+     */
+    public static final int GET_SIGNING_CERTIFICATES = 0x08000000;
+
+    /**
      * Internal flag used to indicate that a system component has done their
      * homework and verified that they correctly handle packages and components
      * that come and go over time. In particular:
@@ -3781,7 +3793,7 @@
     public abstract int getInstantAppCookieMaxBytes();
 
     /**
-     * @deprecated
+     * deprecated
      * @hide
      */
     public abstract int getInstantAppCookieMaxSize();
@@ -5914,4 +5926,60 @@
     public CharSequence getHarmfulAppWarning(@NonNull String packageName) {
         throw new UnsupportedOperationException("getHarmfulAppWarning not implemented in subclass");
     }
+
+    /** @hide */
+    @IntDef(prefix = { "CERT_INPUT_" }, value = {
+            CERT_INPUT_RAW_X509,
+            CERT_INPUT_SHA256
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CertificateInputType {}
+
+    /**
+     * Certificate input bytes: the input bytes represent an encoded X.509 Certificate which could
+     * be generated using an {@code CertificateFactory}
+     */
+    public static final int CERT_INPUT_RAW_X509 = 0;
+
+    /**
+     * Certificate input bytes: the input bytes represent the SHA256 output of an encoded X.509
+     * Certificate.
+     */
+    public static final int CERT_INPUT_SHA256 = 1;
+
+    /**
+     * Searches the set of signing certificates by which the given package has proven to have been
+     * signed.  This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
+     * since it takes into account the possibility of signing certificate rotation, except in the
+     * case of packages that are signed by multiple certificates, for which signing certificate
+     * rotation is not supported.
+     *
+     * @param packageName package whose signing certificates to check
+     * @param certificate signing certificate for which to search
+     * @param type representation of the {@code certificate}
+     * @return true if this package was or is signed by exactly the certificate {@code certificate}
+     */
+    public boolean hasSigningCertificate(
+            String packageName, byte[] certificate, @CertificateInputType int type) {
+        throw new UnsupportedOperationException(
+                "hasSigningCertificate not implemented in subclass");
+    }
+
+    /**
+     * Searches the set of signing certificates by which the given uid has proven to have been
+     * signed.  This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
+     * since it takes into account the possibility of signing certificate rotation, except in the
+     * case of packages that are signed by multiple certificates, for which signing certificate
+     * rotation is not supported.
+     *
+     * @param uid package whose signing certificates to check
+     * @param certificate signing certificate for which to search
+     * @param type representation of the {@code certificate}
+     * @return true if this package was or is signed by exactly the certificate {@code certificate}
+     */
+    public boolean hasSigningCertificate(
+            int uid, byte[] certificate, @CertificateInputType int type) {
+        throw new UnsupportedOperationException(
+                "hasSigningCertificate not implemented in subclass");
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4efd081..5b5ccf5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -801,13 +801,40 @@
                 }
             }
         }
+        // deprecated method of getting signing certificates
         if ((flags&PackageManager.GET_SIGNATURES) != 0) {
-            if (p.mSigningDetails.hasSignatures()) {
+            if (p.mSigningDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return the oldest
+                // cert so that programmatic checks keep working even if unaware of key rotation.
+                pi.signatures = new Signature[1];
+                pi.signatures[0] = p.mSigningDetails.pastSigningCertificates[0];
+            } else if (p.mSigningDetails.hasSignatures()) {
+                // otherwise keep old behavior
                 int numberOfSigs = p.mSigningDetails.signatures.length;
                 pi.signatures = new Signature[numberOfSigs];
                 System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
             }
         }
+
+        // replacement for GET_SIGNATURES
+        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+            if (p.mSigningDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Convert each
+                // entry to an array
+                int numberOfSigs = p.mSigningDetails.pastSigningCertificates.length;
+                pi.signingCertificateHistory = new Signature[numberOfSigs][];
+                for (int i = 0; i < numberOfSigs; i++) {
+                    pi.signingCertificateHistory[i] =
+                            new Signature[] { p.mSigningDetails.pastSigningCertificates[i] };
+                }
+            } else if (p.mSigningDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = p.mSigningDetails.signatures.length;
+                pi.signingCertificateHistory = new Signature[1][numberOfSigs];
+                System.arraycopy(p.mSigningDetails.signatures, 0,
+                        pi.signingCertificateHistory[0], 0, numberOfSigs);
+            }
+        }
         return pi;
     }
 
@@ -5759,6 +5786,11 @@
             return signatures != null && signatures.length > 0;
         }
 
+        /** Returns true if the signing details have past signing certificates. */
+        public boolean hasPastSigningCertificates() {
+            return pastSigningCertificates != null && pastSigningCertificates.length > 0;
+        }
+
         /** Returns true if the signatures in this and other match exactly. */
         public boolean signaturesMatchExactly(SigningDetails other) {
             return Signature.areExactMatch(this.signatures, other.signatures);
diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
new file mode 100644
index 0000000..49d884c
--- /dev/null
+++ b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
@@ -0,0 +1,55 @@
+/*
+ * 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.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Base for classes that update a {@link PackageParser.Package}'s shared libraries.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public abstract class PackageSharedLibraryUpdater {
+
+    /**
+     * Update the package's shared libraries.
+     *
+     * @param pkg the package to update.
+     */
+    public abstract void updatePackage(PackageParser.Package pkg);
+
+    static @NonNull
+            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
+        if (cur == null) {
+            cur = new ArrayList<>();
+        }
+        cur.add(0, val);
+        return cur;
+    }
+
+    static boolean isLibraryPresent(ArrayList<String> usesLibraries,
+            ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
+        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
+                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
+    }
+}
diff --git a/core/java/android/hardware/fingerprint/FingerprintDialog.java b/core/java/android/hardware/fingerprint/FingerprintDialog.java
new file mode 100644
index 0000000..6b7fab7
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/FingerprintDialog.java
@@ -0,0 +1,293 @@
+/*
+ * 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.hardware.fingerprint;
+
+import static android.Manifest.permission.USE_FINGERPRINT;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.text.TextUtils;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A class that manages a system-provided fingerprint dialog.
+ */
+public class FingerprintDialog {
+
+    /**
+     * @hide
+     */
+    public static final String KEY_TITLE = "title";
+    /**
+     * @hide
+     */
+    public static final String KEY_SUBTITLE = "subtitle";
+    /**
+     * @hide
+     */
+    public static final String KEY_DESCRIPTION = "description";
+    /**
+     * @hide
+     */
+    public static final String KEY_POSITIVE_TEXT = "positive_text";
+    /**
+     * @hide
+     */
+    public static final String KEY_NEGATIVE_TEXT = "negative_text";
+
+    /**
+     * Error/help message will show for this amount of time.
+     * For error messages, the dialog will also be dismissed after this amount of time.
+     * Error messages will be propagated back to the application via AuthenticationCallback
+     * after this amount of time.
+     * @hide
+     */
+    public static final int HIDE_DIALOG_DELAY = 3000; // ms
+    /**
+     * @hide
+     */
+    public static final int DISMISSED_REASON_POSITIVE = 1;
+
+    /**
+     * @hide
+     */
+    public static final int DISMISSED_REASON_NEGATIVE = 2;
+
+    /**
+     * @hide
+     */
+    public static final int DISMISSED_REASON_USER_CANCEL = 3;
+
+    private static class ButtonInfo {
+        Executor executor;
+        DialogInterface.OnClickListener listener;
+        ButtonInfo(Executor ex, DialogInterface.OnClickListener l) {
+            executor = ex;
+            listener = l;
+        }
+    }
+
+    /**
+     * A builder that collects arguments, to be shown on the system-provided fingerprint dialog.
+     **/
+    public static class Builder {
+        private final Bundle bundle;
+        private ButtonInfo positiveButtonInfo;
+        private ButtonInfo negativeButtonInfo;
+
+        /**
+         * Creates a builder for a fingerprint dialog.
+         */
+        public Builder() {
+            bundle = new Bundle();
+        }
+
+        /**
+         * Required: Set the title to display.
+         * @param title
+         * @return
+         */
+        public Builder setTitle(@NonNull CharSequence title) {
+            bundle.putCharSequence(KEY_TITLE, title);
+            return this;
+        }
+
+        /**
+         * Optional: Set the subtitle to display.
+         * @param subtitle
+         * @return
+         */
+        public Builder setSubtitle(@NonNull CharSequence subtitle) {
+            bundle.putCharSequence(KEY_SUBTITLE, subtitle);
+            return this;
+        }
+
+        /**
+         * Optional: Set the description to display.
+         * @param description
+         * @return
+         */
+        public Builder setDescription(@NonNull CharSequence description) {
+            bundle.putCharSequence(KEY_DESCRIPTION, description);
+            return this;
+        }
+
+        /**
+         * Optional: Set the text for the positive button. If not set, the positive button
+         * will not show.
+         * @param text
+         * @return
+         * @hide
+         */
+        public Builder setPositiveButton(@NonNull CharSequence text,
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull DialogInterface.OnClickListener listener) {
+            if (TextUtils.isEmpty(text)) {
+                throw new IllegalArgumentException("Text must be set and non-empty");
+            }
+            if (executor == null) {
+                throw new IllegalArgumentException("Executor must not be null");
+            }
+            if (listener == null) {
+                throw new IllegalArgumentException("Listener must not be null");
+            }
+            bundle.putCharSequence(KEY_POSITIVE_TEXT, text);
+            positiveButtonInfo = new ButtonInfo(executor, listener);
+            return this;
+        }
+
+        /**
+         * Required: Set the text for the negative button.
+         * @param text
+         * @return
+         */
+        public Builder setNegativeButton(@NonNull CharSequence text,
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull DialogInterface.OnClickListener listener) {
+            if (TextUtils.isEmpty(text)) {
+                throw new IllegalArgumentException("Text must be set and non-empty");
+            }
+            if (executor == null) {
+                throw new IllegalArgumentException("Executor must not be null");
+            }
+            if (listener == null) {
+                throw new IllegalArgumentException("Listener must not be null");
+            }
+            bundle.putCharSequence(KEY_NEGATIVE_TEXT, text);
+            negativeButtonInfo = new ButtonInfo(executor, listener);
+            return this;
+        }
+
+        /**
+         * Creates a {@link FingerprintDialog} with the arguments supplied to this builder.
+         * @param context
+         * @return a {@link FingerprintDialog}
+         * @throws IllegalArgumentException if any of the required fields are not set.
+         */
+        public FingerprintDialog build(Context context) {
+            final CharSequence title = bundle.getCharSequence(KEY_TITLE);
+            final CharSequence negative = bundle.getCharSequence(KEY_NEGATIVE_TEXT);
+
+            if (TextUtils.isEmpty(title)) {
+                throw new IllegalArgumentException("Title must be set and non-empty");
+            } else if (TextUtils.isEmpty(negative)) {
+                throw new IllegalArgumentException("Negative text must be set and non-empty");
+            }
+            return new FingerprintDialog(context, bundle, positiveButtonInfo, negativeButtonInfo);
+        }
+    }
+
+    private FingerprintManager mFingerprintManager;
+    private Bundle mBundle;
+    private ButtonInfo mPositiveButtonInfo;
+    private ButtonInfo mNegativeButtonInfo;
+
+    IFingerprintDialogReceiver mDialogReceiver = new IFingerprintDialogReceiver.Stub() {
+        @Override
+        public void onDialogDismissed(int reason) {
+            // Check the reason and invoke OnClickListener(s) if necessary
+            if (reason == DISMISSED_REASON_POSITIVE) {
+                mPositiveButtonInfo.executor.execute(() -> {
+                    mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE);
+                });
+            } else if (reason == DISMISSED_REASON_NEGATIVE) {
+                mNegativeButtonInfo.executor.execute(() -> {
+                    mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+                });
+            }
+        }
+    };
+
+    private FingerprintDialog(Context context, Bundle bundle,
+            ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
+        mBundle = bundle;
+        mPositiveButtonInfo = positiveButtonInfo;
+        mNegativeButtonInfo = negativeButtonInfo;
+        mFingerprintManager = context.getSystemService(FingerprintManager.class);
+    }
+
+    /**
+     * This call warms up the fingerprint hardware, displays a system-provided dialog,
+     * and starts scanning for a fingerprint. It terminates when
+     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
+     * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
+     * dismisses the system-provided dialog, at which point the crypto object becomes invalid.
+     * This operation can be canceled by using the provided cancel object. The application will
+     * receive authentication errors through {@link AuthenticationCallback}, and button events
+     * through the corresponding callback set in
+     * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
+     * It is safe to reuse the {@link FingerprintDialog} object, and calling
+     * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
+     * while an existing authentication attempt is occurring will stop the previous client and
+     * start a new authentication. The interrupted client will receive a cancelled notification
+     * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+     *
+     * @throws IllegalArgumentException if any of the arguments are null
+     *
+     * @param crypto object associated with the call
+     * @param cancel an object that can be used to cancel authentication
+     * @param executor an executor to handle callback events
+     * @param callback an object to receive authentication events
+     */
+    @RequiresPermission(USE_FINGERPRINT)
+    public void authenticate(@NonNull FingerprintManager.CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull FingerprintManager.AuthenticationCallback callback) {
+        mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,
+                callback);
+    }
+
+    /**
+     * This call warms up the fingerprint hardware, displays a system-provided dialog,
+     * and starts scanning for a fingerprint. It terminates when
+     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
+     * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
+     * dismisses the system-provided dialog. This operation can be canceled by using the provided
+     * cancel object. The application will receive authentication errors through
+     * {@link AuthenticationCallback}, and button events through the corresponding callback set in
+     * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
+     * It is safe to reuse the {@link FingerprintDialog} object, and calling
+     * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
+     * while an existing authentication attempt is occurring will stop the previous client and
+     * start a new authentication. The interrupted client will receive a cancelled notification
+     * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+     *
+     * @throws IllegalArgumentException if any of the arguments are null
+     *
+     * @param cancel an object that can be used to cancel authentication
+     * @param executor an executor to handle callback events
+     * @param callback an object to receive authentication events
+     */
+    @RequiresPermission(USE_FINGERPRINT)
+    public void authenticate(@NonNull CancellationSignal cancel,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull FingerprintManager.AuthenticationCallback callback) {
+        mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);
+    }
+}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 987718a..62d92c4 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -16,6 +16,11 @@
 
 package android.hardware.fingerprint;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.USE_FINGERPRINT;
+
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -23,6 +28,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.CancellationSignal.OnCancelListener;
 import android.os.Handler;
@@ -38,14 +44,11 @@
 
 import java.security.Signature;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
 
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.MANAGE_FINGERPRINT;
-import static android.Manifest.permission.USE_FINGERPRINT;
-
 /**
  * A class that coordinates access to the fingerprint hardware.
  */
@@ -204,6 +207,7 @@
     private CryptoObject mCryptoObject;
     private Fingerprint mRemovalFingerprint;
     private Handler mHandler;
+    private Executor mExecutor;
 
     private class OnEnrollCancelListener implements OnCancelListener {
         @Override
@@ -505,7 +509,9 @@
     }
 
     /**
-     * Per-user version
+     * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
+     * CancellationSignal, int, AuthenticationCallback, Handler)}
+     * @param userId the user ID that the fingerprint hardware will authenticate for.
      * @hide
      */
     @RequiresPermission(USE_FINGERPRINT)
@@ -530,7 +536,7 @@
             mCryptoObject = crypto;
             long sessionId = crypto != null ? crypto.getOpId() : 0;
             mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception while authenticating: ", e);
             if (callback != null) {
@@ -543,6 +549,111 @@
     }
 
     /**
+     * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
+     * CancellationSignal, Bundle, Executor, IFingerprintDialogReceiver, AuthenticationCallback)}
+     * @param userId the user ID that the fingerprint hardware will authenticate for.
+     */
+    private void authenticate(int userId,
+            @Nullable CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull Bundle bundle,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull IFingerprintDialogReceiver receiver,
+            @NonNull AuthenticationCallback callback) {
+        mCryptoObject = crypto;
+        if (cancel.isCanceled()) {
+            Log.w(TAG, "authentication already canceled");
+            return;
+        } else {
+            cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
+        }
+
+        if (mService != null) {
+            try {
+                mExecutor = executor;
+                mAuthenticationCallback = callback;
+                final long sessionId = crypto != null ? crypto.getOpId() : 0;
+                mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
+                        0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Remote exception while authenticating", e);
+                mExecutor.execute(() -> {
+                    callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                            getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                });
+            }
+        }
+    }
+
+    /**
+     * Private method, see {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
+     * AuthenticationCallback)}
+     * @param cancel
+     * @param executor
+     * @param callback
+     * @hide
+     */
+    public void authenticate(
+            @NonNull CancellationSignal cancel,
+            @NonNull Bundle bundle,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull IFingerprintDialogReceiver receiver,
+            @NonNull AuthenticationCallback callback) {
+        if (cancel == null) {
+            throw new IllegalArgumentException("Must supply a cancellation signal");
+        }
+        if (bundle == null) {
+            throw new IllegalArgumentException("Must supply a bundle");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must supply an executor");
+        }
+        if (receiver == null) {
+            throw new IllegalArgumentException("Must supply a receiver");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply a calback");
+        }
+        authenticate(UserHandle.myUserId(), null, cancel, bundle, executor, receiver, callback);
+    }
+
+    /**
+     * Private method, see {@link FingerprintDialog#authenticate(CryptoObject, CancellationSignal,
+     * Executor, AuthenticationCallback)}
+     * @param crypto
+     * @param cancel
+     * @param executor
+     * @param callback
+     * @hide
+     */
+    public void authenticate(@NonNull CryptoObject crypto,
+            @NonNull CancellationSignal cancel,
+            @NonNull Bundle bundle,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull IFingerprintDialogReceiver receiver,
+            @NonNull AuthenticationCallback callback) {
+        if (crypto == null) {
+            throw new IllegalArgumentException("Must supply a crypto object");
+        }
+        if (cancel == null) {
+            throw new IllegalArgumentException("Must supply a cancellation signal");
+        }
+        if (bundle == null) {
+            throw new IllegalArgumentException("Must supply a bundle");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must supply an executor");
+        }
+        if (receiver == null) {
+            throw new IllegalArgumentException("Must supply a receiver");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply a calback");
+        }
+        authenticate(UserHandle.myUserId(), crypto, cancel, bundle, executor, receiver, callback);
+    }
+
+    /**
      * Request fingerprint enrollment. This call warms up the fingerprint hardware
      * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
      * {@link EnrollmentCallback} object. It terminates when
@@ -929,64 +1040,64 @@
             }
         }
 
-        private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
-            // emulate HAL 2.1 behavior and send real errMsgId
-            final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR
-                    ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
-            if (mEnrollmentCallback != null) {
-                mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
-                        getErrorString(errMsgId, vendorCode));
-            } else if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
-                        getErrorString(errMsgId, vendorCode));
-            } else if (mRemovalCallback != null) {
-                mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
-                        getErrorString(errMsgId, vendorCode));
-            } else if (mEnumerateCallback != null) {
-                mEnumerateCallback.onEnumerateError(clientErrMsgId,
-                        getErrorString(errMsgId, vendorCode));
-            }
-        }
-
         private void sendEnrollResult(Fingerprint fp, int remaining) {
             if (mEnrollmentCallback != null) {
                 mEnrollmentCallback.onEnrollmentProgress(remaining);
             }
         }
-
-        private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
-            if (mAuthenticationCallback != null) {
-                final AuthenticationResult result =
-                        new AuthenticationResult(mCryptoObject, fp, userId);
-                mAuthenticationCallback.onAuthenticationSucceeded(result);
-            }
-        }
-
-        private void sendAuthenticatedFailed() {
-            if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationFailed();
-            }
-        }
-
-        private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
-            if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
-            }
-            final String msg = getAcquiredString(acquireInfo, vendorCode);
-            if (msg == null) {
-                return;
-            }
-            // emulate HAL 2.1 behavior and send real acquiredInfo
-            final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR
-                    ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo;
-            if (mEnrollmentCallback != null) {
-                mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
-            } else if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
-            }
-        }
     };
 
+    private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
+        if (mAuthenticationCallback != null) {
+            final AuthenticationResult result =
+                    new AuthenticationResult(mCryptoObject, fp, userId);
+            mAuthenticationCallback.onAuthenticationSucceeded(result);
+        }
+    }
+
+    private void sendAuthenticatedFailed() {
+        if (mAuthenticationCallback != null) {
+            mAuthenticationCallback.onAuthenticationFailed();
+        }
+    }
+
+    private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
+        if (mAuthenticationCallback != null) {
+            mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
+        }
+        final String msg = getAcquiredString(acquireInfo, vendorCode);
+        if (msg == null) {
+            return;
+        }
+        // emulate HAL 2.1 behavior and send real acquiredInfo
+        final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR
+                ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo;
+        if (mEnrollmentCallback != null) {
+            mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
+        } else if (mAuthenticationCallback != null) {
+            mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
+        }
+    }
+
+    private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
+        // emulate HAL 2.1 behavior and send real errMsgId
+        final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR
+                ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
+        if (mEnrollmentCallback != null) {
+            mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
+                    getErrorString(errMsgId, vendorCode));
+        } else if (mAuthenticationCallback != null) {
+            mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
+                    getErrorString(errMsgId, vendorCode));
+        } else if (mRemovalCallback != null) {
+            mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
+                    getErrorString(errMsgId, vendorCode));
+        } else if (mEnumerateCallback != null) {
+            mEnumerateCallback.onEnumerateError(clientErrMsgId,
+                    getErrorString(errMsgId, vendorCode));
+        }
+    }
+
     /**
      * @hide
      */
@@ -1023,7 +1134,10 @@
         }
     }
 
-    private String getErrorString(int errMsg, int vendorCode) {
+    /**
+     * @hide
+     */
+    public String getErrorString(int errMsg, int vendorCode) {
         switch (errMsg) {
             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
                 return mContext.getString(
@@ -1043,6 +1157,9 @@
             case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
                 return mContext.getString(
                         com.android.internal.R.string.fingerprint_error_lockout_permanent);
+            case FINGERPRINT_ERROR_USER_CANCELED:
+                return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_user_canceled);
             case FINGERPRINT_ERROR_VENDOR: {
                     String[] msgArray = mContext.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_error_vendor);
@@ -1055,7 +1172,10 @@
         return null;
     }
 
-    private String getAcquiredString(int acquireInfo, int vendorCode) {
+    /**
+     * @hide
+     */
+    public String getAcquiredString(int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FINGERPRINT_ACQUIRED_GOOD:
                 return null;
@@ -1096,22 +1216,47 @@
 
         @Override // binder call
         public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
-            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget();
+            if (mExecutor != null) {
+                mExecutor.execute(() -> {
+                    sendAcquiredResult(deviceId, acquireInfo, vendorCode);
+                });
+            } else {
+                mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode,
+                        deviceId).sendToTarget();
+            }
         }
 
         @Override // binder call
         public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
-            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
+            if (mExecutor != null) {
+                mExecutor.execute(() -> {
+                    sendAuthenticatedSucceeded(fp, userId);
+                });
+            } else {
+                mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
+            }
         }
 
         @Override // binder call
         public void onAuthenticationFailed(long deviceId) {
-            mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
+            if (mExecutor != null) {
+                mExecutor.execute(() -> {
+                    sendAuthenticatedFailed();
+                });
+            } else {
+                mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
+            }
         }
 
         @Override // binder call
         public void onError(long deviceId, int error, int vendorCode) {
-            mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
+            if (mExecutor != null) {
+                mExecutor.execute(() -> {
+                    sendErrorResult(deviceId, error, vendorCode);
+                });
+            } else {
+                mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
+            }
         }
 
         @Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl
new file mode 100644
index 0000000..13e7974
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintDialogReceiver.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FingerprintDialog (SysUI) back to AuthenticationClient.
+ * @hide
+ */
+oneway interface IFingerprintDialogReceiver {
+    void onDialogDismissed(int reason);
+}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 4879d54..f1502e4 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.hardware.fingerprint.Fingerprint;
@@ -29,7 +30,8 @@
 interface IFingerprintService {
     // Authenticate the given sessionId with a fingerprint
     void authenticate(IBinder token, long sessionId, int userId,
-            IFingerprintServiceReceiver receiver, int flags, String opPackageName);
+            IFingerprintServiceReceiver receiver, int flags, String opPackageName,
+            in Bundle bundle, IFingerprintDialogReceiver dialogReceiver);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index eeb30e2..3ce0283 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -21,6 +21,7 @@
 import android.net.IpSecUdpEncapResponse;
 import android.net.IpSecSpiResponse;
 import android.net.IpSecTransformResponse;
+import android.net.IpSecTunnelInterfaceResponse;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -39,11 +40,29 @@
 
     void closeUdpEncapsulationSocket(int resourceId);
 
+    IpSecTunnelInterfaceResponse createTunnelInterface(
+            in String localAddr,
+            in String remoteAddr,
+            in Network underlyingNetwork,
+            in IBinder binder);
+
+    void addAddressToTunnelInterface(
+            int tunnelResourceId,
+            String localAddr);
+
+    void removeAddressFromTunnelInterface(
+            int tunnelResourceId,
+            String localAddr);
+
+    void deleteTunnelInterface(int resourceId);
+
     IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder);
 
     void deleteTransform(int transformId);
 
     void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
 
+    void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId);
+
     void removeTransportModeTransforms(in ParcelFileDescriptor socket);
 }
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 80b0af3..6a262e2 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -65,6 +65,10 @@
     // An interval, in seconds between the NattKeepalive packets
     private int mNattKeepaliveInterval;
 
+    // XFRM mark and mask
+    private int mMarkValue;
+    private int mMarkMask;
+
     /** Set the mode for this IPsec transform */
     public void setMode(int mode) {
         mMode = mode;
@@ -121,6 +125,14 @@
         mNattKeepaliveInterval = interval;
     }
 
+    public void setMarkValue(int mark) {
+        mMarkValue = mark;
+    }
+
+    public void setMarkMask(int mask) {
+        mMarkMask = mask;
+    }
+
     // Transport or Tunnel
     public int getMode() {
         return mMode;
@@ -170,6 +182,14 @@
         return mNattKeepaliveInterval;
     }
 
+    public int getMarkValue() {
+        return mMarkValue;
+    }
+
+    public int getMarkMask() {
+        return mMarkMask;
+    }
+
     // Parcelable Methods
 
     @Override
@@ -191,6 +211,8 @@
         out.writeInt(mEncapSocketResourceId);
         out.writeInt(mEncapRemotePort);
         out.writeInt(mNattKeepaliveInterval);
+        out.writeInt(mMarkValue);
+        out.writeInt(mMarkMask);
     }
 
     @VisibleForTesting
@@ -212,6 +234,8 @@
         mEncapSocketResourceId = in.readInt();
         mEncapRemotePort = in.readInt();
         mNattKeepaliveInterval = in.readInt();
+        mMarkValue = in.readInt();
+        mMarkMask = in.readInt();
     }
 
     @Override
@@ -242,6 +266,10 @@
                 .append(mAuthentication)
                 .append(", mAuthenticatedEncryption=")
                 .append(mAuthenticatedEncryption)
+                .append(", mMarkValue=")
+                .append(mMarkValue)
+                .append(", mMarkMask=")
+                .append(mMarkMask)
                 .append("}");
 
         return strBuilder.toString();
@@ -275,6 +303,8 @@
                 && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption)
                 && IpSecAlgorithm.equals(
                         lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
-                && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication));
+                && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)
+                && lhs.mMarkValue == rhs.mMarkValue
+                && lhs.mMarkMask == rhs.mMarkMask);
     }
 }
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index f04f03f6..24a078f 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -685,7 +685,30 @@
             mLocalAddress = localAddress;
             mRemoteAddress = remoteAddress;
             mUnderlyingNetwork = underlyingNetwork;
-            // TODO: Call IpSecService
+
+            try {
+                IpSecTunnelInterfaceResponse result =
+                        mService.createTunnelInterface(
+                                localAddress.getHostAddress(),
+                                remoteAddress.getHostAddress(),
+                                underlyingNetwork,
+                                new Binder());
+                switch (result.status) {
+                    case Status.OK:
+                        break;
+                    case Status.RESOURCE_UNAVAILABLE:
+                        throw new ResourceUnavailableException(
+                                "No more tunnel interfaces may be allocated by this requester.");
+                    default:
+                        throw new RuntimeException(
+                                "Unknown status returned by IpSecService: " + result.status);
+                }
+                mResourceId = result.resourceId;
+                mInterfaceName = result.interfaceName;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mCloseGuard.open("constructor");
         }
 
         /**
@@ -697,12 +720,12 @@
          */
         @Override
         public void close() {
-            // try {
-            // TODO: Call IpSecService
-            mResourceId = INVALID_RESOURCE_ID;
-            // } catch (RemoteException e) {
-            //    throw e.rethrowFromSystemServer();
-            // }
+            try {
+                mService.deleteTunnelInterface(mResourceId);
+                mResourceId = INVALID_RESOURCE_ID;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
             mCloseGuard.close();
         }
 
@@ -714,11 +737,20 @@
             }
             close();
         }
+
+        /** @hide */
+        @VisibleForTesting
+        public int getResourceId() {
+            return mResourceId;
+        }
     }
 
     /**
      * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
      *
+     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
+     * underlying network goes away, and the onLost() callback is received.
+     *
      * @param localAddress The local addres of the tunnel
      * @param remoteAddress The local addres of the tunnel
      * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
@@ -748,9 +780,14 @@
      * @hide
      */
     @SystemApi
-    void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
+    public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
             IpSecTransform transform) throws IOException {
-        // TODO: call IpSecService
+        try {
+            mService.applyTunnelModeTransform(
+                    tunnel.getResourceId(), direction, transform.getResourceId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
     /**
      * Construct an instance of IpSecManager within an application context.
diff --git a/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl b/core/java/android/net/IpSecTunnelInterfaceResponse.aidl
similarity index 79%
copy from core/java/android/security/keystore/recovery/KeychainSnapshot.aidl
copy to core/java/android/net/IpSecTunnelInterfaceResponse.aidl
index 7822f39..7239221 100644
--- a/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl
+++ b/core/java/android/net/IpSecTunnelInterfaceResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.keystore.recovery;
+package android.net;
 
-/* @hide */
-parcelable KeychainSnapshot;
+/** @hide */
+parcelable IpSecTunnelInterfaceResponse;
diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.java b/core/java/android/net/IpSecTunnelInterfaceResponse.java
new file mode 100644
index 0000000..c23d831
--- /dev/null
+++ b/core/java/android/net/IpSecTunnelInterfaceResponse.java
@@ -0,0 +1,78 @@
+/*
+ * 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class is used to return an IpSecTunnelInterface resource Id and and corresponding status
+ * from the IpSecService to an IpSecTunnelInterface object.
+ *
+ * @hide
+ */
+public final class IpSecTunnelInterfaceResponse implements Parcelable {
+    private static final String TAG = "IpSecTunnelInterfaceResponse";
+
+    public final int resourceId;
+    public final String interfaceName;
+    public final int status;
+    // Parcelable Methods
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(status);
+        out.writeInt(resourceId);
+        out.writeString(interfaceName);
+    }
+
+    public IpSecTunnelInterfaceResponse(int inStatus) {
+        if (inStatus == IpSecManager.Status.OK) {
+            throw new IllegalArgumentException("Valid status implies other args must be provided");
+        }
+        status = inStatus;
+        resourceId = IpSecManager.INVALID_RESOURCE_ID;
+        interfaceName = "";
+    }
+
+    public IpSecTunnelInterfaceResponse(int inStatus, int inResourceId, String inInterfaceName) {
+        status = inStatus;
+        resourceId = inResourceId;
+        interfaceName = inInterfaceName;
+    }
+
+    private IpSecTunnelInterfaceResponse(Parcel in) {
+        status = in.readInt();
+        resourceId = in.readInt();
+        interfaceName = in.readString();
+    }
+
+    public static final Parcelable.Creator<IpSecTunnelInterfaceResponse> CREATOR =
+            new Parcelable.Creator<IpSecTunnelInterfaceResponse>() {
+                public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) {
+                    return new IpSecTunnelInterfaceResponse(in);
+                }
+
+                public IpSecTunnelInterfaceResponse[] newArray(int size) {
+                    return new IpSecTunnelInterfaceResponse[size];
+                }
+            };
+}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 2dacf8f..52a2354 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.content.Context;
+import android.net.ConnectivityManager.PacketKeepalive;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -26,7 +27,6 @@
 
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
-import android.net.ConnectivityManager.PacketKeepalive;
 
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -101,20 +101,6 @@
     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
 
     /**
-     * Sent by the NetworkAgent to ConnectivityService to add new UID ranges
-     * to be forced into this Network.  For VPNs only.
-     * obj = UidRange[] to forward
-     */
-    public static final int EVENT_UID_RANGES_ADDED = BASE + 5;
-
-    /**
-     * Sent by the NetworkAgent to ConnectivityService to remove UID ranges
-     * from being forced into this Network.  For VPNs only.
-     * obj = UidRange[] to stop forwarding
-     */
-    public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
-
-    /**
      * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
      * networks status - whether we could use the network or could not, due to
      * either a bad network configuration (no internet link) or captive portal.
@@ -390,22 +376,6 @@
     }
 
     /**
-     * Called by the VPN code when it wants to add ranges of UIDs to be routed
-     * through the VPN network.
-     */
-    public void addUidRanges(UidRange[] ranges) {
-        queueOrSendMessage(EVENT_UID_RANGES_ADDED, ranges);
-    }
-
-    /**
-     * Called by the VPN code when it wants to remove ranges of UIDs from being routed
-     * through the VPN network.
-     */
-    public void removeUidRanges(UidRange[] ranges) {
-        queueOrSendMessage(EVENT_UID_RANGES_REMOVED, ranges);
-    }
-
-    /**
      * Called by the bearer to indicate this network was manually selected by the user.
      * This should be called before the NetworkInfo is marked CONNECTED so that this
      * Network can be given special treatment at that time. If {@code acceptUnvalidated} is
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 214ff64..1a4765b 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -29,6 +30,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.Set;
 import java.util.StringJoiner;
 
 /**
@@ -47,6 +49,7 @@
  */
 public final class NetworkCapabilities implements Parcelable {
     private static final String TAG = "NetworkCapabilities";
+    private static final int INVALID_UID = -1;
 
     /**
      * @hide
@@ -64,6 +67,8 @@
             mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
             mNetworkSpecifier = nc.mNetworkSpecifier;
             mSignalStrength = nc.mSignalStrength;
+            mUids = nc.mUids;
+            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
         }
     }
 
@@ -77,6 +82,8 @@
         mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
         mNetworkSpecifier = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
+        mUids = null;
+        mEstablishingVpnAppUid = INVALID_UID;
     }
 
     /**
@@ -619,6 +626,29 @@
     }
 
     /**
+     * UID of the app that manages this network, or INVALID_UID if none/unknown.
+     *
+     * This field keeps track of the UID of the app that created this network and is in charge
+     * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
+     * accordingly, but it may be renamed if other mechanisms are offered for third party apps
+     * to create networks.
+     *
+     * Because this field is only used in the services side (and to avoid apps being able to
+     * set this to whatever they want), this field is not parcelled and will not be conserved
+     * across the IPC boundary.
+     * @hide
+     */
+    private int mEstablishingVpnAppUid = INVALID_UID;
+
+    /**
+     * Set the UID of the managing app.
+     * @hide
+     */
+    public void setEstablishingVpnAppUid(final int uid) {
+        mEstablishingVpnAppUid = uid;
+    }
+
+    /**
      * Value indicating that link bandwidth is unspecified.
      * @hide
      */
@@ -837,6 +867,174 @@
     }
 
     /**
+     * List of UIDs this network applies to. No restriction if null.
+     * <p>
+     * This is typically (and at this time, only) used by VPN. This network is only available to
+     * the UIDs in this list, and it is their default network. Apps in this list that wish to
+     * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
+     * member is null, then the network is not restricted by app UID. If it's an empty list, then
+     * it means nobody can use it.
+     * As a special exception, the app managing this network (as identified by its UID stored in
+     * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
+     * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
+     * to the app that manages it as determined by #appliesToUid.
+     * <p>
+     * Please note that in principle a single app can be associated with multiple UIDs because
+     * each app will have a different UID when it's run as a different (macro-)user. A single
+     * macro user can only have a single active VPN app at any given time however.
+     * <p>
+     * Also please be aware this class does not try to enforce any normalization on this. Callers
+     * can only alter the UIDs by setting them wholesale : this class does not provide any utility
+     * to add or remove individual UIDs or ranges. If callers have any normalization needs on
+     * their own (like requiring sortedness or no overlap) they need to enforce it
+     * themselves. Some of the internal methods also assume this is normalized as in no adjacent
+     * or overlapping ranges are present.
+     *
+     * @hide
+     */
+    private Set<UidRange> mUids = null;
+
+    /**
+     * Convenience method to set the UIDs this network applies to to a single UID.
+     * @hide
+     */
+    public NetworkCapabilities setSingleUid(int uid) {
+        final ArraySet<UidRange> identity = new ArraySet<>(1);
+        identity.add(new UidRange(uid, uid));
+        setUids(identity);
+        return this;
+    }
+
+    /**
+     * Set the list of UIDs this network applies to.
+     * This makes a copy of the set so that callers can't modify it after the call.
+     * @hide
+     */
+    public NetworkCapabilities setUids(Set<UidRange> uids) {
+        if (null == uids) {
+            mUids = null;
+        } else {
+            mUids = new ArraySet<>(uids);
+        }
+        return this;
+    }
+
+    /**
+     * Get the list of UIDs this network applies to.
+     * This returns a copy of the set so that callers can't modify the original object.
+     * @hide
+     */
+    public Set<UidRange> getUids() {
+        return null == mUids ? null : new ArraySet<>(mUids);
+    }
+
+    /**
+     * Test whether this network applies to this UID.
+     * @hide
+     */
+    public boolean appliesToUid(int uid) {
+        if (null == mUids) return true;
+        for (UidRange range : mUids) {
+            if (range.contains(uid)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests if the set of UIDs that this network applies to is the same of the passed set of UIDs.
+     * <p>
+     * This test only checks whether equal range objects are in both sets. It will
+     * return false if the ranges are not exactly the same, even if the covered UIDs
+     * are for an equivalent result.
+     * <p>
+     * Note that this method is not very optimized, which is fine as long as it's not used very
+     * often.
+     * <p>
+     * nc is assumed nonnull.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean equalsUids(NetworkCapabilities nc) {
+        Set<UidRange> comparedUids = nc.mUids;
+        if (null == comparedUids) return null == mUids;
+        if (null == mUids) return false;
+        // Make a copy so it can be mutated to check that all ranges in mUids
+        // also are in uids.
+        final Set<UidRange> uids = new ArraySet<>(mUids);
+        for (UidRange range : comparedUids) {
+            if (!uids.contains(range)) {
+                return false;
+            }
+            uids.remove(range);
+        }
+        return uids.isEmpty();
+    }
+
+    /**
+     * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require.
+     *
+     * This method is called on the NetworkCapabilities embedded in a request with the
+     * capabilities of an available network. It checks whether all the UIDs from this listen
+     * (representing the UIDs that must have access to the network) are satisfied by the UIDs
+     * in the passed nc (representing the UIDs that this network is available to).
+     * <p>
+     * As a special exception, the UID that created the passed network (as represented by its
+     * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
+     * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
+     * can see its own network when it listens for it.
+     * <p>
+     * nc is assumed nonnull. Else, NPE.
+     * @see #appliesToUid
+     * @hide
+     */
+    public boolean satisfiedByUids(NetworkCapabilities nc) {
+        if (null == nc.mUids) return true; // The network satisfies everything.
+        if (null == mUids) return false; // Not everything allowed but requires everything
+        for (UidRange requiredRange : mUids) {
+            if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
+            if (!nc.appliesToUidRange(requiredRange)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns whether this network applies to the passed ranges.
+     * This assumes that to apply, the passed range has to be entirely contained
+     * within one of the ranges this network applies to. If the ranges are not normalized,
+     * this method may return false even though all required UIDs are covered because no
+     * single range contained them all.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean appliesToUidRange(UidRange requiredRange) {
+        if (null == mUids) return true;
+        for (UidRange uidRange : mUids) {
+            if (uidRange.containsRange(requiredRange)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Combine the UIDs this network currently applies to with the UIDs the passed
+     * NetworkCapabilities apply to.
+     * nc is assumed nonnull.
+     */
+    private void combineUids(NetworkCapabilities nc) {
+        if (null == nc.mUids || null == mUids) {
+            mUids = null;
+            return;
+        }
+        mUids.addAll(nc.mUids);
+    }
+
+    /**
      * Combine a set of Capabilities to this one.  Useful for coming up with the complete set
      * @hide
      */
@@ -846,6 +1044,7 @@
         combineLinkBandwidths(nc);
         combineSpecifiers(nc);
         combineSignalStrength(nc);
+        combineUids(nc);
     }
 
     /**
@@ -858,12 +1057,13 @@
      * @hide
      */
     private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
-        return (nc != null &&
-                satisfiedByNetCapabilities(nc, onlyImmutable) &&
-                satisfiedByTransportTypes(nc) &&
-                (onlyImmutable || satisfiedByLinkBandwidths(nc)) &&
-                satisfiedBySpecifier(nc) &&
-                (onlyImmutable || satisfiedBySignalStrength(nc)));
+        return (nc != null
+                && satisfiedByNetCapabilities(nc, onlyImmutable)
+                && satisfiedByTransportTypes(nc)
+                && (onlyImmutable || satisfiedByLinkBandwidths(nc))
+                && satisfiedBySpecifier(nc)
+                && (onlyImmutable || satisfiedBySignalStrength(nc))
+                && (onlyImmutable || satisfiedByUids(nc)));
     }
 
     /**
@@ -944,24 +1144,26 @@
     @Override
     public boolean equals(Object obj) {
         if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
-        NetworkCapabilities that = (NetworkCapabilities)obj;
-        return (equalsNetCapabilities(that) &&
-                equalsTransportTypes(that) &&
-                equalsLinkBandwidths(that) &&
-                equalsSignalStrength(that) &&
-                equalsSpecifier(that));
+        NetworkCapabilities that = (NetworkCapabilities) obj;
+        return (equalsNetCapabilities(that)
+                && equalsTransportTypes(that)
+                && equalsLinkBandwidths(that)
+                && equalsSignalStrength(that)
+                && equalsSpecifier(that)
+                && equalsUids(that));
     }
 
     @Override
     public int hashCode() {
-        return ((int)(mNetworkCapabilities & 0xFFFFFFFF) +
-                ((int)(mNetworkCapabilities >> 32) * 3) +
-                ((int)(mTransportTypes & 0xFFFFFFFF) * 5) +
-                ((int)(mTransportTypes >> 32) * 7) +
-                (mLinkUpBandwidthKbps * 11) +
-                (mLinkDownBandwidthKbps * 13) +
-                Objects.hashCode(mNetworkSpecifier) * 17 +
-                (mSignalStrength * 19));
+        return ((int) (mNetworkCapabilities & 0xFFFFFFFF)
+                + ((int) (mNetworkCapabilities >> 32) * 3)
+                + ((int) (mTransportTypes & 0xFFFFFFFF) * 5)
+                + ((int) (mTransportTypes >> 32) * 7)
+                + (mLinkUpBandwidthKbps * 11)
+                + (mLinkDownBandwidthKbps * 13)
+                + Objects.hashCode(mNetworkSpecifier) * 17
+                + (mSignalStrength * 19)
+                + Objects.hashCode(mUids) * 23);
     }
 
     @Override
@@ -976,6 +1178,7 @@
         dest.writeInt(mLinkDownBandwidthKbps);
         dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
         dest.writeInt(mSignalStrength);
+        dest.writeArraySet(new ArraySet<>(mUids));
     }
 
     public static final Creator<NetworkCapabilities> CREATOR =
@@ -990,6 +1193,8 @@
                 netCap.mLinkDownBandwidthKbps = in.readInt();
                 netCap.mNetworkSpecifier = in.readParcelable(null);
                 netCap.mSignalStrength = in.readInt();
+                netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
+                        null /* ClassLoader, null for default */);
                 return netCap;
             }
             @Override
@@ -1022,7 +1227,12 @@
 
         String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : "");
 
-        return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
+        String uids = (null != mUids ? " Uids: <" + mUids + ">" : "");
+
+        String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid;
+
+        return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength
+            + uids + establishingAppUid + "]";
     }
 
     /** @hide */
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 5c5e351..fc88e90 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -202,7 +202,8 @@
         mLooper = Looper.myLooper();
         if (mLooper == null) {
             throw new RuntimeException(
-                "Can't create handler inside thread that has not called Looper.prepare()");
+                "Can't create handler inside thread " + Thread.currentThread()
+                        + " that has not called Looper.prepare()");
         }
         mQueue = mLooper.mQueue;
         mCallback = callback;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3798a5e..61172e1 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -23,6 +23,7 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -1652,6 +1653,21 @@
             }
         }
 
+        /** @hide */
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            synchronized (mToken) {
+                final long token = proto.start(fieldId);
+                proto.write(PowerManagerProto.WakeLockProto.HEX_STRING,
+                        Integer.toHexString(System.identityHashCode(this)));
+                proto.write(PowerManagerProto.WakeLockProto.HELD, mHeld);
+                proto.write(PowerManagerProto.WakeLockProto.INTERNAL_COUNT, mInternalCount);
+                if (mWorkSource != null) {
+                    mWorkSource.writeToProto(proto, PowerManagerProto.WakeLockProto.WORK_SOURCE);
+                }
+                proto.end(token);
+            }
+        }
+
         /**
          * Wraps a Runnable such that this method immediately acquires the wake lock and then
          * once the Runnable is done the wake lock is released.
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 3ef0961..c7d89b0 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -71,6 +71,24 @@
     }
 
     /**
+     * Converts platform constants to proto enums.
+     */
+    public static int wakefulnessToProtoEnum(int wakefulness) {
+        switch (wakefulness) {
+            case WAKEFULNESS_ASLEEP:
+                return PowerManagerInternalProto.WAKEFULNESS_ASLEEP;
+            case WAKEFULNESS_AWAKE:
+                return PowerManagerInternalProto.WAKEFULNESS_AWAKE;
+            case WAKEFULNESS_DREAMING:
+                return PowerManagerInternalProto.WAKEFULNESS_DREAMING;
+            case WAKEFULNESS_DOZING:
+                return PowerManagerInternalProto.WAKEFULNESS_DOZING;
+            default:
+                return wakefulness;
+        }
+    }
+
+    /**
      * Returns true if the wakefulness state represents an interactive state
      * as defined by {@link android.os.PowerManager#isInteractive}.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7683880..6833908 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -574,6 +574,14 @@
     }
 
     /**
+     * Returns whether the given uid belongs to a system core component or not.
+     * @hide
+     */
+    public static boolean isCoreUid(int uid) {
+        return UserHandle.isCore(uid);
+    }
+
+    /**
      * Returns whether the given uid belongs to an application.
      * @param uid A kernel uid.
      * @return Whether the uid corresponds to an application sandbox running in
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 6381b56..5be72bc 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -126,7 +126,10 @@
         return getAppId(uid1) == getAppId(uid2);
     }
 
-    /** @hide */
+    /**
+     * Whether a UID is an "isolated" UID.
+     * @hide
+     */
     public static boolean isIsolated(int uid) {
         if (uid > 0) {
             final int appId = getAppId(uid);
@@ -136,7 +139,11 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Whether a UID belongs to a regular app. *Note* "Not a regular app" does not mean
+     * "it's system", because of isolated UIDs. Use {@link #isCore} for that.
+     * @hide
+     */
     public static boolean isApp(int uid) {
         if (uid > 0) {
             final int appId = getAppId(uid);
@@ -147,6 +154,19 @@
     }
 
     /**
+     * Whether a UID belongs to a system core component or not.
+     * @hide
+     */
+    public static boolean isCore(int uid) {
+        if (uid > 0) {
+            final int appId = getAppId(uid);
+            return appId < Process.FIRST_APPLICATION_UID;
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Returns the user for a given uid.
      * @param uid A uid for an application running in a particular user.
      * @return A {@link UserHandle} for that user.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 228a86d..4b9f589 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1479,6 +1479,21 @@
     public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE =
             "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
 
+    /**
+     * Activity Action: Show screen for controlling which apps have access on volume directories.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * <p>
+     * Applications typically use this action to ask the user to revert the "Do not ask again"
+     * status of directory access requests made by
+     * {@link android.os.storage.StorageVolume#createAccessIntent(String)}.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS =
+            "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -5486,37 +5501,54 @@
          * Note: do not rely on this value being present in settings.db or on ContentObserver
          * notifications for the corresponding Uri. Use {@link LocationManager#MODE_CHANGED_ACTION}
          * to receive changes in this value.
+         *
+         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
+         *             get the status of a location provider, use
+         *             {@link LocationManager#isProviderEnabled(String)}.
          */
+        @Deprecated
         public static final String LOCATION_MODE = "location_mode";
-        /**
-         * Stores the previous location mode when {@link #LOCATION_MODE} is set to
-         * {@link #LOCATION_MODE_OFF}
-         * @hide
-         */
-        public static final String LOCATION_PREVIOUS_MODE = "location_previous_mode";
 
         /**
-         * Sets all location providers to the previous states before location was turned off.
-         * @hide
-         */
-        public static final int LOCATION_MODE_PREVIOUS = -1;
-        /**
          * Location access disabled.
+         *
+         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
+         *             get the status of a location provider, use
+         *             {@link LocationManager#isProviderEnabled(String)}.
          */
+        @Deprecated
         public static final int LOCATION_MODE_OFF = 0;
+
         /**
          * Network Location Provider disabled, but GPS and other sensors enabled.
+         *
+         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
+         *             get the status of a location provider, use
+         *             {@link LocationManager#isProviderEnabled(String)}.
          */
+        @Deprecated
         public static final int LOCATION_MODE_SENSORS_ONLY = 1;
+
         /**
          * Reduced power usage, such as limiting the number of GPS updates per hour. Requests
          * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
          * {@link android.location.Criteria#POWER_MEDIUM}.
+         *
+         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
+         *             get the status of a location provider, use
+         *             {@link LocationManager#isProviderEnabled(String)}.
          */
+        @Deprecated
         public static final int LOCATION_MODE_BATTERY_SAVING = 2;
+
         /**
          * Best-effort location computation allowed.
+         *
+         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
+         *             get the status of a location provider, use
+         *             {@link LocationManager#isProviderEnabled(String)}.
          */
+        @Deprecated
         public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
 
         /**
@@ -7843,7 +7875,6 @@
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
-            CLONE_TO_MANAGED_PROFILE.add(LOCATION_PREVIOUS_MODE);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
             CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
         }
@@ -7894,8 +7925,7 @@
          * @param provider the location provider to query
          * @return true if the provider is enabled
          *
-         * @deprecated use {@link #LOCATION_MODE} or
-         *             {@link LocationManager#isProviderEnabled(String)}
+         * @deprecated use {@link LocationManager#isProviderEnabled(String)}
          */
         @Deprecated
         public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
@@ -7908,12 +7938,13 @@
          * @param provider the location provider to query
          * @param userId the userId to query
          * @return true if the provider is enabled
-         * @deprecated use {@link #LOCATION_MODE} or
-         *             {@link LocationManager#isProviderEnabled(String)}
+         *
+         * @deprecated use {@link LocationManager#isProviderEnabled(String)}
          * @hide
          */
         @Deprecated
-        public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
+        public static final boolean isLocationProviderEnabledForUser(
+                ContentResolver cr, String provider, int userId) {
             String allowedProviders = Settings.Secure.getStringForUser(cr,
                     LOCATION_PROVIDERS_ALLOWED, userId);
             return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
@@ -7924,7 +7955,8 @@
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
-         * @deprecated use {@link #putInt(ContentResolver, String, int)} and {@link #LOCATION_MODE}
+         * @deprecated This API is deprecated. It requires WRITE_SECURE_SETTINGS permission to
+         *             change location settings.
          */
         @Deprecated
         public static final void setLocationProviderEnabled(ContentResolver cr,
@@ -7940,8 +7972,8 @@
          * @param enabled true if the provider should be enabled
          * @param userId the userId for which to enable/disable providers
          * @return true if the value was set, false on database errors
-         * @deprecated use {@link #putIntForUser(ContentResolver, String, int, int)} and
-         *             {@link #LOCATION_MODE}
+         *
+         * @deprecated use {@link LocationManager#setProviderEnabledForUser(String, boolean, int)}
          * @hide
          */
         @Deprecated
@@ -7962,28 +7994,6 @@
         }
 
         /**
-         * Saves the current location mode into {@link #LOCATION_PREVIOUS_MODE}.
-         */
-        private static final boolean saveLocationModeForUser(ContentResolver cr, int userId) {
-            final int mode = getLocationModeForUser(cr, userId);
-            return putIntForUser(cr, Settings.Secure.LOCATION_PREVIOUS_MODE, mode, userId);
-        }
-
-        /**
-         * Restores the current location mode from {@link #LOCATION_PREVIOUS_MODE}.
-         */
-        private static final boolean restoreLocationModeForUser(ContentResolver cr, int userId) {
-            int mode = getIntForUser(cr, Settings.Secure.LOCATION_PREVIOUS_MODE,
-                    LOCATION_MODE_HIGH_ACCURACY, userId);
-            // Make sure that the previous mode is never "off". Otherwise the user won't be able to
-            // turn on location any longer.
-            if (mode == LOCATION_MODE_OFF) {
-                mode = LOCATION_MODE_HIGH_ACCURACY;
-            }
-            return setLocationModeForUser(cr, mode, userId);
-        }
-
-        /**
          * Thread-safe method for setting the location mode to one of
          * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
          * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
@@ -7996,18 +8006,20 @@
          * @return true if the value was set, false on database errors
          *
          * @throws IllegalArgumentException if mode is not one of the supported values
+         *
+         * @deprecated To enable/disable location, use
+         *             {@link LocationManager#setLocationEnabledForUser(boolean, int)}.
+         *             To enable/disable a specific location provider, use
+         *             {@link LocationManager#setProviderEnabledForUser(String, boolean, int)}.
          */
-        private static final boolean setLocationModeForUser(ContentResolver cr, int mode,
-                int userId) {
+        @Deprecated
+        private static boolean setLocationModeForUser(
+                ContentResolver cr, int mode, int userId) {
             synchronized (mLocationSettingsLock) {
                 boolean gps = false;
                 boolean network = false;
                 switch (mode) {
-                    case LOCATION_MODE_PREVIOUS:
-                        // Retrieve the actual mode and set to that mode.
-                        return restoreLocationModeForUser(cr, userId);
                     case LOCATION_MODE_OFF:
-                        saveLocationModeForUser(cr, userId);
                         break;
                     case LOCATION_MODE_SENSORS_ONLY:
                         gps = true;
@@ -8022,15 +8034,7 @@
                     default:
                         throw new IllegalArgumentException("Invalid location mode: " + mode);
                 }
-                // Note it's important that we set the NLP mode first. The Google implementation
-                // of NLP clears its NLP consent setting any time it receives a
-                // LocationManager.PROVIDERS_CHANGED_ACTION broadcast and NLP is disabled. Also,
-                // it shows an NLP consent dialog any time it receives the broadcast, NLP is
-                // enabled, and the NLP consent is not set. If 1) we were to enable GPS first,
-                // 2) a setup wizard has its own NLP consent UI that sets the NLP consent setting,
-                // and 3) the receiver happened to complete before we enabled NLP, then the Google
-                // NLP would detect the attempt to enable NLP and show a redundant NLP consent
-                // dialog. Then the people who wrote the setup wizard would be sad.
+
                 boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
                         cr, LocationManager.NETWORK_PROVIDER, network, userId);
                 boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
@@ -11170,10 +11174,20 @@
          *
          * @hide
          */
+        @TestApi
         public static final String LOCATION_GLOBAL_KILL_SWITCH =
                 "location_global_kill_switch";
 
         /**
+         * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
+         * and restoring to lower version of platform API will be skipped.
+         *
+         * @hide
+         */
+        public static final String OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION =
+                "override_settings_provider_restore_any_version";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/security/keystore/BackwardsCompat.java b/core/java/android/security/keystore/BackwardsCompat.java
index 24921f0..69558c4 100644
--- a/core/java/android/security/keystore/BackwardsCompat.java
+++ b/core/java/android/security/keystore/BackwardsCompat.java
@@ -30,7 +30,7 @@
 
 
     static KeychainProtectionParams toLegacyKeychainProtectionParams(
-            android.security.keystore.recovery.KeychainProtectionParams keychainProtectionParams
+            android.security.keystore.recovery.KeyChainProtectionParams keychainProtectionParams
     ) {
         return new KeychainProtectionParams.Builder()
                 .setUserSecretType(keychainProtectionParams.getUserSecretType())
@@ -80,15 +80,15 @@
         return map(wrappedApplicationKeys, BackwardsCompat::fromLegacyWrappedApplicationKey);
     }
 
-    static List<android.security.keystore.recovery.KeychainProtectionParams>
+    static List<android.security.keystore.recovery.KeyChainProtectionParams>
             fromLegacyKeychainProtectionParams(
                     List<KeychainProtectionParams> keychainProtectionParams) {
         return map(keychainProtectionParams, BackwardsCompat::fromLegacyKeychainProtectionParam);
     }
 
-    static android.security.keystore.recovery.KeychainProtectionParams
+    static android.security.keystore.recovery.KeyChainProtectionParams
             fromLegacyKeychainProtectionParam(KeychainProtectionParams keychainProtectionParams) {
-        return new android.security.keystore.recovery.KeychainProtectionParams.Builder()
+        return new android.security.keystore.recovery.KeyChainProtectionParams.Builder()
                 .setUserSecretType(keychainProtectionParams.getUserSecretType())
                 .setSecret(keychainProtectionParams.getSecret())
                 .setLockScreenUiFormat(keychainProtectionParams.getLockScreenUiFormat())
@@ -99,7 +99,7 @@
     }
 
     static KeychainSnapshot toLegacyKeychainSnapshot(
-            android.security.keystore.recovery.KeychainSnapshot keychainSnapshot
+            android.security.keystore.recovery.KeyChainSnapshot keychainSnapshot
     ) {
         return new KeychainSnapshot.Builder()
                 .setCounterId(keychainSnapshot.getCounterId())
@@ -109,7 +109,7 @@
                 .setMaxAttempts(keychainSnapshot.getMaxAttempts())
                 .setServerParams(keychainSnapshot.getServerParams())
                 .setKeychainProtectionParams(
-                        map(keychainSnapshot.getKeychainProtectionParams(),
+                        map(keychainSnapshot.getKeyChainProtectionParams(),
                                 BackwardsCompat::toLegacyKeychainProtectionParams))
                 .setWrappedApplicationKeys(
                         map(keychainSnapshot.getWrappedApplicationKeys(),
diff --git a/core/java/android/security/keystore/KeychainProtectionParams.java b/core/java/android/security/keystore/KeychainProtectionParams.java
index a3cd431..a940fdc 100644
--- a/core/java/android/security/keystore/KeychainProtectionParams.java
+++ b/core/java/android/security/keystore/KeychainProtectionParams.java
@@ -260,9 +260,6 @@
         }
     };
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mUserSecretType);
diff --git a/core/java/android/security/keystore/KeychainSnapshot.java b/core/java/android/security/keystore/KeychainSnapshot.java
index e03dd4a..23aec25 100644
--- a/core/java/android/security/keystore/KeychainSnapshot.java
+++ b/core/java/android/security/keystore/KeychainSnapshot.java
@@ -151,6 +151,8 @@
 
     /**
      * Builder for creating {@link KeychainSnapshot}.
+     *
+     * @hide
      */
     public static class Builder {
         private KeychainSnapshot mInstance = new KeychainSnapshot();
@@ -263,9 +265,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mSnapshotVersion);
diff --git a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
index fda3387..e0781a5 100644
--- a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
+++ b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
@@ -20,6 +20,7 @@
  * Error thrown when the recovery agent supplies an invalid X509 certificate.
  *
  * @hide
+ * Deprecated
  */
 public class BadCertificateFormatException extends RecoveryControllerException {
     public BadCertificateFormatException(String msg) {
diff --git a/core/java/android/security/keystore/recovery/DecryptionFailedException.java b/core/java/android/security/keystore/recovery/DecryptionFailedException.java
index b414dc5..af00e05 100644
--- a/core/java/android/security/keystore/recovery/DecryptionFailedException.java
+++ b/core/java/android/security/keystore/recovery/DecryptionFailedException.java
@@ -16,14 +16,18 @@
 
 package android.security.keystore.recovery;
 
+import android.annotation.SystemApi;
+
+import java.security.GeneralSecurityException;
+
 /**
  * Error thrown when decryption failed, due to an agent error. i.e., using the incorrect key,
  * trying to decrypt garbage data, trying to decrypt data that has somehow been corrupted, etc.
  *
  * @hide
  */
-public class DecryptionFailedException extends RecoveryControllerException {
-
+@SystemApi
+public class DecryptionFailedException extends GeneralSecurityException {
     public DecryptionFailedException(String msg) {
         super(msg);
     }
diff --git a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
index 07a540c..218d26e 100644
--- a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
+++ b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
@@ -16,6 +16,9 @@
 
 package android.security.keystore.recovery;
 
+import android.annotation.SystemApi;
+
+import java.security.GeneralSecurityException;
 /**
  * An error thrown when something went wrong internally in the recovery service.
  *
@@ -24,7 +27,8 @@
  *
  * @hide
  */
-public class InternalRecoveryServiceException extends RecoveryControllerException {
+@SystemApi
+public class InternalRecoveryServiceException extends GeneralSecurityException {
     public InternalRecoveryServiceException(String msg) {
         super(msg);
     }
diff --git a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.aidl
similarity index 94%
rename from core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
rename to core/java/android/security/keystore/recovery/KeyChainProtectionParams.aidl
index 5385738..58edc84 100644
--- a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.aidl
@@ -17,4 +17,4 @@
 package android.security.keystore.recovery;
 
 /* @hide */
-parcelable KeychainProtectionParams;
+parcelable KeyChainProtectionParams;
diff --git a/core/java/android/security/keystore/recovery/KeychainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
similarity index 81%
rename from core/java/android/security/keystore/recovery/KeychainProtectionParams.java
rename to core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index 445815b..a43952a 100644
--- a/core/java/android/security/keystore/recovery/KeychainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,7 +29,7 @@
 import java.util.Arrays;
 
 /**
- * A {@link KeychainSnapshot} is protected with a key derived from the user's lock screen. This
+ * A {@link KeyChainSnapshot} is protected with a key derived from the user's lock screen. This
  * class wraps all the data necessary to derive the same key on a recovering device:
  *
  * <ul>
@@ -38,7 +39,7 @@
  *     <li>The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt.
  * </ul>
  *
- * <p>As such, this data is sent along with the {@link KeychainSnapshot} when syncing the current
+ * <p>As such, this data is sent along with the {@link KeyChainSnapshot} when syncing the current
  * version of the keychain.
  *
  * <p>For now, the recoverable keychain only supports a single layer of protection, which is the
@@ -47,10 +48,11 @@
  *
  * @hide
  */
-public final class KeychainProtectionParams implements Parcelable {
+@SystemApi
+public final class KeyChainProtectionParams implements Parcelable {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
+    @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
     public @interface UserSecretType {
     }
 
@@ -66,24 +68,24 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_PIN, TYPE_PASSWORD, TYPE_PATTERN})
+    @IntDef(prefix = {"UI_FORMAT_"}, value = {UI_FORMAT_PIN, UI_FORMAT_PASSWORD, UI_FORMAT_PATTERN})
     public @interface LockScreenUiFormat {
     }
 
     /**
      * Pin with digits only.
      */
-    public static final int TYPE_PIN = 1;
+    public static final int UI_FORMAT_PIN = 1;
 
     /**
      * Password. String with latin-1 characters only.
      */
-    public static final int TYPE_PASSWORD = 2;
+    public static final int UI_FORMAT_PASSWORD = 2;
 
     /**
      * Pattern with 3 by 3 grid.
      */
-    public static final int TYPE_PATTERN = 3;
+    public static final int UI_FORMAT_PATTERN = 3;
 
     @UserSecretType
     private Integer mUserSecretType;
@@ -102,7 +104,7 @@
      * @link {#clearSecret} to overwrite its value in memory.
      * @hide
      */
-    public KeychainProtectionParams(@UserSecretType int userSecretType,
+    public KeyChainProtectionParams(@UserSecretType int userSecretType,
             @LockScreenUiFormat int lockScreenUiFormat,
             @NonNull KeyDerivationParams keyDerivationParams,
             @NonNull byte[] secret) {
@@ -112,7 +114,7 @@
         mSecret = Preconditions.checkNotNull(secret);
     }
 
-    private KeychainProtectionParams() {
+    private KeyChainProtectionParams() {
 
     }
 
@@ -126,11 +128,11 @@
 
     /**
      * Specifies UX shown to user during recovery.
-     * Default value is {@code TYPE_LOCKSCREEN}
+     * Default value is {@code UI_FORMAT_LOCKSCREEN}
      *
-     * @see TYPE_PIN
-     * @see TYPE_PASSWORD
-     * @see TYPE_PATTERN
+     * @see UI_FORMAT_PIN
+     * @see UI_FORMAT_PASSWORD
+     * @see UI_FORMAT_PATTERN
      */
     public @LockScreenUiFormat int getLockScreenUiFormat() {
         return mLockScreenUiFormat;
@@ -140,7 +142,7 @@
      * Specifies function used to derive symmetric key from user input
      * Format is defined in separate util class.
      */
-    @NonNull public KeyDerivationParams getKeyDerivationParams() {
+    public @NonNull KeyDerivationParams getKeyDerivationParams() {
         return mKeyDerivationParams;
     }
 
@@ -155,11 +157,10 @@
     }
 
     /**
-     * Builder for creating {@link KeychainProtectionParams}.
+     * Builder for creating {@link KeyChainProtectionParams}.
      */
     public static class Builder {
-        private KeychainProtectionParams
-                mInstance = new KeychainProtectionParams();
+        private KeyChainProtectionParams mInstance = new KeyChainProtectionParams();
 
         /**
          * Sets user secret type.
@@ -177,9 +178,9 @@
         /**
          * Sets UI format.
          *
-         * @see TYPE_PIN
-         * @see TYPE_PASSWORD
-         * @see TYPE_PATTERN
+         * @see UI_FORMAT_PIN
+         * @see UI_FORMAT_PASSWORD
+         * @see UI_FORMAT_PATTERN
          * @param lockScreenUiFormat The UI format
          * @return This builder.
          */
@@ -213,14 +214,14 @@
 
 
         /**
-         * Creates a new {@link KeychainProtectionParams} instance.
+         * Creates a new {@link KeyChainProtectionParams} instance.
          * The instance will include default values, if {@link setSecret}
          * or {@link setUserSecretType} were not called.
          *
          * @return new instance
          * @throws NullPointerException if some required fields were not set.
          */
-        @NonNull public KeychainProtectionParams build() {
+        @NonNull public KeyChainProtectionParams build() {
             if (mInstance.mUserSecretType == null) {
                 mInstance.mUserSecretType = TYPE_LOCKSCREEN;
             }
@@ -250,20 +251,17 @@
         Arrays.fill(mSecret, (byte) 0);
     }
 
-    public static final Creator<KeychainProtectionParams> CREATOR =
-            new Creator<KeychainProtectionParams>() {
-        public KeychainProtectionParams createFromParcel(Parcel in) {
-            return new KeychainProtectionParams(in);
+    public static final Parcelable.Creator<KeyChainProtectionParams> CREATOR =
+            new Parcelable.Creator<KeyChainProtectionParams>() {
+        public KeyChainProtectionParams createFromParcel(Parcel in) {
+            return new KeyChainProtectionParams(in);
         }
 
-        public KeychainProtectionParams[] newArray(int length) {
-            return new KeychainProtectionParams[length];
+        public KeyChainProtectionParams[] newArray(int length) {
+            return new KeyChainProtectionParams[length];
         }
     };
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mUserSecretType);
@@ -275,7 +273,7 @@
     /**
      * @hide
      */
-    protected KeychainProtectionParams(Parcel in) {
+    protected KeyChainProtectionParams(Parcel in) {
         mUserSecretType = in.readInt();
         mLockScreenUiFormat = in.readInt();
         mKeyDerivationParams = in.readTypedObject(KeyDerivationParams.CREATOR);
diff --git a/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl b/core/java/android/security/keystore/recovery/KeyChainSnapshot.aidl
similarity index 95%
rename from core/java/android/security/keystore/recovery/KeychainSnapshot.aidl
rename to core/java/android/security/keystore/recovery/KeyChainSnapshot.aidl
index 7822f39..d02a2ea 100644
--- a/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.aidl
@@ -17,4 +17,4 @@
 package android.security.keystore.recovery;
 
 /* @hide */
-parcelable KeychainSnapshot;
+parcelable KeyChainSnapshot;
diff --git a/core/java/android/security/keystore/recovery/KeychainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
similarity index 85%
rename from core/java/android/security/keystore/recovery/KeychainSnapshot.java
rename to core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index a8e2725..df535ed 100644
--- a/core/java/android/security/keystore/recovery/KeychainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -17,6 +17,7 @@
 package android.security.keystore.recovery;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -42,7 +43,8 @@
  *
  * @hide
  */
-public final class KeychainSnapshot implements Parcelable {
+@SystemApi
+public final class KeyChainSnapshot implements Parcelable {
     private static final int DEFAULT_MAX_ATTEMPTS = 10;
     private static final long DEFAULT_COUNTER_ID = 1L;
 
@@ -51,7 +53,7 @@
     private long mCounterId = DEFAULT_COUNTER_ID;
     private byte[] mServerParams;
     private byte[] mPublicKey;
-    private List<KeychainProtectionParams> mKeychainProtectionParams;
+    private List<KeyChainProtectionParams> mKeyChainProtectionParams;
     private List<WrappedApplicationKey> mEntryRecoveryData;
     private byte[] mEncryptedRecoveryKeyBlob;
 
@@ -59,21 +61,21 @@
      * @hide
      * Deprecated, consider using builder.
      */
-    public KeychainSnapshot(
+    public KeyChainSnapshot(
             int snapshotVersion,
-            @NonNull List<KeychainProtectionParams> keychainProtectionParams,
+            @NonNull List<KeyChainProtectionParams> keyChainProtectionParams,
             @NonNull List<WrappedApplicationKey> wrappedApplicationKeys,
             @NonNull byte[] encryptedRecoveryKeyBlob) {
         mSnapshotVersion = snapshotVersion;
-        mKeychainProtectionParams =
-                Preconditions.checkCollectionElementsNotNull(keychainProtectionParams,
-                        "keychainProtectionParams");
+        mKeyChainProtectionParams =
+                Preconditions.checkCollectionElementsNotNull(keyChainProtectionParams,
+                        "KeyChainProtectionParams");
         mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(wrappedApplicationKeys,
                 "wrappedApplicationKeys");
         mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob);
     }
 
-    private KeychainSnapshot() {
+    private KeyChainSnapshot() {
 
     }
 
@@ -119,8 +121,8 @@
     /**
      * UI and key derivation parameters. Note that combination of secrets may be used.
      */
-    public @NonNull List<KeychainProtectionParams> getKeychainProtectionParams() {
-        return mKeychainProtectionParams;
+    public @NonNull List<KeyChainProtectionParams> getKeyChainProtectionParams() {
+        return mKeyChainProtectionParams;
     }
 
     /**
@@ -138,23 +140,23 @@
         return mEncryptedRecoveryKeyBlob;
     }
 
-    public static final Creator<KeychainSnapshot> CREATOR =
-            new Creator<KeychainSnapshot>() {
-        public KeychainSnapshot createFromParcel(Parcel in) {
-            return new KeychainSnapshot(in);
+    public static final Creator<KeyChainSnapshot> CREATOR =
+            new Creator<KeyChainSnapshot>() {
+        public KeyChainSnapshot createFromParcel(Parcel in) {
+            return new KeyChainSnapshot(in);
         }
 
-        public KeychainSnapshot[] newArray(int length) {
-            return new KeychainSnapshot[length];
+        public KeyChainSnapshot[] newArray(int length) {
+            return new KeyChainSnapshot[length];
         }
     };
 
     /**
-     * Builder for creating {@link KeychainSnapshot}.
+     * Builder for creating {@link KeyChainSnapshot}.
+     * @hide
      */
     public static class Builder {
-        private KeychainSnapshot
-                mInstance = new KeychainSnapshot();
+        private KeyChainSnapshot mInstance = new KeyChainSnapshot();
 
         /**
          * Snapshot version for given account.
@@ -217,9 +219,9 @@
          * @param recoveryMetadata The UI and key derivation parameters
          * @return This builder.
          */
-        public Builder setKeychainProtectionParams(
-                @NonNull List<KeychainProtectionParams> recoveryMetadata) {
-            mInstance.mKeychainProtectionParams = recoveryMetadata;
+        public Builder setKeyChainProtectionParams(
+                @NonNull List<KeyChainProtectionParams> recoveryMetadata) {
+            mInstance.mKeyChainProtectionParams = recoveryMetadata;
             return this;
         }
 
@@ -247,13 +249,13 @@
 
 
         /**
-         * Creates a new {@link KeychainSnapshot} instance.
+         * Creates a new {@link KeyChainSnapshot} instance.
          *
          * @return new instance
          * @throws NullPointerException if some required fields were not set.
          */
-        @NonNull public KeychainSnapshot build() {
-            Preconditions.checkCollectionElementsNotNull(mInstance.mKeychainProtectionParams,
+        @NonNull public KeyChainSnapshot build() {
+            Preconditions.checkCollectionElementsNotNull(mInstance.mKeyChainProtectionParams,
                     "recoveryMetadata");
             Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
                     "entryRecoveryData");
@@ -264,13 +266,10 @@
         }
     }
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mSnapshotVersion);
-        out.writeTypedList(mKeychainProtectionParams);
+        out.writeTypedList(mKeyChainProtectionParams);
         out.writeByteArray(mEncryptedRecoveryKeyBlob);
         out.writeTypedList(mEntryRecoveryData);
         out.writeInt(mMaxAttempts);
@@ -282,9 +281,9 @@
     /**
      * @hide
      */
-    protected KeychainSnapshot(Parcel in) {
+    protected KeyChainSnapshot(Parcel in) {
         mSnapshotVersion = in.readInt();
-        mKeychainProtectionParams = in.createTypedArrayList(KeychainProtectionParams.CREATOR);
+        mKeyChainProtectionParams = in.createTypedArrayList(KeyChainProtectionParams.CREATOR);
         mEncryptedRecoveryKeyBlob = in.createByteArray();
         mEntryRecoveryData = in.createTypedArrayList(WrappedApplicationKey.CREATOR);
         mMaxAttempts = in.readInt();
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index 9061395..fc909a0 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -18,9 +18,11 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -32,6 +34,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class KeyDerivationParams implements Parcelable {
     private final int mAlgorithm;
     private byte[] mSalt;
@@ -61,6 +64,9 @@
         return new KeyDerivationParams(ALGORITHM_SHA256, salt);
     }
 
+    /**
+     * @hide
+     */
     // TODO: Make private once legacy API is removed
     public KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
         mAlgorithm = algorithm;
@@ -81,8 +87,8 @@
         return mSalt;
     }
 
-    public static final Creator<KeyDerivationParams> CREATOR =
-            new Creator<KeyDerivationParams>() {
+    public static final Parcelable.Creator<KeyDerivationParams> CREATOR =
+            new Parcelable.Creator<KeyDerivationParams>() {
         public KeyDerivationParams createFromParcel(Parcel in) {
                 return new KeyDerivationParams(in);
         }
@@ -92,9 +98,6 @@
         }
     };
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mAlgorithm);
diff --git a/core/java/android/security/keystore/recovery/LockScreenRequiredException.java b/core/java/android/security/keystore/recovery/LockScreenRequiredException.java
index ced2368..0062d29 100644
--- a/core/java/android/security/keystore/recovery/LockScreenRequiredException.java
+++ b/core/java/android/security/keystore/recovery/LockScreenRequiredException.java
@@ -16,6 +16,10 @@
 
 package android.security.keystore.recovery;
 
+import android.annotation.SystemApi;
+
+import java.security.GeneralSecurityException;
+
 /**
  * Error thrown when trying to generate keys for a profile that has no lock screen set.
  *
@@ -23,7 +27,8 @@
  *
  * @hide
  */
-public class LockScreenRequiredException extends RecoveryControllerException {
+@SystemApi
+public class LockScreenRequiredException extends GeneralSecurityException {
     public LockScreenRequiredException(String msg) {
         super(msg);
     }
diff --git a/core/java/android/security/keystore/recovery/RecoveryClaim.java b/core/java/android/security/keystore/recovery/RecoveryClaim.java
index 11385d8..45c6b4ff 100644
--- a/core/java/android/security/keystore/recovery/RecoveryClaim.java
+++ b/core/java/android/security/keystore/recovery/RecoveryClaim.java
@@ -20,6 +20,7 @@
  * An attempt to recover a keychain protected by remote secure hardware.
  *
  * @hide
+ * Deprecated
  */
 public class RecoveryClaim {
 
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 1908ce2..71a36f1 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -18,15 +18,19 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
+import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
-import android.util.Log;
 
 import com.android.internal.widget.ILockSettings;
 
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -49,6 +53,7 @@
  *
  * @hide
  */
+@SystemApi
 public class RecoveryController {
     private static final String TAG = "RecoveryController";
 
@@ -114,9 +119,18 @@
     }
 
     /**
+     * Internal method used by {@code RecoverySession}.
+     *
+     * @hide
+     */
+    ILockSettings getBinder() {
+        return mBinder;
+    }
+
+    /**
      * Gets a new instance of the class.
      */
-    public static RecoveryController getInstance() {
+    public static RecoveryController getInstance(Context context) {
         ILockSettings lockSettings =
                 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
         return new RecoveryController(lockSettings);
@@ -136,38 +150,39 @@
      *
      * @param rootCertificateAlias alias of a root certificate preinstalled on the device
      * @param signedPublicKeyList binary blob a list of X509 certificates and signature
-     * @throws BadCertificateFormatException if the {@code signedPublicKeyList} is in a bad format.
+     * @throws CertificateException if the {@code signedPublicKeyList} is in a bad format.
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public void initRecoveryService(
             @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
-            throws BadCertificateFormatException, InternalRecoveryServiceException {
+            throws CertificateException, InternalRecoveryServiceException {
         try {
             mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
             if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
-                throw new BadCertificateFormatException(e.getMessage());
+                throw new CertificateException(e.getMessage());
             }
             throw wrapUnexpectedServiceSpecificException(e);
         }
     }
 
     /**
-     * Returns data necessary to store all recoverable keys for given account. Key material is
+     * Returns data necessary to store all recoverable keys. Key material is
      * encrypted with user secret and recovery public key.
      *
-     * @param account specific to Recovery agent.
      * @return Data necessary to recover keystore.
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
-    @NonNull public KeychainSnapshot getRecoveryData(@NonNull byte[] account)
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public @NonNull KeyChainSnapshot getRecoveryData()
             throws InternalRecoveryServiceException {
         try {
-            return mBinder.getRecoveryData(account);
+            return mBinder.getRecoveryData(/*account=*/ new byte[]{});
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -188,6 +203,7 @@
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
             throws InternalRecoveryServiceException {
         try {
@@ -200,32 +216,8 @@
     }
 
     /**
-     * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot
-     * version. Version zero is used, if no snapshots were created for the account.
-     *
-     * @return Map from recovery agent accounts to snapshot versions.
-     * @see KeychainSnapshot#getSnapshotVersion
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
-     */
-    public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
-            throws InternalRecoveryServiceException {
-        try {
-            // IPC doesn't support generic Maps.
-            @SuppressWarnings("unchecked")
-            Map<byte[], Integer> result =
-                    (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions();
-            return result;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw wrapUnexpectedServiceSpecificException(e);
-        }
-    }
-
-    /**
      * Server parameters used to generate new recovery key blobs. This value will be included in
-     * {@code KeychainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included
+     * {@code KeyChainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included
      * in vaultParams {@link #startRecoverySession}
      *
      * @param serverParams included in recovery key blob.
@@ -233,6 +225,7 @@
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public void setServerParams(byte[] serverParams) throws InternalRecoveryServiceException {
         try {
             mBinder.setServerParams(serverParams);
@@ -244,21 +237,43 @@
     }
 
     /**
-     * Updates recovery status for given keys. It is used to notify keystore that key was
+     * Gets aliases of recoverable keys for the application.
+     *
+     * @param packageName which recoverable keys' aliases will be returned.
+     *
+     * @return {@code List} of all aliases.
+     */
+    public List<String> getAliases(@Nullable String packageName)
+            throws InternalRecoveryServiceException {
+        try {
+            // TODO: update aidl
+            Map<String, Integer> allStatuses = mBinder.getRecoveryStatus(packageName);
+            return new ArrayList<>(allStatuses.keySet());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Updates recovery status for given key. It is used to notify keystore that key was
      * successfully stored on the server or there were an error. Application can check this value
      * using {@code getRecoveyStatus}.
      *
-     * @param packageName Application whose recoverable keys' statuses are to be updated.
-     * @param aliases List of application-specific key aliases. If the array is empty, updates the
-     *     status for all existing recoverable keys.
+     * @param packageName Application whose recoverable key's status are to be updated.
+     * @param alias Application-specific key alias.
      * @param status Status specific to recovery agent.
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public void setRecoveryStatus(
-            @NonNull String packageName, @Nullable String[] aliases, int status)
+            @NonNull String packageName, String alias, int status)
             throws NameNotFoundException, InternalRecoveryServiceException {
         try {
+            // TODO: update aidl
+            String[] aliases = alias == null ? null : new String[]{alias};
             mBinder.setRecoveryStatus(packageName, aliases, status);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -268,7 +283,7 @@
     }
 
     /**
-     * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status.
+     * Returns recovery status for Application's KeyStore key.
      * Negative status values are reserved for recovery agent specific codes. List of common codes:
      *
      * <ul>
@@ -278,18 +293,24 @@
      *   <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
      * </ul>
      *
-     * @return {@code Map} from KeyStore alias to recovery status.
+     * @param packageName Application whose recoverable key status is returned.
+     * @param alias Application-specific key alias.
+     * @return Recovery status.
      * @see #setRecoveryStatus
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
-    public Map<String, Integer> getRecoveryStatus() throws InternalRecoveryServiceException {
+    public int getRecoveryStatus(String packageName, String alias)
+            throws InternalRecoveryServiceException {
         try {
-            // IPC doesn't support generic Maps.
-            @SuppressWarnings("unchecked")
-            Map<String, Integer> result =
-                    (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null);
-            return result;
+            // TODO: update aidl
+            Map<String, Integer> allStatuses = mBinder.getRecoveryStatus(packageName);
+            Integer status = allStatuses.get(alias);
+            if (status == null) {
+                return RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE;
+            } else {
+                return status;
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -301,13 +322,13 @@
      * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
      * is necessary to recover data.
      *
-     * @param secretTypes {@link KeychainProtectionParams#TYPE_LOCKSCREEN} or {@link
-     *     KeychainProtectionParams#TYPE_CUSTOM_PASSWORD}
+     * @param secretTypes {@link KeyChainProtectionParams#TYPE_LOCKSCREEN} or {@link
+     *     KeyChainProtectionParams#TYPE_CUSTOM_PASSWORD}
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
     public void setRecoverySecretTypes(
-            @NonNull @KeychainProtectionParams.UserSecretType int[] secretTypes)
+            @NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
             throws InternalRecoveryServiceException {
         try {
             mBinder.setRecoverySecretTypes(secretTypes);
@@ -320,14 +341,14 @@
 
     /**
      * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
-     * necessary to generate KeychainSnapshot.
+     * necessary to generate KeyChainSnapshot.
      *
      * @return list of recovery secret types
-     * @see KeychainSnapshot
+     * @see KeyChainSnapshot
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
-    public @NonNull @KeychainProtectionParams.UserSecretType int[] getRecoverySecretTypes()
+    public @NonNull @KeyChainProtectionParams.UserSecretType int[] getRecoverySecretTypes()
             throws InternalRecoveryServiceException {
         try {
             return mBinder.getRecoverySecretTypes();
@@ -348,7 +369,7 @@
      *     service.
      */
     @NonNull
-    public @KeychainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes()
+    public @KeyChainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes()
             throws InternalRecoveryServiceException {
         try {
             return mBinder.getPendingRecoverySecretTypes();
@@ -362,7 +383,7 @@
     /**
      * Method notifies KeyStore that a user-generated secret is available. This method generates a
      * symmetric session key which a trusted remote device can use to return a recovery key. Caller
-     * should use {@link KeychainProtectionParams#clearSecret} to override the secret value in
+     * should use {@link KeyChainProtectionParams#clearSecret} to override the secret value in
      * memory.
      *
      * @param recoverySecret user generated secret together with parameters necessary to regenerate
@@ -370,7 +391,7 @@
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
-    public void recoverySecretAvailable(@NonNull KeychainProtectionParams recoverySecret)
+    public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
             throws InternalRecoveryServiceException {
         try {
             mBinder.recoverySecretAvailable(recoverySecret);
@@ -382,117 +403,21 @@
     }
 
     /**
-     * Initializes recovery session and returns a blob with proof of recovery secrets possession.
-     * The method generates symmetric key for a session, which trusted remote device can use to
-     * return recovery key.
-     *
-     * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
-     * used to create the recovery blob on the source device.
-     * Keystore will verify the certificate using root of trust.
-     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
-     *     Used to limit number of guesses.
-     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
-     *     replay attacks
-     * @param secrets Secrets provided by user, the method only uses type and secret fields.
-     * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
-     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
-     *     key and parameters necessary to identify the counter with the number of failed recovery
-     *     attempts.
-     * @throws BadCertificateFormatException if the {@code verifierPublicKey} is in an incorrect
-     *     format.
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
-     */
-    @NonNull public RecoveryClaim startRecoverySession(
-            @NonNull byte[] verifierPublicKey,
-            @NonNull byte[] vaultParams,
-            @NonNull byte[] vaultChallenge,
-            @NonNull List<KeychainProtectionParams> secrets)
-            throws BadCertificateFormatException, InternalRecoveryServiceException {
-        try {
-            RecoverySession recoverySession = RecoverySession.newInstance(this);
-            byte[] recoveryClaim =
-                    mBinder.startRecoverySession(
-                            recoverySession.getSessionId(),
-                            verifierPublicKey,
-                            vaultParams,
-                            vaultChallenge,
-                            secrets);
-            return new RecoveryClaim(recoverySession, recoveryClaim);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
-                throw new BadCertificateFormatException(e.getMessage());
-            }
-            throw wrapUnexpectedServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Imports keys.
-     *
-     * @param session Related recovery session, as originally created by invoking
-     *        {@link #startRecoverySession(byte[], byte[], byte[], List)}.
-     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
-     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
-     *     and session. KeyStore only uses package names from the application info in {@link
-     *     WrappedApplicationKey}. Caller is responsibility to perform certificates check.
-     * @return Map from alias to raw key material.
-     * @throws SessionExpiredException if {@code session} has since been closed.
-     * @throws DecryptionFailedException if unable to decrypt the snapshot.
-     * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
-     */
-    public Map<String, byte[]> recoverKeys(
-            @NonNull RecoverySession session,
-            @NonNull byte[] recoveryKeyBlob,
-            @NonNull List<WrappedApplicationKey> applicationKeys)
-            throws SessionExpiredException, DecryptionFailedException,
-            InternalRecoveryServiceException {
-        try {
-            return (Map<String, byte[]>) mBinder.recoverKeys(
-                    session.getSessionId(), recoveryKeyBlob, applicationKeys);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode == ERROR_DECRYPTION_FAILED) {
-                throw new DecryptionFailedException(e.getMessage());
-            }
-            if (e.errorCode == ERROR_SESSION_EXPIRED) {
-                throw new SessionExpiredException(e.getMessage());
-            }
-            throw wrapUnexpectedServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Deletes all data associated with {@code session}. Should not be invoked directly but via
-     * {@link RecoverySession#close()}.
-     *
-     * @hide
-     */
-    void closeSession(RecoverySession session) {
-        try {
-            mBinder.closeSession(session.getSessionId());
-        } catch (RemoteException | ServiceSpecificException e) {
-            Log.e(TAG, "Unexpected error trying to close session", e);
-        }
-    }
-
-    /**
-     * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
-     * raw material of the key.
+     * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
+     * key store. Returns the raw material of the key.
      *
      * @param alias The key alias.
+     * @param account The account associated with the key
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
      *     to generate recoverable keys, as the snapshots are encrypted using a key derived from the
      *     lock screen.
      */
-    public byte[] generateAndStoreKey(@NonNull String alias)
+    public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
             throws InternalRecoveryServiceException, LockScreenRequiredException {
         try {
+            // TODO: add account
             return mBinder.generateAndStoreKey(alias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -521,7 +446,7 @@
         }
     }
 
-    private InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
+    InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
             ServiceSpecificException e) {
         if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) {
             return new InternalRecoveryServiceException(e.getMessage());
diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
index 0fb7c07..2733aca 100644
--- a/core/java/android/security/keystore/recovery/RecoveryControllerException.java
+++ b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
@@ -22,6 +22,7 @@
  * Base exception for errors thrown by {@link RecoveryController}.
  *
  * @hide
+ * Deprecated
  */
 public abstract class RecoveryControllerException extends GeneralSecurityException {
     RecoveryControllerException() { }
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 89f8945..4db5d6e 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -16,15 +16,27 @@
 
 package android.security.keystore.recovery;
 
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+
 import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.util.List;
+import java.util.Map;
 
 /**
- * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a
+ * Session to recover a {@link KeyChainSnapshot} from the remote trusted hardware, initiated by a
  * recovery agent.
  *
  * @hide
  */
+@SystemApi
 public class RecoverySession implements AutoCloseable {
+    private static final String TAG = "RecoverySession";
 
     private static final int SESSION_ID_LENGTH_BYTES = 16;
 
@@ -39,6 +51,7 @@
     /**
      * A new session, started by {@code recoveryManager}.
      */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     static RecoverySession newInstance(RecoveryController recoveryController) {
         return new RecoverySession(recoveryController, newSessionId());
     }
@@ -58,14 +71,107 @@
     }
 
     /**
+     * Starts a recovery session and returns a blob with proof of recovery secret possession.
+     * The method generates a symmetric key for a session, which trusted remote device can use to
+     * return recovery key.
+     *
+     * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
+     *     used to create the recovery blob on the source device.
+     *     Keystore will verify the certificate using root of trust.
+     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
+     *     Used to limit number of guesses.
+     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
+     *     replay attacks
+     * @param secrets Secrets provided by user, the method only uses type and secret fields.
+     * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
+     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
+     *     key and parameters necessary to identify the counter with the number of failed recovery
+     *     attempts.
+     * @throws CertificateException if the {@code verifierPublicKey} is in an incorrect
+     *     format.
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    @NonNull public byte[] start(
+            @NonNull byte[] verifierPublicKey,
+            @NonNull byte[] vaultParams,
+            @NonNull byte[] vaultChallenge,
+            @NonNull List<KeyChainProtectionParams> secrets)
+            throws CertificateException, InternalRecoveryServiceException {
+        try {
+            byte[] recoveryClaim =
+                    mRecoveryController.getBinder().startRecoverySession(
+                            mSessionId,
+                            verifierPublicKey,
+                            vaultParams,
+                            vaultChallenge,
+                            secrets);
+            return recoveryClaim;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+                throw new CertificateException(e.getMessage());
+            }
+            throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
+     * Imports keys.
+     *
+     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
+     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
+     *     and session. KeyStore only uses package names from the application info in {@link
+     *     WrappedApplicationKey}. Caller is responsibility to perform certificates check.
+     * @return Map from alias to raw key material.
+     * @throws SessionExpiredException if {@code session} has since been closed.
+     * @throws DecryptionFailedException if unable to decrypt the snapshot.
+     * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public Map<String, byte[]> recoverKeys(
+            @NonNull byte[] recoveryKeyBlob,
+            @NonNull List<WrappedApplicationKey> applicationKeys)
+            throws SessionExpiredException, DecryptionFailedException,
+            InternalRecoveryServiceException {
+        try {
+            return (Map<String, byte[]>) mRecoveryController.getBinder().recoverKeys(
+                    mSessionId, recoveryKeyBlob, applicationKeys);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == RecoveryController.ERROR_DECRYPTION_FAILED) {
+                throw new DecryptionFailedException(e.getMessage());
+            }
+            if (e.errorCode == RecoveryController.ERROR_SESSION_EXPIRED) {
+                throw new SessionExpiredException(e.getMessage());
+            }
+            throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
      * An internal session ID, used by the framework to match recovery claims to snapshot responses.
+     *
+     * @hide
      */
     String getSessionId() {
         return mSessionId;
     }
 
+    /**
+     * Deletes all data associated with {@code session}. Should not be invoked directly but via
+     * {@link RecoverySession#close()}.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     @Override
     public void close() {
-        mRecoveryController.closeSession(this);
+        try {
+            mRecoveryController.getBinder().closeSession(mSessionId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            Log.e(TAG, "Unexpected error trying to close session", e);
+        }
     }
 }
diff --git a/core/java/android/security/keystore/recovery/SessionExpiredException.java b/core/java/android/security/keystore/recovery/SessionExpiredException.java
index 7fc2b05..8c18e41 100644
--- a/core/java/android/security/keystore/recovery/SessionExpiredException.java
+++ b/core/java/android/security/keystore/recovery/SessionExpiredException.java
@@ -16,12 +16,17 @@
 
 package android.security.keystore.recovery;
 
+import android.annotation.SystemApi;
+
+import java.security.GeneralSecurityException;
+
 /**
  * Error thrown when attempting to use a {@link RecoverySession} that has since expired.
  *
  * @hide
  */
-public class SessionExpiredException extends RecoveryControllerException {
+@SystemApi
+public class SessionExpiredException extends GeneralSecurityException {
     public SessionExpiredException(String msg) {
         super(msg);
     }
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index bca03b3..f360bbe9 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -17,6 +17,8 @@
 package android.security.keystore.recovery;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,6 +29,7 @@
  *
  * <ul>
  *   <li>Alias - Keystore alias of the key.
+ *   <li>Account Recovery Agent specific account associated with the key.
  *   <li>Encrypted key material.
  * </ul>
  *
@@ -35,17 +38,18 @@
  *
  * @hide
  */
+@SystemApi
 public final class WrappedApplicationKey implements Parcelable {
     private String mAlias;
     // The only supported format is AES-256 symmetric key.
     private byte[] mEncryptedKeyMaterial;
+    private byte[] mAccount;
 
     /**
      * Builder for creating {@link WrappedApplicationKey}.
      */
     public static class Builder {
-        private WrappedApplicationKey
-                mInstance = new WrappedApplicationKey();
+        private WrappedApplicationKey mInstance = new WrappedApplicationKey();
 
         /**
          * Sets Application-specific alias of the key.
@@ -59,6 +63,17 @@
         }
 
         /**
+         * Sets Recovery agent specific account.
+         *
+         * @param account The account.
+         * @return This builder.
+         */
+        public Builder setAccount(@NonNull byte[] account) {
+            mInstance.mAccount = account;
+            return this;
+        }
+
+        /**
          * Sets key material encrypted by recovery key.
          *
          * @param encryptedKeyMaterial The key material
@@ -79,12 +94,14 @@
         @NonNull public WrappedApplicationKey build() {
             Preconditions.checkNotNull(mInstance.mAlias);
             Preconditions.checkNotNull(mInstance.mEncryptedKeyMaterial);
+            if (mInstance.mAccount == null) {
+                mInstance.mAccount = new byte[]{};
+            }
             return mInstance;
         }
     }
 
     private WrappedApplicationKey() {
-
     }
 
     /**
@@ -110,8 +127,16 @@
         return mEncryptedKeyMaterial;
     }
 
-    public static final Creator<WrappedApplicationKey> CREATOR =
-            new Creator<WrappedApplicationKey>() {
+    /** Account, default value is empty array */
+    public @NonNull byte[] getAccount() {
+        if (mAccount == null) {
+            return new byte[]{};
+        }
+        return mAccount;
+    }
+
+    public static final Parcelable.Creator<WrappedApplicationKey> CREATOR =
+            new Parcelable.Creator<WrappedApplicationKey>() {
                 public WrappedApplicationKey createFromParcel(Parcel in) {
                     return new WrappedApplicationKey(in);
                 }
@@ -121,13 +146,11 @@
                 }
             };
 
-    /**
-     * @hide
-     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mAlias);
         out.writeByteArray(mEncryptedKeyMaterial);
+        out.writeByteArray(mAccount);
     }
 
     /**
@@ -136,6 +159,7 @@
     protected WrappedApplicationKey(Parcel in) {
         mAlias = in.readString();
         mEncryptedKeyMaterial = in.createByteArray();
+        mAccount = in.createByteArray();
     }
 
     @Override
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index df63a91..1ef6100 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -172,6 +172,7 @@
      * {@hide}
      */
     public static final class Scores implements Parcelable {
+        @NonNull
         public final float[][] scores;
 
         private Scores(Parcel parcel) {
@@ -185,11 +186,23 @@
             }
         }
 
-        private Scores(float[][] scores) {
+        private Scores(@NonNull float[][] scores) {
             this.scores = scores;
         }
 
         @Override
+        public String toString() {
+            final int size1 = scores.length;
+            final int size2 = size1 > 0 ? scores[0].length : 0;
+            final StringBuilder builder = new StringBuilder("Scores [")
+                    .append(size1).append("x").append(size2).append("] ");
+            for (int i = 0; i < size1; i++) {
+                builder.append(i).append(": ").append(Arrays.toString(scores[i])).append(' ');
+            }
+            return builder.toString();
+        }
+
+        @Override
         public int describeContents() {
             return 0;
         }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 9f9033c..b313514 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -40,7 +40,7 @@
         DEFAULT_FLAGS.put("device_info_v2", "true");
         DEFAULT_FLAGS.put("settings_app_info_v2", "true");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
-        DEFAULT_FLAGS.put("settings_battery_v2", "false");
+        DEFAULT_FLAGS.put("settings_battery_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_security_settings_v2", "true");
         DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index e2e9d53..a5e3818 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -105,7 +105,7 @@
      * @param data The data.
      * @return The digest or null if an error occurs.
      */
-    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
+    public static @Nullable byte[] computeSha256DigestBytes(@NonNull byte[] data) {
         MessageDigest messageDigest;
         try {
             messageDigest = MessageDigest.getInstance("SHA256");
@@ -116,6 +116,15 @@
 
         messageDigest.update(data);
 
-        return ByteStringUtils.toHexString(messageDigest.digest());
+        return messageDigest.digest();
+    }
+
+    /**
+     * Computes the SHA256 digest of some data.
+     * @param data The data.
+     * @return The digest or null if an error occurs.
+     */
+    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
+        return ByteStringUtils.toHexString(computeSha256DigestBytes(data));
     }
 }
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 85b7ec8..c7bbb9f 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -48,4 +48,26 @@
         proto.write(Duration.END_MS, endMs);
         proto.end(token);
     }
+
+    /**
+     * Helper function to write bit-wise flags to proto as repeated enums
+     * @hide
+     */
+    public static void writeBitWiseFlagsToProtoEnum(ProtoOutputStream proto, long fieldId,
+            int flags, int[] origEnums, int[] protoEnums) {
+        if (protoEnums.length != origEnums.length) {
+            throw new IllegalArgumentException("The length of origEnums must match protoEnums");
+        }
+        int len = origEnums.length;
+        for (int i = 0; i < len; i++) {
+            // handle zero flag case.
+            if (origEnums[i] == 0 && flags == 0) {
+                proto.write(fieldId, protoEnums[i]);
+                return;
+            }
+            if ((flags & origEnums[i]) != 0) {
+                proto.write(fieldId, protoEnums[i]);
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index ed2b8b6..a597405 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -806,8 +806,10 @@
     public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283;
     /** Key code constant: Show all apps */
     public static final int KEYCODE_ALL_APPS = 284;
+    /** Key code constant: Refresh key. */
+    public static final int KEYCODE_REFRESH = 285;
 
-    private static final int LAST_KEYCODE = KEYCODE_ALL_APPS;
+    private static final int LAST_KEYCODE = KEYCODE_REFRESH;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e0864bd..4631261 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -57,6 +57,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.LayoutAnimationController;
 import android.view.animation.Transformation;
+import android.view.autofill.Helper;
 
 import com.android.internal.R;
 
@@ -3474,8 +3475,10 @@
         }
 
         if (!isLaidOut()) {
-            Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
-                    + childrenCount + " children of " + getAccessibilityViewId());
+            if (Helper.sVerbose) {
+                Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
+                        + childrenCount + " children of " + getAccessibilityViewId());
+            }
             return;
         }
 
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index 0aa2b64..f0a2728 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -26,12 +26,41 @@
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.View;
 
 /**
+ * A View that contains the controls for MediaPlayer2.
+ * It provides a wide range of UI including buttons such as "Play/Pause", "Rewind", "Fast Forward",
+ * "Subtitle", "Full Screen", and it is also possible to add multiple custom buttons.
+ *
+ * <p>
+ * <em> MediaControlView2 can be initialized in two different ways: </em>
+ * 1) When VideoView2 is initialized, it automatically initializes a MediaControlView2 instance and
+ * adds it to the view.
+ * 2) Initialize MediaControlView2 programmatically and add it to a ViewGroup instance.
+ *
+ * In the first option, VideoView2 automatically connects MediaControlView2 to MediaController2,
+ * which is necessary to communicate with MediaSession2. In the second option, however, the
+ * developer needs to manually retrieve a MediaController2 instance and set it to MediaControlView2
+ * by calling setController(MediaController2 controller).
+ *
  * TODO PUBLIC API
  * @hide
  */
 public class MediaControlView2 extends FrameLayout {
+    // TODO: should overflow button be included?
+    public static final int BUTTON_PLAY_PAUSE = 1;
+    public static final int BUTTON_FFWD = 2;
+    public static final int BUTTON_REW = 3;
+    public static final int BUTTON_NEXT = 4;
+    public static final int BUTTON_PREV = 5;
+    public static final int BUTTON_SUBTITLE = 6;
+    public static final int BUTTON_FULL_SCREEN = 7;
+    public static final int BUTTON_OVERFLOW = 8;
+    public static final int BUTTON_MUTE = 9;
+    public static final int BUTTON_ASPECT_RATIO = 10;
+    public static final int BUTTON_SETTINGS = 11;
+
     private final MediaControlView2Provider mProvider;
 
     public MediaControlView2(@NonNull Context context) {
@@ -55,112 +84,135 @@
                 .createMediaControlView2(this, new SuperProvider());
     }
 
+    /**
+     * @hide
+     */
     public MediaControlView2Provider getProvider() {
         return mProvider;
     }
 
     /**
-     * TODO: add docs
+     * Sets MediaController2 instance to control corresponding MediaSession2.
      */
     public void setController(MediaController controller) {
         mProvider.setController_impl(controller);
     }
 
     /**
-     * TODO: add docs
+     * Shows the control view on screen. It will disappear automatically after 3 seconds of
+     * inactivity.
      */
     public void show() {
         mProvider.show_impl();
     }
 
     /**
-     * TODO: add docs
+     * Shows the control view on screen. It will disappear automatically after {@code timeout}
+     * milliseconds of inactivity.
      */
     public void show(int timeout) {
         mProvider.show_impl(timeout);
     }
 
     /**
-     * TODO: add docs
+     * Returns whether the control view is currently shown or hidden.
      */
     public boolean isShowing() {
         return mProvider.isShowing_impl();
     }
 
     /**
-     * TODO: add docs
+     * Hide the control view from the screen.
      */
     public void hide() {
         mProvider.hide_impl();
     }
 
     /**
-     * TODO: add docs
-     */
-    public void showCCButton() {
-        mProvider.showCCButton_impl();
-    }
-
-    /**
-     * TODO: add docs
+     * Returns whether the media is currently playing or not.
      */
     public boolean isPlaying() {
         return mProvider.isPlaying_impl();
     }
 
     /**
-     * TODO: add docs
+     * Returns the current position of the media in milliseconds.
      */
     public int getCurrentPosition() {
         return mProvider.getCurrentPosition_impl();
     }
 
     /**
-     * TODO: add docs
+     * Returns the percentage of how much of the media is currently buffered in storage.
      */
     public int getBufferPercentage() {
         return mProvider.getBufferPercentage_impl();
     }
 
     /**
-     * TODO: add docs
+     * Returns whether the media can be paused or not.
      */
     public boolean canPause() {
         return mProvider.canPause_impl();
     }
 
     /**
-     * TODO: add docs
+     * Returns whether the media can be rewound or not.
      */
     public boolean canSeekBackward() {
         return mProvider.canSeekBackward_impl();
     }
 
     /**
-     * TODO: add docs
+     * Returns whether the media can be fast-forwarded or not.
      */
     public boolean canSeekForward() {
         return mProvider.canSeekForward_impl();
     }
 
     /**
-     * TODO: add docs
+     * If the media selected has a subtitle track, calling this method will display the subtitle at
+     * the bottom of the view. If a media has multiple subtitle tracks, this method will select the
+     * first one of them.
      */
     public void showSubtitle() {
         mProvider.showSubtitle_impl();
     }
 
     /**
-     * TODO: add docs
+     * Hides the currently displayed subtitle.
      */
     public void hideSubtitle() {
         mProvider.hideSubtitle_impl();
     }
 
+    /**
+     * Set listeners for previous and next buttons to customize the behavior of clicking them.
+     * The UI for these buttons are provided as default and will be automatically displayed when
+     * this method is called.
+     *
+     * @param next Listener for clicking next button
+     * @param prev Listener for clicking previous button
+     */
+    public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
+        mProvider.setPrevNextListeners_impl(next, prev);
+    }
+
+    /**
+     * Hides the specified button from view.
+     *
+     * @param button the constant integer assigned to individual buttons
+     * @param visible whether the button should be visible or not
+     */
+    public void setButtonVisibility(int button, boolean visible) {
+        mProvider.setButtonVisibility_impl(button, visible);
+    }
+
     @Override
     protected void onAttachedToWindow() {
         mProvider.onAttachedToWindow_impl();
     }
+
     @Override
     protected void onDetachedFromWindow() {
         mProvider.onDetachedFromWindow_impl();
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 56f3dbd..8650c0a 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.MediaPlayerBase;
 import android.media.update.ApiLoader;
 import android.media.update.VideoView2Provider;
 import android.media.update.ViewProvider;
@@ -32,6 +33,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.List;
 import java.util.Map;
 
 // TODO: Use @link tag to refer MediaPlayer2 in docs once MediaPlayer2.java is submitted. Same to
@@ -235,6 +237,13 @@
         mProvider.hideSubtitle_impl();
     }
 
+    /**
+     * Sets full screen mode.
+     */
+    public void setFullScreen(boolean fullScreen) {
+        mProvider.setFullScreen_impl(fullScreen);
+    }
+
     // TODO: This should be revised after integration with MediaPlayer2.
     /**
      * Sets playback speed.
@@ -271,7 +280,8 @@
      * background.
      *
      * @param focusGain the type of audio focus gain that will be requested, or
-     *     {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during playback.
+     *                  {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during
+     *                  playback.
      */
     public void setAudioFocusRequest(int focusGain) {
         mProvider.setAudioFocusRequest_impl(focusGain);
@@ -287,6 +297,21 @@
     }
 
     /**
+     * Sets a remote player for handling playback of the selected route from MediaControlView2.
+     * If this is not called, MediaCotrolView2 will not show the route button.
+     *
+     * @param routeCategories        the list of media control categories in
+     *                               {@link android.support.v7.media.MediaControlIntent}
+     * @param player                 the player to handle the selected route. If null, a default
+     *                               route player will be used.
+     * @throws IllegalStateException if MediaControlView2 is not set.
+     */
+    public void setRouteAttributes(@NonNull List<String> routeCategories,
+            @Nullable MediaPlayerBase player) {
+        mProvider.setRouteAttributes_impl(routeCategories, player);
+    }
+
+    /**
      * Sets video path.
      *
      * @param path the path of the video.
@@ -399,6 +424,13 @@
     }
 
     /**
+     * Registers a callback to be invoked when the fullscreen mode should be changed.
+     */
+    public void setFullScreenChangedListener(OnFullScreenChangedListener l) {
+        mProvider.setFullScreenChangedListener_impl(l);
+    }
+
+    /**
      * Interface definition of a callback to be invoked when the viw type has been changed.
      */
     public interface OnViewTypeChangedListener {
@@ -466,6 +498,16 @@
         void onInfo(int what, int extra);
     }
 
+    /**
+     * Interface definition of a callback to be invoked to inform the fullscreen mode is changed.
+     */
+    public interface OnFullScreenChangedListener {
+        /**
+         * Called to indicate a fullscreen mode change.
+         */
+        void onFullScreenChanged(boolean fullScreen);
+    }
+
     @Override
     protected void onAttachedToWindow() {
         mProvider.onAttachedToWindow_impl();
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 02cd09f..43abade 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -31,13 +31,17 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ProcFileReader;
+import com.google.android.collect.Lists;
 
 import libcore.io.IoUtils;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.net.ProtocolException;
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -57,6 +61,8 @@
     // Used for correct stats accounting on clatd interfaces.
     private static final int IPV4V6_HEADER_DELTA = 20;
 
+    /** Path to {@code /proc/net/dev}. */
+    private final File mStatsIfaceDev;
     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
     private final File mStatsXtIfaceAll;
     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */
@@ -64,6 +70,8 @@
     /** Path to {@code /proc/net/xt_qtaguid/stats}. */
     private final File mStatsXtUid;
 
+    private boolean mUseBpfStats;
+
     // TODO: to improve testability and avoid global state, do not use a static variable.
     @GuardedBy("sStackedIfaces")
     private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>();
@@ -79,14 +87,54 @@
     }
 
     public NetworkStatsFactory() {
-        this(new File("/proc/"));
+        this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists());
     }
 
     @VisibleForTesting
-    public NetworkStatsFactory(File procRoot) {
+    public NetworkStatsFactory(File procRoot, boolean useBpfStats) {
+        mStatsIfaceDev = new File(procRoot, "net/dev");
         mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
+        mUseBpfStats = useBpfStats;
+    }
+
+    @VisibleForTesting
+    public NetworkStats readNetworkStatsIfaceDev() throws IOException {
+        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+
+        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
+        final NetworkStats.Entry entry = new NetworkStats.Entry();
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new FileReader(mStatsIfaceDev));
+
+            // skip first two header lines
+            reader.readLine();
+            reader.readLine();
+
+            // parse remaining lines
+            String line;
+            while ((line = reader.readLine()) != null) {
+                String[] values = line.trim().split("\\:?\\s+");
+                entry.iface = values[0];
+                entry.uid = UID_ALL;
+                entry.set = SET_ALL;
+                entry.tag = TAG_NONE;
+                entry.rxBytes = Long.parseLong(values[1]);
+                entry.rxPackets = Long.parseLong(values[2]);
+                entry.txBytes = Long.parseLong(values[9]);
+                entry.txPackets = Long.parseLong(values[10]);
+                stats.addValues(entry);
+            }
+        } catch (NullPointerException|NumberFormatException e) {
+            throw new ProtocolException("problem parsing stats", e);
+        } finally {
+            IoUtils.closeQuietly(reader);
+            StrictMode.setThreadPolicy(savedPolicy);
+        }
+        return stats;
     }
 
     /**
@@ -98,6 +146,11 @@
      * @throws IllegalStateException when problem parsing stats.
      */
     public NetworkStats readNetworkStatsSummaryDev() throws IOException {
+
+        // Return the stats get from /proc/net/dev if switched to bpf module.
+        if (mUseBpfStats)
+            return readNetworkStatsIfaceDev();
+
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
@@ -149,6 +202,11 @@
      * @throws IllegalStateException when problem parsing stats.
      */
     public NetworkStats readNetworkStatsSummaryXt() throws IOException {
+
+        // Return the stats get from /proc/net/dev if qtaguid  module is replaced.
+        if (mUseBpfStats)
+            return readNetworkStatsIfaceDev();
+
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
         // return null when kernel doesn't support
@@ -254,7 +312,7 @@
                 stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             }
             if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
-                    limitIfaces, limitTag) != 0) {
+                    limitIfaces, limitTag, mUseBpfStats) != 0) {
                 throw new IOException("Failed to parse network stats");
             }
             if (SANITY_CHECK_NATIVE) {
@@ -348,6 +406,6 @@
      * are expected to monotonically increase since device boot.
      */
     @VisibleForTesting
-    public static native int nativeReadNetworkStatsDetail(
-            NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag);
+    public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
+        int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index e097362a..f5af80a 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.Rect;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 
@@ -130,4 +131,15 @@
     void handleSystemKey(in int key);
 
     void showShutdownUi(boolean isReboot, String reason);
+
+    // Used to show the dialog when FingerprintService starts authentication
+    void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
+    // Used to hide the dialog when a finger is authenticated
+    void onFingerprintAuthenticated();
+    // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
+    void onFingerprintHelp(String message);
+    // Used to set a message - the dialog will dismiss after a certain amount of time
+    void onFingerprintError(String error);
+    // Used to hide the fingerprint dialog when the authenticationclient is stopped
+    void hideFingerprintDialog();
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 03603e4..cb0b53c 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -79,4 +80,15 @@
     void remTile(in ComponentName tile);
     void clickTile(in ComponentName tile);
     void handleSystemKey(in int key);
+
+    // Used to show the dialog when FingerprintService starts authentication
+    void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
+    // Used to hide the dialog when a finger is authenticated
+    void onFingerprintAuthenticated();
+    // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
+    void onFingerprintHelp(String message);
+    // Used to set a message - the dialog will dismiss after a certain amount of time
+    void onFingerprintError(String error);
+    // Used to hide the fingerprint dialog when the authenticationclient is stopped
+    void hideFingerprintDialog();
 }
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index f9da1eb..927d757 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -20,8 +20,8 @@
 import android.app.trust.IStrongAuthTracker;
 import android.os.Bundle;
 import android.security.keystore.recovery.WrappedApplicationKey;
-import android.security.keystore.recovery.KeychainSnapshot;
-import android.security.keystore.recovery.KeychainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyChainProtectionParams;
 import com.android.internal.widget.ICheckCredentialProgressCallback;
 import com.android.internal.widget.VerifyCredentialResponse;
 
@@ -64,7 +64,7 @@
     // {@code ServiceSpecificException} may be thrown to signal an error, which caller can
     // convert to  {@code RecoveryManagerException}.
     void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
-    KeychainSnapshot getRecoveryData(in byte[] account);
+    KeyChainSnapshot getRecoveryData(in byte[] account);
     byte[] generateAndStoreKey(String alias);
     void removeKey(String alias);
     void setSnapshotCreatedPendingIntent(in PendingIntent intent);
@@ -75,10 +75,10 @@
     void setRecoverySecretTypes(in int[] secretTypes);
     int[] getRecoverySecretTypes();
     int[] getPendingRecoverySecretTypes();
-    void recoverySecretAvailable(in KeychainProtectionParams recoverySecret);
+    void recoverySecretAvailable(in KeyChainProtectionParams recoverySecret);
     byte[] startRecoverySession(in String sessionId,
             in byte[] verifierPublicKey, in byte[] vaultParams, in byte[] vaultChallenge,
-            in List<KeychainProtectionParams> secrets);
+            in List<KeyChainProtectionParams> secrets);
     Map/*<String, byte[]>*/ recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
             in List<WrappedApplicationKey> applicationKeys);
     void closeSession(in String sessionId);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 543acc7..47765d9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -228,6 +228,8 @@
     ],
 
     shared_libs: [
+        "libbpf",
+        "libnetdutils",
         "libmemtrack",
         "libandroidfw",
         "libappfuse",
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index ec15cce..8b3ce66 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -18,6 +18,7 @@
 #include "ImageDecoder.h"
 #include "core_jni_helpers.h"
 
+#include <hwui/AnimatedImageDrawable.h>
 #include <hwui/Canvas.h>
 #include <SkAndroidCodec.h>
 #include <SkAnimatedImage.h>
@@ -27,10 +28,6 @@
 
 using namespace android;
 
-struct AnimatedImageDrawable {
-    sk_sp<SkAnimatedImage> mDrawable;
-    SkPaint                mPaint;
-};
 
 // Note: jpostProcess holds a handle to the ImageDecoder.
 static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -65,20 +62,22 @@
         picture = recorder.finishRecordingAsPicture();
     }
 
-    std::unique_ptr<AnimatedImageDrawable> drawable(new AnimatedImageDrawable);
-    drawable->mDrawable = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
-                scaledSize, subset, std::move(picture));
-    if (!drawable->mDrawable) {
+
+    sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
+                                                               scaledSize, subset,
+                                                               std::move(picture));
+    if (!animatedImg) {
         doThrowIOE(env, "Failed to create drawable");
         return 0;
     }
-    drawable->mDrawable->start();
 
+    sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(animatedImg));
+    drawable->start();
     return reinterpret_cast<jlong>(drawable.release());
 }
 
 static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) {
-    delete drawable;
+    SkSafeUnref(drawable);
 }
 
 static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
@@ -86,45 +85,43 @@
 }
 
 static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
-                                         jlong canvasPtr, jlong msecs) {
+                                         jlong canvasPtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    double timeToNextUpdate = drawable->mDrawable->update(msecs);
     auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    canvas->drawAnimatedImage(drawable->mDrawable.get(), 0, 0, &drawable->mPaint);
-    return (jlong) timeToNextUpdate;
+    return (jlong) canvas->drawAnimatedImage(drawable);
 }
 
 static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                             jint alpha) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    drawable->mPaint.setAlpha(alpha);
+    drawable->setStagingAlpha(alpha);
 }
 
 static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    return drawable->mPaint.getAlpha();
+    return drawable->getStagingAlpha();
 }
 
 static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                                   jlong nativeFilter) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
     auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter);
-    drawable->mPaint.setColorFilter(sk_ref_sp(filter));
+    drawable->setStagingColorFilter(sk_ref_sp(filter));
 }
 
 static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    return drawable->mDrawable->isRunning();
+    return drawable->isRunning();
 }
 
 static void AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    drawable->mDrawable->start();
+    drawable->start();
 }
 
 static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    drawable->mDrawable->stop();
+    drawable->stop();
 }
 
 static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
@@ -136,7 +133,7 @@
 static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
     { "nCreate",             "(JLandroid/graphics/ImageDecoder;IILandroid/graphics/Rect;)J", (void*) AnimatedImageDrawable_nCreate },
     { "nGetNativeFinalizer", "()J",                                                          (void*) AnimatedImageDrawable_nGetNativeFinalizer },
-    { "nDraw",               "(JJJ)J",                                                       (void*) AnimatedImageDrawable_nDraw },
+    { "nDraw",               "(JJ)J",                                                        (void*) AnimatedImageDrawable_nDraw },
     { "nSetAlpha",           "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetAlpha },
     { "nGetAlpha",           "(J)I",                                                         (void*) AnimatedImageDrawable_nGetAlpha },
     { "nSetColorFilter",     "(JJ)V",                                                        (void*) AnimatedImageDrawable_nSetColorFilter },
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index d254de6..99d9839 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -30,7 +30,14 @@
 
 #include <utils/Log.h>
 #include <utils/misc.h>
-#include <utils/Vector.h>
+
+#include "android-base/unique_fd.h"
+#include "bpf/BpfNetworkStats.h"
+#include "bpf/BpfUtils.h"
+
+using android::bpf::hasBpfSupport;
+using android::bpf::parseBpfNetworkStatsDetail;
+using android::bpf::stats_line;
 
 namespace android {
 
@@ -53,17 +60,6 @@
     jfieldID operations;
 } gNetworkStatsClassInfo;
 
-struct stats_line {
-    char iface[32];
-    int32_t uid;
-    int32_t set;
-    int32_t tag;
-    int64_t rxBytes;
-    int64_t rxPackets;
-    int64_t txBytes;
-    int64_t txPackets;
-};
-
 static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
 {
     if (!grow) {
@@ -97,33 +93,14 @@
     return env->NewLongArray(size);
 }
 
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
-        jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) {
-    ScopedUtfChars path8(env, path);
-    if (path8.c_str() == NULL) {
-        return -1;
-    }
-
-    FILE *fp = fopen(path8.c_str(), "r");
+static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
+                                        const std::vector<std::string>& limitIfaces,
+                                        int limitTag, int limitUid, const char* path) {
+    FILE* fp = fopen(path, "r");
     if (fp == NULL) {
         return -1;
     }
 
-    Vector<String8> limitIfaces;
-    if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
-        int num = env->GetArrayLength(limitIfacesObj);
-        limitIfaces.setCapacity(num);
-        for (int i=0; i<num; i++) {
-            jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
-            ScopedUtfChars string8(env, string);
-            if (string8.c_str() != NULL) {
-                limitIfaces.add(String8(string8.c_str()));
-            }
-        }
-    }
-
-    Vector<stats_line> lines;
-
     int lastIdx = 1;
     int idx;
     char buffer[384];
@@ -215,7 +192,7 @@
                 //ALOGI("skipping due to uid: %s", buffer);
                 continue;
             }
-            lines.push_back(s);
+            lines->push_back(s);
         } else {
             //ALOGI("skipping due to bad remaining fields: %s", pos);
         }
@@ -225,8 +202,42 @@
         ALOGE("Failed to close netstats file");
         return -1;
     }
+    return 0;
+}
+
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
+                                  jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
+                                  jboolean useBpfStats) {
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return -1;
+    }
+
+    std::vector<std::string> limitIfaces;
+    if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
+        int num = env->GetArrayLength(limitIfacesObj);
+        for (int i = 0; i < num; i++) {
+            jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
+            ScopedUtfChars string8(env, string);
+            if (string8.c_str() != NULL) {
+                limitIfaces.push_back(std::string(string8.c_str()));
+            }
+        }
+    }
+    std::vector<stats_line> lines;
+
+
+    if (useBpfStats) {
+        if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+            return -1;
+    } else {
+        if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
+                                         limitUid, path8.c_str()) < 0)
+            return -1;
+    }
 
     int size = lines.size();
+
     bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
 
     ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats,
@@ -303,7 +314,7 @@
 
 static const JNINativeMethod gMethods[] = {
         { "nativeReadNetworkStatsDetail",
-                "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
+                "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
                 (void*) readNetworkStatsDetail }
 };
 
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index 3412a32..03f8204 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -19,6 +19,7 @@
 package android.app;
 
 option java_multiple_files = true;
+option java_outer_classname = "ActivityManagerProto";
 
 // ActivityManager.java PROCESS_STATEs
 enum ProcessState {
@@ -79,3 +80,16 @@
   PROCESS_STATE_NONEXISTENT = 1900;
 }
 
+// ActivityManager.java UID_OBSERVERs flags
+enum UidObserverFlag {
+  // report changes in process state, original value is 1 << 0
+  UID_OBSERVER_FLAG_PROCSTATE = 1;
+  // report uid gone, original value is 1 << 1
+  UID_OBSERVER_FLAG_GONE = 2;
+  // report uid has become idle, original value is 1 << 2
+  UID_OBSERVER_FLAG_IDLE = 3;
+  // report uid has become active, original value is 1 << 3
+  UID_OBSERVER_FLAG_ACTIVE = 4;
+  // report uid cached state has changed, original value is 1 << 4
+  UID_OBSERVER_FLAG_CACHED = 5;
+}
diff --git a/core/proto/android/app/profilerinfo.proto b/core/proto/android/app/profilerinfo.proto
new file mode 100644
index 0000000..ca1b935
--- /dev/null
+++ b/core/proto/android/app/profilerinfo.proto
@@ -0,0 +1,33 @@
+/*
+ * 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";
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * An android.app.ProfilerInfo object.
+ */
+message ProfilerInfoProto {
+    optional string profile_file = 1;
+    optional int32 profile_fd = 2;
+    optional int32 sampling_interval = 3;
+    optional bool auto_stop_profiler = 4;
+    optional bool streaming_output = 5;
+    optional string agent = 6;
+}
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
new file mode 100644
index 0000000..8470159
--- /dev/null
+++ b/core/proto/android/content/package_item_info.proto
@@ -0,0 +1,82 @@
+/*
+ * 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";
+option java_package = "android.content.pm";
+option java_multiple_files = true;
+
+package android.content.pm;
+
+message PackageItemInfoProto {
+    optional string name = 1;
+    optional string package_name = 2;
+    optional int32 label_res = 3;
+    optional string non_localized_label = 4;
+    optional int32 icon = 5;
+    optional int32 banner = 6;
+}
+
+// Proto of android.content.pm.ApplicationInfo which extends PackageItemInfo
+message ApplicationInfoProto {
+    optional PackageItemInfoProto package = 1;
+    optional string permission = 2;
+    optional string process_name = 3;
+    optional int32 uid = 4;
+    optional int32 flags = 5;
+    optional int32 private_flags = 6;
+    optional int32 theme = 7;
+    optional string source_dir = 8;
+    optional string public_source_dir = 9;
+    repeated string split_source_dirs = 10;
+    repeated string split_public_source_dirs = 11;
+    repeated string resource_dirs = 12;
+    optional string data_dir = 13;
+    optional string class_loader_name = 14;
+    repeated string split_class_loader_names = 15;
+
+    message Version {
+        optional bool enabled = 1;
+        optional int32 min_sdk_version = 2;
+        optional int32 target_sdk_version = 3;
+        optional int32 version_code = 4;
+        optional int32 target_sandbox_version = 5;
+    }
+    optional Version version = 16;
+
+    message Detail {
+        optional string class_name = 1;
+        optional string task_affinity = 2;
+        optional int32 requires_smallest_width_dp = 3;
+        optional int32 compatible_width_limit_dp = 4;
+        optional int32 largest_width_limit_dp = 5;
+        optional string seinfo = 6;
+        optional string seinfo_user = 7;
+        optional string device_protected_data_dir = 8;
+        optional string credential_protected_data_dir = 9;
+        repeated string shared_library_files = 10;
+        optional string manage_space_activity_name = 11;
+        optional int32 description_res = 12;
+        optional int32 ui_options = 13;
+        optional bool supports_rtl = 14;
+        oneof full_backup_content {
+            string content = 15;
+            bool is_full_backup = 16;
+        }
+        optional int32 networkSecurity_config_res = 17;
+        optional int32 category = 18;
+    }
+    optional Detail detail = 17;
+}
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 331f80f..ce1d5c9 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -22,8 +22,11 @@
 import "frameworks/base/core/proto/android/app/jobparameters.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
 import "frameworks/base/core/proto/android/telephony/signalstrength.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message BatteryStatsProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 report_version = 1;
   optional int64 parcel_version = 2;
   optional string start_platform_version = 3;
@@ -33,6 +36,8 @@
 }
 
 message ControllerActivityProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // Time (milliseconds) spent in the idle state.
   optional int64 idle_duration_ms = 1;
   // Time (milliseconds) spent in the receive state.
@@ -45,6 +50,8 @@
   // of power. The levels themselves are controller-specific (and may possibly
   // be device specific...yet to be confirmed).
   message TxLevel {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Transmit level. Higher levels draw more power.
     optional int32 level = 1;
     // Time spent in this specific transmit level state.
@@ -54,7 +61,11 @@
 }
 
 message SystemProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   message Battery {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Wall clock time when the data collection started.
     // In case of device time manually reset by users:
     //   start_clock_time_ms keeps the same value in the current collection
@@ -92,6 +103,8 @@
   optional Battery battery = 1;
 
   message BatteryDischarge {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Discharged battery percentage points since the stats were last reset
     // after charging (lower bound approximation).
     optional int32 lower_bound_since_charge = 1;
@@ -142,6 +155,8 @@
   // the entire duration. Field for which the conditions were not consistent
   // for the entire duration should be marked MIXED.
   message BatteryLevelStep {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // How long the battery was at the current level.
     optional int64 duration_ms = 1;
     // Battery level
@@ -192,6 +207,8 @@
   repeated int64 cpu_frequency = 7;
 
   message DataConnection {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Name {
       NONE = 0;
       GPRS = 1;
@@ -221,6 +238,8 @@
   optional ControllerActivityProto global_wifi_controller = 11;
 
   message GlobalNetwork {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Total Bytes received on mobile connections.
     optional int64 mobile_bytes_rx = 1;
     // Total Bytes transmitted on mobile connections.
@@ -245,6 +264,8 @@
   optional GlobalNetwork global_network = 12;
 
   message GlobalWifi {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // The amount of time that wifi has been on while the device was running on
     // battery.
     optional int64 on_duration_ms = 1;
@@ -257,6 +278,8 @@
   // Kernel wakelock metrics are only recorded when the device is unplugged
   // *and* the screen is off.
   message KernelWakelock {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     // Kernel wakelock stats aren't apportioned across all kernel wakelocks (as
     // app wakelocks stats are).
@@ -267,6 +290,8 @@
   repeated KernelWakelock kernel_wakelock = 14;
 
   message Misc {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 screen_on_duration_ms = 1;
     optional int64 phone_on_duration_ms = 2;
     optional int64 full_wakelock_total_duration_ms = 3;
@@ -312,12 +337,16 @@
   optional Misc misc = 15;
 
   message PhoneSignalStrength {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional android.telephony.SignalStrengthProto.StrengthName name = 1;
     optional TimerProto total = 2;
   };
   repeated PhoneSignalStrength phone_signal_strength = 16;
 
   message PowerUseItem {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Sipper {
       UNKNOWN_SIPPER = 0;
       IDLE = 1;
@@ -352,6 +381,8 @@
   repeated PowerUseItem power_use_item = 17;
 
   message PowerUseSummary {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional double battery_capacity_mah = 1;
     optional double computed_power_mah = 2;
     // Lower bound of actual power drained.
@@ -362,6 +393,8 @@
   optional PowerUseSummary power_use_summary = 18;
 
   message ResourcePowerManager {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Either StateName or StateName.VoterName.
     optional string name = 1;
     optional TimerProto total = 2;
@@ -370,6 +403,8 @@
   repeated ResourcePowerManager resource_power_manager = 19;
 
   message ScreenBrightness {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Name {
       DARK = 0; // Not screen-off.
       DIM = 1;
@@ -386,18 +421,24 @@
   optional TimerProto signal_scanning = 21;
 
   message WakeupReason {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     optional TimerProto total = 2;
   };
   repeated WakeupReason wakeup_reason = 22;
 
   message WifiMulticastWakelockTotal {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 duration_ms = 1;
     optional int32 count = 2;
   }
   optional WifiMulticastWakelockTotal wifi_multicast_wakelock_total = 23;
 
   message WifiSignalStrength {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Name {
       NONE = 0;
       POOR = 1;
@@ -411,6 +452,8 @@
   repeated WifiSignalStrength wifi_signal_strength = 24;
 
   message WifiState {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Name {
       OFF = 0;
       OFF_SCANNING = 1;
@@ -427,6 +470,8 @@
   repeated WifiState wifi_state = 25;
 
   message WifiSupplicantState {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Name {
       INVALID = 0;
       DISCONNECTED = 1;
@@ -449,6 +494,8 @@
 }
 
 message TimerProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // This may be an apportioned time.
   optional int64 duration_ms = 1;
   optional int64 count = 2;
@@ -468,14 +515,20 @@
 }
 
 message UidProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // Combination of app ID and user ID.
   optional int32 uid = 1;
 
   // The statistics associated with a particular package.
   message Package {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
 
     message Service {
+      option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional string name = 1;
       // Time spent started.
       optional int64 start_duration_ms = 2;
@@ -492,6 +545,8 @@
 
   // Bluetooth misc data.
   message BluetoothMisc {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Duration spent BLE scanning blamed on this App (i.e. apportioned to this
     // app amongst all apps doing BLE scanning; see explanation of 'apportioned'
     // in App's comment).
@@ -515,6 +570,8 @@
   optional BluetoothMisc bluetooth_misc = 6;
 
   message Cpu {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Total CPU time with processes executing in userspace. Summed up across
     // multiple cores.
     optional int64 user_duration_ms = 1;
@@ -529,6 +586,8 @@
     // system_duration_millis, which are just approximations. Data is not
     // tracked when device is charging.
     message ByFrequency {
+      option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
       // Index of the frequency in system.cpu_frequency. It starts from 1, to
       // make it easier to analyze.
       optional int32 frequency_index = 1;
@@ -551,6 +610,8 @@
     }
     // CPU times at different process states.
     message ByProcessState {
+      option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional ProcessState process_state = 1;
       repeated ByFrequency by_frequency = 2;
     }
@@ -574,7 +635,11 @@
   optional TimerProto video = 14;
 
   message Job {
-    optional string name = 1;
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string name = 1 [
+        (android.privacy).dest = DEST_EXPLICIT
+    ];
     // Job times aren't apportioned.
     optional TimerProto total = 2;
     optional TimerProto background = 3;
@@ -582,10 +647,16 @@
   repeated Job jobs = 15;
 
   message JobCompletion {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Job name.
-    optional string name = 1;
+    optional string name = 1 [
+        (android.privacy).dest = DEST_EXPLICIT
+    ];
 
     message ReasonCount {
+      option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
       optional android.app.JobParametersProto.CancelReason name = 1;
       optional int32 count = 2;
     }
@@ -594,6 +665,8 @@
   repeated JobCompletion job_completion = 16;
 
   message Network {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Mobile data traffic (total, background + foreground).
     optional int64 mobile_bytes_rx = 1;
     optional int64 mobile_bytes_tx = 2;
@@ -631,6 +704,8 @@
 
   // TODO: combine System and App messages?
   message PowerUseItem {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Estimated power use in mAh.
     optional double computed_power_mah = 1;
     // Starting in Oreo, Battery Settings has two modes to display the battery
@@ -648,6 +723,8 @@
 
   // Durations are not pooled/apportioned.
   message Process {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string name = 1;
     // Time spent executing in user code.
     optional int64 user_duration_ms = 2;
@@ -665,6 +742,8 @@
   repeated Process process = 19;
 
   message StateTime {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // All of these (non-deprecated) states are mutually exclusive and can be
     // added together to find the total time a uid has had any processes running
     // at all.
@@ -706,6 +785,8 @@
   repeated StateTime states = 20;
 
   message Sensor {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 id = 1;
     optional TimerProto apportioned = 2;
     // Background times aren't apportioned.
@@ -714,7 +795,11 @@
   repeated Sensor sensors = 21;
 
   message Sync {
-    optional string name = 1;
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string name = 1 [
+        (android.privacy).dest = DEST_EXPLICIT
+    ];
     // Sync times aren't apportioned.
     optional TimerProto total = 2;
     optional TimerProto background = 3;
@@ -722,6 +807,8 @@
   repeated Sync syncs = 22;
 
   message UserActivity {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional android.os.PowerManagerProto.UserActivityEvent name = 1;
     optional int32 count = 2;
   };
@@ -736,6 +823,8 @@
   // wakelocks. AggregatedWakelock, on the other hand, holds overall per-app
   // wakelock data.
   message AggregatedWakelock {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // The total duration that the app spent holding partial wakelocks.
     // It includes both foreground + background use.
     optional int64 partial_duration_ms = 1;
@@ -747,7 +836,11 @@
   optional AggregatedWakelock aggregated_wakelock = 24;
 
   message Wakelock {
-    optional string name = 1;
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string name = 1 [
+        (android.privacy).dest = DEST_EXPLICIT
+    ];
 
     // Full wakelocks keep the screen on. Based on
     // PowerManager.SCREEN_BRIGHT_WAKE_LOCK (deprecated in API 13) and
@@ -776,14 +869,20 @@
   repeated Wakelock wakelocks = 25;
 
   message WakeupAlarm {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Wakeup alarm name.
-    optional string name = 1;
+    optional string name = 1 [
+        (android.privacy).dest = DEST_EXPLICIT
+    ];
     // Only includes counts when screen-off (& on battery).
     optional int32 count = 2;
   }
   repeated WakeupAlarm wakeup_alarm = 26;
 
   message Wifi {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Duration holding Wifi-lock. This time is apportioned.
     optional int64 full_wifi_lock_duration_ms = 1;
     // Duration running Wifi. This time is apportioned.
diff --git a/core/proto/android/os/batterytype.proto b/core/proto/android/os/batterytype.proto
index 75d0dd3..2388c1e 100644
--- a/core/proto/android/os/batterytype.proto
+++ b/core/proto/android/os/batterytype.proto
@@ -20,6 +20,10 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 message BatteryTypeProto {
-   optional string type = 1;
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string type = 1;
 }
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index e5efb90..828a55f 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -226,7 +226,10 @@
         (section).args = "activity --proto service"
     ];
 
-    optional com.android.server.am.proto.ProcessProto amprocesses = 3015;
+    optional com.android.server.am.proto.ProcessesProto amprocesses = 3015 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "activity --proto processes"
+    ];
 
     optional com.android.server.AlarmManagerServiceProto alarm = 3016 [
         (section).type = SECTION_DUMPSYS,
diff --git a/core/proto/android/os/powermanager.proto b/core/proto/android/os/powermanager.proto
index e9f409d..8e0a607 100644
--- a/core/proto/android/os/powermanager.proto
+++ b/core/proto/android/os/powermanager.proto
@@ -19,6 +19,8 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/core/proto/android/os/worksource.proto";
+
 message PowerManagerProto {
     /* User activity events in PowerManager.java. */
     enum UserActivityEvent {
@@ -85,6 +87,14 @@
         // the dozing state.
         DRAW_WAKE_LOCK = 128;
     }
+
+    // WakeLock class in android.os.PowerManager, it is the one used by sdk
+    message WakeLockProto {
+        optional string hex_string = 1;
+        optional bool held = 2;
+        optional int32 internal_count = 3;
+        optional WorkSourceProto work_source = 4;
+    }
 }
 
 message PowerManagerInternalProto {
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index d3ca496..1434d82 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -18,11 +18,17 @@
 
 package com.android.server.am.proto;
 
+import "frameworks/base/core/proto/android/app/activitymanager.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";
+import "frameworks/base/core/proto/android/content/configuration.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
+import "frameworks/base/core/proto/android/content/package_item_info.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/internal/processstats.proto";
 import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/os/powermanager.proto";
 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";
@@ -36,7 +42,7 @@
 
   optional ActiveServicesProto services = 3;
 
-  optional ProcessProto processes = 4;
+  optional ProcessesProto processes = 4;
 }
 
 // "dumpsys activity --proto activities"
@@ -130,6 +136,7 @@
   optional int32 user_id = 4;
   optional int32 app_id = 5;
   optional int32 isolated_app_id = 6;
+  optional bool persistent = 7;
 }
 
 message BroadcastRecordProto {
@@ -459,7 +466,7 @@
     WAIVE_PRIORITY = 6;
     IMPORTANT = 7;
     ADJUST_WITH_ACTIVITY = 8;
-    FG_SERVICE_WHILE_WAKE = 9;
+    FG_SERVICE_WHILE_AWAKE = 9;
     FG_SERVICE = 10;
     TREAT_LIKE_ACTIVITY = 11;
     VISIBLE = 12;
@@ -492,5 +499,362 @@
 }
 
 // TODO: "dumpsys activity --proto processes"
-message ProcessProto {
+message ProcessesProto {
+  repeated ProcessRecordProto procs = 1;
+  repeated ProcessRecordProto isolated_procs = 2;
+  repeated ActiveInstrumentationProto active_instrumentations = 3;
+  repeated UidRecordProto active_uids = 4;
+  repeated UidRecordProto validate_uids = 5;
+
+  // Process LRU list (sorted by oom_adj)
+  message LruProcesses {
+    optional int32 size = 1;
+    optional int32 non_act_at = 2;
+    optional int32 non_svc_at = 3;
+    repeated ProcessOomProto list = 4;
+  }
+  optional LruProcesses lru_procs = 6;
+  repeated ProcessRecordProto pids_self_locked = 7;
+  // Foreground Processes
+  repeated ImportanceTokenProto important_procs = 8;
+  // Persisent processes that are starting
+  repeated ProcessRecordProto persistent_starting_procs = 9;
+  // Processes that are being removed
+  repeated ProcessRecordProto removed_procs = 10;
+  // Processes that are on old until the system is ready
+  repeated ProcessRecordProto on_hold_procs = 11;
+  // Processes that are waiting to GC
+  repeated ProcessToGcProto gc_procs = 12;
+  optional AppErrorsProto app_errors = 13;
+  optional UserControllerProto user_controller = 14;
+  optional ProcessRecordProto home_proc = 15;
+  optional ProcessRecordProto previous_proc = 16;
+  optional int64 previous_proc_visible_time_ms = 17;
+  optional ProcessRecordProto heavy_weight_proc = 18;
+  optional .android.content.ConfigurationProto global_configuration = 19;
+  // ActivityStackSupervisorProto dumps these values as well, still here?
+  // repeated ActivityDisplayProto displays = 20;
+
+  optional bool config_will_change = 21;
+
+  message ScreenCompatPackage {
+    optional string package = 1;
+    optional int32 mode = 2;
+  }
+  repeated ScreenCompatPackage screen_compat_packages = 22;
+
+  message UidObserverRegistrationProto {
+    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 {
+      optional int32 uid = 1;
+      optional int32 state = 2;
+    }
+    repeated ProcState last_proc_states = 5;
+  }
+  repeated UidObserverRegistrationProto uid_observers = 23;
+  repeated int32 device_idle_whitelist = 24;
+  repeated int32 device_idle_temp_whitelist = 25;
+
+  message PendingTempWhitelist {
+    optional int32 target_uid = 1;
+    optional int64 duration_ms = 2;
+    optional string tag = 3;
+  }
+  repeated PendingTempWhitelist pending_temp_whitelist = 26;
+
+  message SleepStatus {
+    optional .android.os.PowerManagerInternalProto.Wakefulness wakefulness = 1;
+    repeated string sleep_tokens = 2;
+    optional bool sleeping = 3;
+    optional bool shutting_down = 4;
+    optional bool test_pss_mode = 5;
+  }
+  optional SleepStatus sleep_status = 27;
+
+  message VoiceProto {
+    optional string session = 1;
+    optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2;
+  }
+  optional VoiceProto running_voice = 28;
+
+  message VrControllerProto {
+    enum VrMode {
+      FLAG_NON_VR_MODE = 0;
+      FLAG_VR_MODE = 1;
+      FLAG_PERSISTENT_VR_MODE = 2;
+    }
+    repeated VrMode vr_mode = 1;
+    optional int32 render_thread_id = 2;
+  }
+  optional VrControllerProto vr_controller = 29;
+
+  message DebugApp {
+    optional string debug_app = 1;
+    optional string orig_debug_app = 2;
+    optional bool debug_transient = 3;
+    optional bool orig_wait_for_debugger = 4;
+  }
+  optional DebugApp debug = 30;
+  optional AppTimeTrackerProto current_tracker = 31;
+
+  message MemWatchProcess {
+    message Process {
+      optional string name = 1;
+
+      message MemStats {
+        optional int32 uid = 1;
+        optional string size = 2;
+        optional string report_to = 3;
+      }
+      repeated MemStats mem_stats = 2;
+    }
+    repeated Process procs = 1;
+
+    message Dump {
+      optional string proc_name = 1;
+      optional string file = 2;
+      optional int32 pid = 3;
+      optional int32 uid = 4;
+    }
+    optional Dump dump = 2;
+  }
+  optional MemWatchProcess mem_watch_processes = 32;
+  optional string track_allocation_app = 33;
+
+  message Profile {
+    optional string app_name = 1;
+    optional ProcessRecordProto proc = 2;
+    optional .android.app.ProfilerInfoProto info = 3;
+    optional int32 type = 4;
+  }
+  optional Profile profile = 34;
+  optional string native_debugging_app = 35;
+  optional bool always_finish_activities = 36;
+
+  message Controller {
+    optional string controller = 1;
+    optional bool is_a_monkey = 2;
+  }
+  optional Controller controller = 37;
+
+  optional int32 total_persistent_procs = 38;
+  optional bool processes_ready = 39;
+  optional bool system_ready = 40;
+  optional bool booted = 41;
+  optional int32 factory_test = 42;
+  optional bool booting = 43;
+  optional bool call_finish_booting = 44;
+  optional bool boot_animation_complete = 45;
+  optional int64 last_power_check_uptime_ms = 46;
+  optional .android.os.PowerManagerProto.WakeLockProto going_to_sleep = 47;
+  optional .android.os.PowerManagerProto.WakeLockProto launching_activity = 48;
+  optional int32 adj_seq = 49;
+  optional int32 lru_seq = 50;
+  optional int32 num_non_cached_procs = 51;
+  optional int32 num_cached_hidden_procs = 52;
+  optional int32 num_service_procs = 53;
+  optional int32 new_num_service_procs = 54;
+  optional bool allow_lower_mem_level = 55;
+  optional int32 last_memory_level = 56;
+  optional int32 last_num_processes = 57;
+  optional .android.util.Duration last_idle_time = 58;
+  optional int64 low_ram_since_last_idle_ms = 59;
+}
+
+message ActiveInstrumentationProto {
+  optional .android.content.ComponentNameProto class = 1;
+  optional bool finished = 2;
+  repeated ProcessRecordProto running_processes = 3;
+  repeated string target_processes = 4;
+  optional .android.content.pm.ApplicationInfoProto target_info = 5;
+  optional string profile_file = 6;
+  optional string watcher = 7;
+  optional string ui_automation_connection = 8;
+  optional string arguments = 9;
+}
+
+// Proto definition of com.android.server.am.UidRecord.java
+message UidRecordProto {
+  optional string hex_hash = 1;
+  optional int32 uid = 2;
+  optional .android.app.ProcessState current = 3;
+  optional bool ephemeral = 4;
+  optional bool fg_services = 5;
+  optional bool whilelist = 6;
+  optional .android.util.Duration last_background_time = 7;
+  optional bool idle = 8;
+
+  enum Change {
+    CHANGE_GONE = 0;
+    CHANGE_IDLE = 1;
+    CHANGE_ACTIVE = 2;
+    CHANGE_CACHED = 3;
+    CHANGE_UNCACHED = 4;
+  }
+  repeated Change last_reported_changes = 9;
+  optional int32 num_procs = 10;
+
+  message ProcStateSequence {
+    optional int64 cururent = 1;
+    optional int64 last_network_updated = 2;
+    optional int64 last_dispatched = 3;
+  }
+  optional ProcStateSequence network_state_update = 11;
+}
+
+// proto of class ImportanceToken in ActivityManagerService
+message ImportanceTokenProto {
+  optional int32 pid = 1;
+  optional string token = 2;
+  optional string reason = 3;
+}
+
+message ProcessOomProto {
+  optional bool persistent = 1;
+  optional int32 num = 2;
+  optional string oom_adj = 3;
+
+  // Activity manager's version of Process enum, see ProcessList.java
+  enum SchedGroup {
+    SCHED_GROUP_UNKNOWN = -1;
+    SCHED_GROUP_BACKGROUND = 0;
+    SCHED_GROUP_DEFAULT = 1;
+    SCHED_GROUP_TOP_APP = 2;
+    SCHED_GROUP_TOP_APP_BOUND = 3;
+  }
+  optional SchedGroup sched_group = 4 [ default = SCHED_GROUP_UNKNOWN];
+
+  oneof Foreground {
+    bool activities = 5;
+    bool services = 6;
+  }
+
+  optional .android.app.ProcessState state = 7;
+  optional int32 trim_memory_level = 8;
+  optional ProcessRecordProto proc = 9;
+  optional string adj_type = 10;
+
+  oneof AdjTarget {
+    .android.content.ComponentNameProto adj_target_component_name = 11;
+    string adj_target_object = 12;
+  }
+
+  oneof AdjSource {
+    ProcessRecordProto adj_source_proc = 13;
+    string adj_source_object = 14;
+  }
+
+  message Detail {
+    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 string last_pss = 9;
+    optional string last_swap_pss = 10;
+    optional string last_cached_pss = 11;
+    optional bool cached = 12;
+    optional bool empty = 13;
+    optional bool has_above_client = 14;
+
+    // only make sense if process is a service
+    message CpuRunTime {
+      optional int64 over_ms = 1;
+      optional int64 used_ms = 2;
+      optional float ultilization = 3; // ratio of cpu time usage
+    }
+    optional CpuRunTime service_run_time = 15;
+  }
+  optional Detail detail = 15;
+}
+
+message ProcessToGcProto {
+  optional ProcessRecordProto proc = 1;
+  optional bool report_low_memory = 2;
+  optional int64 now_uptime_ms = 3;
+  optional int64 last_gced_ms = 4;
+  optional int64 last_low_memory_ms = 5;
+}
+
+// sync with com.android.server.am.AppErrors.java
+message AppErrorsProto {
+
+  optional int64 now_uptime_ms = 1;
+
+  message ProcessCrashTime {
+    optional string process_name = 1;
+
+    message Entry {
+      optional int32 uid = 1;
+      optional int64 last_crashed_at_ms = 2;
+    }
+    repeated Entry entries = 2;
+  }
+  repeated ProcessCrashTime process_crash_times = 2;
+
+  message BadProcess {
+    optional string process_name = 1;
+
+    message Entry {
+      optional int32 uid = 1;
+      optional int64 crashed_at_ms = 2;
+      optional string short_msg = 3;
+      optional string long_msg = 4;
+      optional string stack = 5;
+    }
+    repeated Entry entries = 2;
+  }
+  repeated BadProcess bad_processes = 3;
+}
+
+// sync with com.android.server.am.UserState.java
+message UserStateProto {
+  enum State {
+    STATE_BOOTING = 0;
+    STATE_RUNNING_LOCKED = 1;
+    STATE_RUNNING_UNLOCKING = 2;
+    STATE_RUNNING_UNLOCKED = 3;
+    STATE_STOPPING = 4;
+    STATE_SHUTDOWN = 5;
+  }
+  optional State state = 1;
+  optional bool switching = 2;
+}
+
+// sync with com.android.server.am.UserController.java
+message UserControllerProto {
+  message User {
+    optional int32 id = 1;
+    optional UserStateProto state = 2;
+  }
+  repeated User started_users = 1;
+  repeated int32 started_user_array = 2;
+  repeated int32 user_lru = 3;
+
+  message UserProfile {
+    optional int32 user = 1;
+    optional int32 profile = 2;
+  }
+  repeated UserProfile user_profile_group_ids = 4;
+}
+
+// sync with com.android.server.am.AppTimeTracker.java
+message AppTimeTrackerProto {
+  optional string receiver = 1;
+  optional int64 total_duration_ms = 2;
+
+  message PackageTime {
+    optional string package = 1;
+    optional int64 duration_ms = 2;
+  }
+  repeated PackageTime package_times = 3;
+
+  optional .android.util.Duration started_time = 4;
+  optional string started_package = 5;
 }
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index f72ca62..739fca3 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -558,4 +558,6 @@
 
     optional int64 last_successful_run_time = 22;
     optional int64 last_failed_run_time = 23;
+
+    optional int64 internal_flags = 24;
 }
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
index 4cb7fd3..42fa72c 100644
--- a/core/proto/android/service/battery.proto
+++ b/core/proto/android/service/battery.proto
@@ -21,8 +21,11 @@
 option java_outer_classname = "BatteryServiceProto";
 
 import "frameworks/base/core/proto/android/os/batterymanager.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message BatteryServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum BatteryStatus {
         BATTERY_STATUS_INVALID = 0;
         BATTERY_STATUS_UNKNOWN = 1;
diff --git a/core/proto/android/service/batterystats.proto b/core/proto/android/service/batterystats.proto
index 54d3f40..e31e7f3 100644
--- a/core/proto/android/service/batterystats.proto
+++ b/core/proto/android/service/batterystats.proto
@@ -21,7 +21,10 @@
 option java_outer_classname = "BatteryStatsServiceProto";
 
 import "frameworks/base/core/proto/android/os/batterystats.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message BatteryStatsServiceDumpProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional android.os.BatteryStatsProto batterystats = 1;
 }
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 7a0e152..65df89a 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -24,6 +24,7 @@
 import "frameworks/base/core/proto/android/app/notification_channel_group.proto";
 import "frameworks/base/core/proto/android/app/notificationmanager.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
+import "frameworks/base/core/proto/android/media/audioattributes.proto";
 
 message NotificationServiceDumpProto {
     repeated NotificationRecordProto records = 1;
@@ -55,7 +56,7 @@
     optional int32 flags = 3;
     optional string channelId = 4;
     optional string sound = 5;
-    optional int32 sound_usage = 6;
+    optional .android.media.AudioAttributesProto audio_attributes = 6;
     optional bool can_vibrate = 7;
     optional bool can_show_light = 8;
     optional string group_key = 9;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 93d852c..d095641 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -327,6 +327,10 @@
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" />
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" />
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE" />
+    <protected-broadcast android:name="com.android.server.wifi.wakeup.DISMISS_NOTIFICATION" />
+    <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES" />
+    <protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS" />
+    <protected-broadcast android:name="com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
@@ -510,6 +514,7 @@
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
+    <protected-broadcast android:name="android.app.action.APP_BLOCK_STATE_CHANGED" />
 
     <protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
     <protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index 435289d..19c4d23 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -57,7 +57,7 @@
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"
-                android:textSize="20sp"
+                android:textSize="24sp"
                 android:textColor="#ffffffff"
             />
             <TextView android:id="@+id/text"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4d80b2f..354d658 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1897,6 +1897,7 @@
         <enum name="KEYCODE_SYSTEM_NAVIGATION_LEFT" value="282" />
         <enum name="KEYCODE_SYSTEM_NAVIGATION_RIGHT" value="283" />
         <enum name="KEYCODE_ALL_APPS" value="284" />
+        <enum name="KEYCODE_REFRESH" value="285" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9cab9fa..4119cdc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -650,11 +650,11 @@
     <!-- Label for the Android system components when they are shown to the user. -->
     <string name="android_system_label">Android System</string>
 
-    <!-- Label for the user owner in the intent forwarding app. -->
-    <string name="user_owner_label">Switch to Personal</string>
+    <!-- "Switch" is a verb; it means to change user profile by tapping another user profile name. -->
+    <string name="user_owner_label">Switch to personal profile</string>
 
-    <!-- Label for a corporate profile in the intent forwarding app. -->
-    <string name="managed_profile_label">Switch to Work</string>
+    <!-- "Switch" is a verb; it means to change user profile by tapping another user profile name. -->
+    <string name="managed_profile_label">Switch to work profile</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_contacts">Contacts</string>
@@ -1321,6 +1321,9 @@
     <string-array name="fingerprint_acquired_vendor">
     </string-array>
 
+    <!-- Message shown by the fingerprint dialog when fingerprint is not recognized -->
+    <string name="fingerprint_not_recognized">Not recognized</string>
+
     <!-- Error message shown when the fingerprint hardware can't be accessed -->
     <string name="fingerprint_error_hw_not_available">Fingerprint hardware not available.</string>
     <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
@@ -1329,6 +1332,8 @@
     <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
     <!-- Generic error message shown when the fingerprint operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user-->
     <string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
+    <!-- Generic error message shown when the fingerprint authentication operation is canceled due to user input. Generally not shown to the user -->
+    <string name="fingerprint_error_user_canceled">Fingerprint operation canceled by user.</string>
     <!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
     <string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
     <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
@@ -4604,11 +4609,10 @@
     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
     <string name="locale_search_menu">Search</string>
 
-    <!-- Title for dialog displayed when work profile is turned off. [CHAR LIMIT=30] -->
-    <string name="work_mode_off_title">Turn on work mode?</string>
-    <!-- Message displayed in dialog when work profile is turned off. [CHAR LIMIT=NONE] -->
-    <string name="work_mode_off_message">This will turn on your work profile, including apps,
-        background sync, and related features</string>
+    <!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] -->
+    <string name="work_mode_off_title">Turn on work profile?</string>
+    <!-- Text in a dialog. This string describes what will happen if a user decides to turn on their work profile. "Work profile" is used as an adjective. [CHAR LIMIT=NONE] -->
+    <string name="work_mode_off_message">Your work apps, notifications, data, and other work profile features will be turned on</string>
     <!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] -->
     <string name="work_mode_turn_on">Turn on</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4ef0a6c..1711ec9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2341,9 +2341,11 @@
   <java-symbol type="string" name="fingerprint_acquired_too_fast" />
   <java-symbol type="array" name="fingerprint_acquired_vendor" />
   <java-symbol type="string" name="fingerprint_error_canceled" />
+  <java-symbol type="string" name="fingerprint_error_user_canceled" />
   <java-symbol type="string" name="fingerprint_error_lockout" />
   <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
   <java-symbol type="string" name="fingerprint_name_template" />
+  <java-symbol type="string" name="fingerprint_not_recognized" />
 
   <!-- Fingerprint config -->
   <java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
diff --git a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
index e62fbd6..c213464 100644
--- a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
+++ b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
@@ -53,7 +53,7 @@
                     stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL,
                     // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70
                     // Fixed compilation problem but needs addressing properly.
-                    new String[0], 999);
+                    new String[0], 999, false);
         }
     }
 }
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 47990a1..60b46b4 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -53,6 +53,10 @@
     android.test.base \
     android.test.mock \
 
+ifeq ($(REMOVE_OAHL_FROM_BCP),true)
+LOCAL_JAVA_LIBRARIES += framework-oahl-backward-compatibility
+endif
+
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
index 63a5e4c..6996e50 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -73,9 +73,13 @@
     public void targeted_at_O() {
         mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
-        assertEquals("usesLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY),
-                mPackage.usesLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            assertEquals("usesLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY),
+                    mPackage.usesLibraries);
+        } else {
+            assertNull("usesOptionalLibraries not updated correctly", mPackage.usesLibraries);
+        }
         assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
     }
 
@@ -84,10 +88,16 @@
         mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
         mPackage.usesLibraries = arrayList(OTHER_LIBRARY);
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
-        // The org.apache.http.legacy jar should be added at the start of the list.
-        assertEquals("usesLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY),
-                mPackage.usesLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            // The org.apache.http.legacy jar should be added at the start of the list.
+            assertEquals("usesLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY),
+                    mPackage.usesLibraries);
+        } else {
+            assertEquals("usesLibraries not updated correctly",
+                    arrayList(OTHER_LIBRARY),
+                    mPackage.usesLibraries);
+        }
         assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
     }
 
@@ -96,9 +106,13 @@
         mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
         mPackage.usesLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
-        assertEquals("usesLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY),
-                mPackage.usesLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            assertEquals("usesLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY),
+                    mPackage.usesLibraries);
+        } else {
+            assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
+        }
         assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
     }
 
@@ -108,18 +122,27 @@
         mPackage.usesOptionalLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
         assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
-        assertEquals("usesOptionalLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY),
-                mPackage.usesOptionalLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            assertEquals("usesOptionalLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY),
+                    mPackage.usesOptionalLibraries);
+        } else {
+            assertNull("usesOptionalLibraries not updated correctly",
+                    mPackage.usesOptionalLibraries);
+        }
     }
 
     @Test
     public void org_apache_http_legacy_in_usesLibraries() {
         mPackage.usesLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
-        assertEquals("usesLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY),
-                mPackage.usesLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            assertEquals("usesLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY),
+                    mPackage.usesLibraries);
+        } else {
+            assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
+        }
         assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
     }
 
@@ -128,9 +151,14 @@
         mPackage.usesOptionalLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
         PackageBackwardCompatibility.modifySharedLibraries(mPackage);
         assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
-        assertEquals("usesOptionalLibraries not updated correctly",
-                arrayList(ORG_APACHE_HTTP_LEGACY),
-                mPackage.usesOptionalLibraries);
+        if (PackageBackwardCompatibility.removeOAHLFromBCP()) {
+            assertEquals("usesOptionalLibraries not updated correctly",
+                    arrayList(ORG_APACHE_HTTP_LEGACY),
+                    mPackage.usesOptionalLibraries);
+        } else {
+            assertNull("usesOptionalLibraries not updated correctly",
+                    mPackage.usesOptionalLibraries);
+        }
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7403c26..09ac1d8 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -428,7 +428,8 @@
                     Settings.Global.ZEN_MODE,
                     Settings.Global.ZEN_MODE_CONFIG_ETAG,
                     Settings.Global.ZEN_MODE_RINGER_LEVEL,
-                    Settings.Global.ZRAM_ENABLED);
+                    Settings.Global.ZRAM_ENABLED,
+                    Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION);
 
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
@@ -481,7 +482,6 @@
                  Settings.Secure.INSTALL_NON_MARKET_APPS,
                  Settings.Secure.LAST_SETUP_SHOWN,
                  Settings.Secure.LOCATION_MODE,
-                 Settings.Secure.LOCATION_PREVIOUS_MODE,
                  Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, // Candidate?
                  Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
                  Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 74f8c71..8699cb4 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -192,7 +192,7 @@
 # key 170 "KEY_ISO"
 key 171   MUSIC
 key 172   HOME
-# key 173 "KEY_REFRESH"
+key 173   REFRESH
 # key 174 "KEY_EXIT"
 # key 175 "KEY_MOVE"
 # key 176 "KEY_EDIT"
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index da170c0..6d3ddd5 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -118,9 +118,12 @@
 
     @Override
     public void draw(@NonNull Canvas canvas) {
-        long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper(),
-                SystemClock.uptimeMillis());
-        scheduleSelf(mRunnable, nextUpdate);
+        long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper());
+        // a value <= 0 indicates that the drawable is stopped or that renderThread
+        // will manage the animation
+        if (nextUpdate > 0) {
+            scheduleSelf(mRunnable, nextUpdate);
+        }
     }
 
     @Override
@@ -130,6 +133,7 @@
                    + " 255! provided " + alpha);
         }
         nSetAlpha(mNativePtr, alpha);
+        invalidateSelf();
     }
 
     @Override
@@ -141,6 +145,7 @@
     public void setColorFilter(@Nullable ColorFilter colorFilter) {
         long nativeFilter = colorFilter == null ? 0 : colorFilter.getNativeInstance();
         nSetColorFilter(mNativePtr, nativeFilter);
+        invalidateSelf();
     }
 
     @Override
@@ -161,7 +166,10 @@
 
     @Override
     public void start() {
-        nStart(mNativePtr);
+        if (isRunning() == false) {
+            nStart(mNativePtr);
+            invalidateSelf();
+        }
     }
 
     @Override
@@ -173,7 +181,7 @@
             @Nullable ImageDecoder decoder, int width, int height, Rect cropRect)
         throws IOException;
     private static native long nGetNativeFinalizer();
-    private static native long nDraw(long nativePtr, long canvasNativePtr, long msecs);
+    private static native long nDraw(long nativePtr, long canvasNativePtr);
     private static native void nSetAlpha(long nativePtr, int alpha);
     private static native int nGetAlpha(long nativePtr);
     private static native void nSetColorFilter(long nativePtr, long nativeFilter);
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 3a5f7b7..e3740e3 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,7 +27,6 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
-import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Outline;
@@ -50,7 +49,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -113,7 +111,7 @@
      */
     @Deprecated
     public BitmapDrawable() {
-        init(new BitmapState((Bitmap) null), null);
+        mBitmapState = new BitmapState((Bitmap) null);
     }
 
     /**
@@ -126,7 +124,8 @@
     @SuppressWarnings("unused")
     @Deprecated
     public BitmapDrawable(Resources res) {
-        init(new BitmapState((Bitmap) null), res);
+        mBitmapState = new BitmapState((Bitmap) null);
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -136,7 +135,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        init(new BitmapState(bitmap), null);
+        this(new BitmapState(bitmap), null);
     }
 
     /**
@@ -144,7 +143,8 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        init(new BitmapState(bitmap), res);
+        this(new BitmapState(bitmap), res);
+        mBitmapState.mTargetDensity = mTargetDensity;
     }
 
     /**
@@ -154,7 +154,10 @@
      */
     @Deprecated
     public BitmapDrawable(String filepath) {
-        this(null, filepath);
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
+        if (mBitmapState.mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+        }
     }
 
     /**
@@ -162,21 +165,10 @@
      */
     @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, String filepath) {
-        Bitmap bitmap = null;
-        try (FileInputStream stream = new FileInputStream(filepath)) {
-            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
-                    (decoder, info, src) -> {
-                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-            });
-        } catch (Exception e) {
-            /*  do nothing. This matches the behavior of BitmapFactory.decodeFile()
-                If the exception happened on decode, mBitmapState.mBitmap will be null.
-            */
-        } finally {
-            init(new BitmapState(bitmap), res);
-            if (mBitmapState.mBitmap == null) {
-                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
-            }
+        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
+        if (mBitmapState.mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
     }
 
@@ -187,7 +179,10 @@
      */
     @Deprecated
     public BitmapDrawable(java.io.InputStream is) {
-        this(null, is);
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        if (mBitmapState.mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+        }
     }
 
     /**
@@ -195,21 +190,10 @@
      */
     @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, java.io.InputStream is) {
-        Bitmap bitmap = null;
-        try {
-            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
-                    (decoder, info, src) -> {
-                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-            });
-        } catch (Exception e) {
-            /*  do nothing. This matches the behavior of BitmapFactory.decodeStream()
-                If the exception happened on decode, mBitmapState.mBitmap will be null.
-            */
-        } finally {
-            init(new BitmapState(bitmap), res);
-            if (mBitmapState.mBitmap == null) {
-                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
-            }
+        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
+        mBitmapState.mTargetDensity = mTargetDensity;
+        if (mBitmapState.mBitmap == null) {
+            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
     }
 
@@ -828,19 +812,9 @@
                 }
             }
 
-            int density = Bitmap.DENSITY_NONE;
-            if (value.density == TypedValue.DENSITY_DEFAULT) {
-                density = DisplayMetrics.DENSITY_DEFAULT;
-            } else if (value.density != TypedValue.DENSITY_NONE) {
-                density = value.density;
-            }
-
             Bitmap bitmap = null;
             try (InputStream is = r.openRawResource(srcResId, value)) {
-                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
-                bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
-                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-                });
+                bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
             } catch (Exception e) {
                 // Do nothing and pick up the error below.
             }
@@ -1039,21 +1013,14 @@
         }
     }
 
-    private BitmapDrawable(BitmapState state, Resources res) {
-        init(state, res);
-    }
-
     /**
-     * The one helper to rule them all. This is called by all public & private
+     * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
      */
-    private void init(BitmapState state, Resources res) {
+    private BitmapDrawable(BitmapState state, Resources res) {
         mBitmapState = state;
-        updateLocalState(res);
 
-        if (mBitmapState != null && res != null) {
-            mBitmapState.mTargetDensity = mTargetDensity;
-        }
+        updateLocalState(res);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 36a4d26..f17cd76 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,7 +37,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
@@ -51,13 +50,11 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.View;
 
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
@@ -1178,10 +1175,6 @@
             return null;
         }
 
-        if (opts == null) {
-            return getBitmapDrawable(res, value, is);
-        }
-
         /*  ugh. The decodeStream contract is that we have already allocated
             the pad rect, but if the bitmap does not had a ninepatch chunk,
             then the pad will be ignored. If we could change this to lazily
@@ -1214,33 +1207,6 @@
         return null;
     }
 
-    private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
-        try {
-            ImageDecoder.Source source = null;
-            if (value != null) {
-                int density = Bitmap.DENSITY_NONE;
-                if (value.density == TypedValue.DENSITY_DEFAULT) {
-                    density = DisplayMetrics.DENSITY_DEFAULT;
-                } else if (value.density != TypedValue.DENSITY_NONE) {
-                    density = value.density;
-                }
-                source = ImageDecoder.createSource(res, is, density);
-            } else {
-                source = ImageDecoder.createSource(res, is);
-            }
-
-            return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
-                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-            });
-        } catch (IOException e) {
-            /*  do nothing.
-                If the exception happened on decode, the drawable will be null.
-            */
-            Log.e("Drawable", "Unable to decode stream: " + e);
-        }
-        return null;
-    }
-
     /**
      * Create a drawable from an XML document. For more information on how to
      * create resources in XML, see
@@ -1340,10 +1306,11 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
-        try (FileInputStream stream = new FileInputStream(pathName)) {
-            return getBitmapDrawable(null, null, stream);
-        } catch(IOException e) {
-            // Do nothing; we will just return null if the FileInputStream had an error
+        try {
+            Bitmap bm = BitmapFactory.decodeFile(pathName);
+            if (bm != null) {
+                return drawableFromBitmap(null, bm, null, null, null, pathName);
+            }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 7cacaf6..17f9b7c 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -137,6 +137,7 @@
     whole_static_libs: ["libskia"],
 
     srcs: [
+        "hwui/AnimatedImageDrawable.cpp",
         "hwui/Bitmap.cpp",
         "font/CacheTexture.cpp",
         "font/Font.cpp",
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index fb7b246..e1df1e7 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -495,9 +495,9 @@
                                           refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
 }
 
-void RecordingCanvas::drawAnimatedImage(SkAnimatedImage*, float left, float top,
-                                        const SkPaint*) {
+double RecordingCanvas::drawAnimatedImage(AnimatedImageDrawable*) {
     // Unimplemented
+    return 0;
 }
 
 // Text
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index dd06ada..e663402 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -183,8 +183,7 @@
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) override;
-    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
-                                   const SkPaint* paint) override;
+    virtual double drawAnimatedImage(AnimatedImageDrawable*) override;
 
     // Text
     virtual bool drawTextAbsolutePos() const override { return false; }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index dc274cf..b2edd33 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -725,18 +725,8 @@
     mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
 }
 
-void SkiaCanvas::drawAnimatedImage(SkAnimatedImage* image, float left, float top,
-                                   const SkPaint* paint) {
-    sk_sp<SkPicture> pic(image->newPictureSnapshot());
-    SkMatrix matrixStorage;
-    SkMatrix* matrix;
-    if (left == 0.0f && top == 0.0f) {
-        matrix = nullptr;
-    } else {
-        matrixStorage = SkMatrix::MakeTrans(left, top);
-        matrix = &matrixStorage;
-    }
-    mCanvas->drawPicture(pic.get(), matrix, paint);
+double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
+    return imgDrawable->drawStaging(mCanvas);
 }
 
 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 7137210..3efc22a 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -124,8 +124,7 @@
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) override;
-    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
-                                   const SkPaint* paint) override;
+    virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
 
     virtual bool drawTextAbsolutePos() const override { return true; }
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
new file mode 100644
index 0000000..36dd06f
--- /dev/null
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#include "AnimatedImageDrawable.h"
+
+#include "thread/Task.h"
+#include "thread/TaskManager.h"
+#include "thread/TaskProcessor.h"
+#include "utils/TraceUtils.h"
+
+#include <SkPicture.h>
+#include <SkRefCnt.h>
+#include <SkTime.h>
+#include <SkTLazy.h>
+
+namespace android {
+
+AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage)
+    : mSkAnimatedImage(std::move(animatedImage)) { }
+
+void AnimatedImageDrawable::syncProperties() {
+    mAlpha = mStagingAlpha;
+    mColorFilter = mStagingColorFilter;
+}
+
+void AnimatedImageDrawable::start() {
+    SkAutoExclusive lock(mLock);
+
+    mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot());
+
+    mSkAnimatedImage->start();
+}
+
+void AnimatedImageDrawable::stop() {
+    SkAutoExclusive lock(mLock);
+    mSkAnimatedImage->stop();
+    mSnapshot.reset(nullptr);
+}
+
+bool AnimatedImageDrawable::isRunning() {
+    return mSkAnimatedImage->isRunning();
+}
+
+// This is really a Task<void> but that doesn't really work when Future<>
+// expects to be able to get/set a value
+class AnimatedImageDrawable::AnimatedImageTask : public uirenderer::Task<bool> {
+public:
+    AnimatedImageTask(AnimatedImageDrawable* animatedImageDrawable)
+            : mAnimatedImageDrawable(sk_ref_sp(animatedImageDrawable)) {}
+
+    sk_sp<AnimatedImageDrawable> mAnimatedImageDrawable;
+    bool mIsCompleted = false;
+};
+
+class AnimatedImageDrawable::AnimatedImageTaskProcessor : public uirenderer::TaskProcessor<bool> {
+public:
+    explicit AnimatedImageTaskProcessor(uirenderer::TaskManager* taskManager)
+            : uirenderer::TaskProcessor<bool>(taskManager) {}
+    ~AnimatedImageTaskProcessor() {}
+
+    virtual void onProcess(const sp<uirenderer::Task<bool>>& task) override {
+        ATRACE_NAME("Updating AnimatedImageDrawables");
+        AnimatedImageTask* t = static_cast<AnimatedImageTask*>(task.get());
+        t->mAnimatedImageDrawable->update();
+        t->mIsCompleted = true;
+        task->setResult(true);
+    };
+};
+
+void AnimatedImageDrawable::scheduleUpdate(uirenderer::TaskManager* taskManager) {
+    if (!mSkAnimatedImage->isRunning()
+            || (mDecodeTask.get() != nullptr && !mDecodeTask->mIsCompleted)) {
+        return;
+    }
+
+    if (!mDecodeTaskProcessor.get()) {
+        mDecodeTaskProcessor = new AnimatedImageTaskProcessor(taskManager);
+    }
+
+    // TODO get one frame ahead and only schedule updates when you need to replenish
+    mDecodeTask = new AnimatedImageTask(this);
+    mDecodeTaskProcessor->add(mDecodeTask);
+}
+
+void AnimatedImageDrawable::update() {
+    SkAutoExclusive lock(mLock);
+
+    if (!mSkAnimatedImage->isRunning()) {
+        return;
+    }
+
+    const double currentTime = SkTime::GetMSecs();
+    if (currentTime >= mNextFrameTime) {
+        mNextFrameTime = mSkAnimatedImage->update(currentTime);
+        mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot());
+        mIsDirty = true;
+    }
+}
+
+void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
+    SkTLazy<SkPaint> lazyPaint;
+    if (mAlpha != SK_AlphaOPAQUE || mColorFilter.get()) {
+        lazyPaint.init();
+        lazyPaint.get()->setAlpha(mAlpha);
+        lazyPaint.get()->setColorFilter(mColorFilter);
+        lazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
+    }
+
+    SkAutoExclusive lock(mLock);
+    if (mSkAnimatedImage->isRunning()) {
+        canvas->drawPicture(mSnapshot, nullptr, lazyPaint.getMaybeNull());
+    } else {
+        // TODO: we could potentially keep the cached surface around if there is a paint and we know
+        // the drawable is attached to the view system
+        SkAutoCanvasRestore acr(canvas, false);
+        if (lazyPaint.isValid()) {
+            canvas->saveLayer(mSkAnimatedImage->getBounds(), lazyPaint.get());
+        }
+        mSkAnimatedImage->draw(canvas);
+    }
+
+    mIsDirty = false;
+}
+
+double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
+    // update the drawable with the current time
+    double nextUpdate = mSkAnimatedImage->update(SkTime::GetMSecs());
+    SkAutoCanvasRestore acr(canvas, false);
+    if (mStagingAlpha != SK_AlphaOPAQUE || mStagingColorFilter.get()) {
+        SkPaint paint;
+        paint.setAlpha(mStagingAlpha);
+        paint.setColorFilter(mStagingColorFilter);
+        canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint);
+    }
+    canvas->drawDrawable(mSkAnimatedImage.get());
+    return nextUpdate;
+}
+
+};  // namespace android
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
new file mode 100644
index 0000000..18764af
--- /dev/null
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cutils/compiler.h>
+#include <utils/RefBase.h>
+
+#include <SkAnimatedImage.h>
+#include <SkCanvas.h>
+#include <SkColorFilter.h>
+#include <SkDrawable.h>
+#include <SkMutex.h>
+
+class SkPicture;
+
+namespace android {
+
+namespace uirenderer {
+class TaskManager;
+}
+
+/**
+ * Native component of android.graphics.drawable.AnimatedImageDrawables.java.  This class can be
+ * drawn into Canvas.h and maintains the state needed to drive the animation from the RenderThread.
+ */
+class ANDROID_API AnimatedImageDrawable : public SkDrawable {
+public:
+    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage);
+
+    /**
+     * This returns true if the animation has updated and signals that the next draw will contain
+     * new content.
+     */
+    bool isDirty() const { return mIsDirty; }
+
+    int getStagingAlpha() const { return mStagingAlpha; }
+    void setStagingAlpha(int alpha) { mStagingAlpha = alpha; }
+    void setStagingColorFilter(sk_sp<SkColorFilter> filter) { mStagingColorFilter = filter; }
+    void syncProperties();
+
+    virtual SkRect onGetBounds() override {
+        return mSkAnimatedImage->getBounds();
+    }
+
+    double drawStaging(SkCanvas* canvas);
+
+    void start();
+    void stop();
+    bool isRunning();
+
+    void scheduleUpdate(uirenderer::TaskManager* taskManager);
+
+protected:
+    virtual void onDraw(SkCanvas* canvas) override;
+
+private:
+    void update();
+
+    sk_sp<SkAnimatedImage> mSkAnimatedImage;
+    sk_sp<SkPicture> mSnapshot;
+    SkMutex mLock;
+
+    int mStagingAlpha = SK_AlphaOPAQUE;
+    sk_sp<SkColorFilter> mStagingColorFilter;
+
+    int mAlpha = SK_AlphaOPAQUE;
+    sk_sp<SkColorFilter> mColorFilter;
+    double mNextFrameTime = 0.0;
+    bool mIsDirty = false;
+
+    class AnimatedImageTask;
+    class AnimatedImageTaskProcessor;
+    sp<AnimatedImageTask> mDecodeTask;
+    sp<AnimatedImageTaskProcessor> mDecodeTaskProcessor;
+};
+
+};  // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 5efd357..cae4542 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -73,6 +73,7 @@
 
 typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc;
 
+class AnimatedImageDrawable;
 class Bitmap;
 class Paint;
 struct Typeface;
@@ -238,8 +239,7 @@
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) = 0;
 
-    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
-                                   const SkPaint* paint) = 0;
+    virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
 
     /**
      * Specifies if the positions passed to ::drawText are absolute or relative
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index cb10901..cf0b6a4 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -31,6 +31,9 @@
     for (auto& functor : mChildFunctors) {
         functor.syncFunctor();
     }
+    for (auto& animatedImage : mAnimatedImages) {
+        animatedImage->syncProperties();
+    }
     for (auto& vectorDrawable : mVectorDrawables) {
         vectorDrawable->syncProperties();
     }
@@ -89,6 +92,18 @@
     }
 
     bool isDirty = false;
+    for (auto& animatedImage : mAnimatedImages) {
+        // If any animated image in the display list needs updated, then damage the node.
+        if (animatedImage->isDirty()) {
+            isDirty = true;
+        }
+        if (animatedImage->isRunning()) {
+            static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
+                    ->scheduleDeferredUpdate(animatedImage);
+            info.out.hasAnimations = true;
+        }
+    }
+
     for (auto& vectorDrawable : mVectorDrawables) {
         // If any vector drawable in the display list needs update, damage the node.
         if (vectorDrawable->isDirty()) {
@@ -109,6 +124,7 @@
 
     mMutableImages.clear();
     mVectorDrawables.clear();
+    mAnimatedImages.clear();
     mChildFunctors.clear();
     mChildNodes.clear();
 
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 6883d33..818ec11 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "DisplayList.h"
+#include "hwui/AnimatedImageDrawable.h"
 #include "GLFunctorDrawable.h"
 #include "RenderNodeDrawable.h"
 
@@ -144,6 +145,7 @@
     std::deque<GLFunctorDrawable> mChildFunctors;
     std::vector<SkImage*> mMutableImages;
     std::vector<VectorDrawableRoot*> mVectorDrawables;
+    std::vector<AnimatedImageDrawable*> mAnimatedImages;
     SkLiteDL mDisplayList;
 
     // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9db39d9..534782a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -40,6 +40,7 @@
 Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
 
 SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+    mAnimatedImageDrawables.reserve(30);
     mVectorDrawables.reserve(30);
 }
 
@@ -326,6 +327,15 @@
 
     ATRACE_NAME("flush commands");
     surface->getCanvas()->flush();
+
+    // TODO move to another method
+    if (!mAnimatedImageDrawables.empty()) {
+        ATRACE_NAME("Update AnimatedImageDrawables");
+        for (auto animatedImage : mAnimatedImageDrawables) {
+            animatedImage->scheduleUpdate(getTaskManager());
+        }
+        mAnimatedImageDrawables.clear();
+    }
 }
 
 namespace {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 2709227..cc75e9c 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -18,6 +18,7 @@
 
 #include <SkSurface.h>
 #include "FrameBuilder.h"
+#include "hwui/AnimatedImageDrawable.h"
 #include "renderthread/CanvasContext.h"
 #include "renderthread/IRenderPipeline.h"
 
@@ -54,6 +55,12 @@
 
     std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
 
+    void scheduleDeferredUpdate(AnimatedImageDrawable* imageDrawable) {
+        mAnimatedImageDrawables.push_back(imageDrawable);
+    }
+
+    std::vector<AnimatedImageDrawable*>* getAnimatingImages() { return &mAnimatedImageDrawables; }
+
     static void destroyLayer(RenderNode* node);
 
     static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
@@ -137,6 +144,11 @@
      */
     std::vector<VectorDrawableRoot*> mVectorDrawables;
 
+    /**
+     * populated by prepareTree with images with active animations
+     */
+    std::vector<AnimatedImageDrawable*> mAnimatedImageDrawables;
+
     // Block of properties used only for debugging to record a SkPicture and save it in a file.
     /**
      * mCapturedFile is used to enforce we don't capture more than once for a given name (cause
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 035cea3..eabe2e8 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -246,6 +246,12 @@
     }
 }
 
+double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) {
+    drawDrawable(animatedImage);
+    mDisplayList->mAnimatedImages.push_back(animatedImage);
+    return 0;
+}
+
 };  // namespace skiapipeline
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index d35bbab..0e5dbdb 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -53,6 +53,7 @@
     virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
                                float dstLeft, float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) override;
+    virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override;
 
     virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
                                uirenderer::CanvasPropertyPrimitive* top,
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 0990dcc..018db9a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -89,6 +89,10 @@
     ProviderProperties getProviderProperties(String provider);
     String getNetworkProviderPackage();
     boolean isProviderEnabled(String provider);
+    boolean isProviderEnabledForUser(String provider, int userId);
+    boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
+    boolean isLocationEnabledForUser(int userId);
+    void setLocationEnabledForUser(boolean enabled, int userId);
 
     void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
     void removeTestProvider(String provider, String opPackageName);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f0b2774..9db9d33 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -16,7 +16,10 @@
 
 package android.location;
 
-import com.android.internal.location.ProviderProperties;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.LOCATION_HARDWARE;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -24,7 +27,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -33,17 +35,15 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
-
+import com.android.internal.location.ProviderProperties;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
-import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static android.Manifest.permission.LOCATION_HARDWARE;
-
 /**
  * This class provides access to the system location services.  These
  * services allow applications to obtain periodic updates of the
@@ -1171,13 +1171,57 @@
     }
 
     /**
+     * Returns the current enabled/disabled status of location
+     *
+     * @return true if location is enabled. false if location is disabled.
+     */
+    public boolean isLocationEnabled() {
+        return isLocationEnabledForUser(Process.myUserHandle());
+    }
+
+    /**
+     * Method for enabling or disabling location.
+     *
+     * @param enabled true to enable location. false to disable location
+     * @param userHandle the user to set
+     * @return true if the value was set, false on database errors
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(WRITE_SECURE_SETTINGS)
+    public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
+        try {
+            mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the current enabled/disabled status of location
+     *
+     * @param userHandle the user to query
+     * @return true location is enabled. false if location is disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isLocationEnabledForUser(UserHandle userHandle) {
+        try {
+            return mService.isLocationEnabledForUser(userHandle.getIdentifier());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the current enabled/disabled status of the given provider.
      *
      * <p>If the user has enabled this provider in the Settings menu, true
      * is returned otherwise false is returned
      *
-     * <p>Callers should instead use
-     * {@link android.provider.Settings.Secure#LOCATION_MODE}
+     * <p>Callers should instead use {@link #isLocationEnabled()}
      * unless they depend on provider-specific APIs such as
      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
      *
@@ -1202,6 +1246,64 @@
     }
 
     /**
+     * Returns the current enabled/disabled status of the given provider and user.
+     *
+     * <p>If the user has enabled this provider in the Settings menu, true
+     * is returned otherwise false is returned
+     *
+     * <p>Callers should instead use {@link #isLocationEnabled()}
+     * unless they depend on provider-specific APIs such as
+     * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
+     *
+     * <p>
+     * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
+     * method would throw {@link SecurityException} if the location permissions
+     * were not sufficient to use the specified provider.
+     *
+     * @param provider the name of the provider
+     * @param userHandle the user to query
+     * @return true if the provider exists and is enabled
+     *
+     * @throws IllegalArgumentException if provider is null
+     * @hide
+     */
+    @SystemApi
+    public boolean isProviderEnabledForUser(String provider, UserHandle userHandle) {
+        checkProvider(provider);
+
+        try {
+            return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Method for enabling or disabling a single location provider.
+     *
+     * @param provider the name of the provider
+     * @param enabled true to enable the provider. false to disable the provider
+     * @param userHandle the user to set
+     * @return true if the value was set, false on database errors
+     *
+     * @throws IllegalArgumentException if provider is null
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(WRITE_SECURE_SETTINGS)
+    public boolean setProviderEnabledForUser(
+            String provider, boolean enabled, UserHandle userHandle) {
+        checkProvider(provider);
+
+        try {
+            return mService.setProviderEnabledForUser(
+                    provider, enabled, userHandle.getIdentifier());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Get the last known location.
      *
      * <p>This location could be very old so use
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index d7861e3..44a2ff9 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -880,7 +880,9 @@
     }
 
     /** @hide */
-    public void toProto(ProtoOutputStream proto) {
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
         proto.write(AudioAttributesProto.USAGE, mUsage);
         proto.write(AudioAttributesProto.CONTENT_TYPE, mContentType);
         proto.write(AudioAttributesProto.FLAGS, mFlags);
@@ -892,6 +894,8 @@
             }
         }
         // TODO: is the data in mBundle useful for debugging?
+
+        proto.end(token);
     }
 
     /** @hide */
diff --git a/media/java/android/media/IMediaSession2.aidl b/media/java/android/media/IMediaSession2.aidl
index bc8121e..078b611 100644
--- a/media/java/android/media/IMediaSession2.aidl
+++ b/media/java/android/media/IMediaSession2.aidl
@@ -47,6 +47,11 @@
     PlaybackState getPlaybackState();
 
     //////////////////////////////////////////////////////////////////////////////////////////////
+    // Get library service specific
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    oneway void getBrowserRoot(IMediaSession2Callback callback, in Bundle rootHints);
+
+    //////////////////////////////////////////////////////////////////////////////////////////////
     // Callbacks -- remove them
     //////////////////////////////////////////////////////////////////////////////////////////////
     /**
diff --git a/media/java/android/media/IMediaSession2Callback.aidl b/media/java/android/media/IMediaSession2Callback.aidl
index 0058e79..1664e01 100644
--- a/media/java/android/media/IMediaSession2Callback.aidl
+++ b/media/java/android/media/IMediaSession2Callback.aidl
@@ -44,4 +44,11 @@
     //               Follow-up TODO: Add similar functions to the session.
     // TODO(jaewan): Is term 'accepted/rejected' correct? For permission, 'grant' is used.
     void onConnectionChanged(IMediaSession2 sessionBinder, in Bundle commandGroup);
+
+    void onCustomLayoutChanged(in List<Bundle> commandButtonlist);
+
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // Browser sepcific
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    void onGetRootResult(in Bundle rootHints, String rootMediaId, in Bundle rootExtra);
 }
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
new file mode 100644
index 0000000..fa00902
--- /dev/null
+++ b/media/java/android/media/MediaBrowser2.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.update.ApiLoader;
+import android.media.update.MediaBrowser2Provider;
+import android.os.Bundle;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Browses media content offered by a {@link MediaLibraryService2}.
+ * @hide
+ */
+public class MediaBrowser2 extends MediaController2 {
+    // Equals to the ((MediaBrowser2Provider) getProvider())
+    private final MediaBrowser2Provider mProvider;
+
+    /**
+     * Callback to listen events from {@link MediaLibraryService2}.
+     */
+    public abstract static class BrowserCallback extends MediaController2.ControllerCallback {
+        /**
+         * Called with the result of {@link #getBrowserRoot(Bundle)}.
+         * <p>
+         * {@code rootMediaId} and {@code rootExtra} can be {@code null} if the browser root isn't
+         * available.
+         *
+         * @param rootHints rootHints that you previously requested.
+         * @param rootMediaId media id of the browser root. Can be {@code null}
+         * @param rootExtra extra of the browser root. Can be {@code null}
+         */
+        public abstract void onGetRootResult(Bundle rootHints, @Nullable String rootMediaId,
+                @Nullable Bundle rootExtra);
+    }
+
+    public MediaBrowser2(Context context, SessionToken token, BrowserCallback callback,
+            Executor executor) {
+        super(context, token, callback, executor);
+        mProvider = (MediaBrowser2Provider) getProvider();
+    }
+
+    @Override
+    MediaBrowser2Provider createProvider(Context context, SessionToken token,
+            ControllerCallback callback, Executor executor) {
+        return ApiLoader.getProvider(context)
+                .createMediaBrowser2(this, context, token, (BrowserCallback) callback, executor);
+    }
+
+    public void getBrowserRoot(Bundle rootHints) {
+        mProvider.getBrowserRoot_impl(rootHints);
+    }
+}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 550eee2..3836e78 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.media.MediaPlayerBase.PlaybackListener;
+import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.session.MediaSessionManager;
@@ -26,6 +28,8 @@
 import android.media.update.ApiLoader;
 import android.media.update.MediaController2Provider;
 import android.os.Handler;
+
+import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
@@ -58,7 +62,7 @@
  */
 // TODO(jaewan): Unhide
 // TODO(jaewan): Revisit comments. Currently MediaBrowser case is missing.
-public class MediaController2 extends MediaPlayerBase {
+public class MediaController2 implements AutoCloseable {
     /**
      * Interface for listening to change in activeness of the {@link MediaSession2}.  It's
      * active if and only if it has set a player.
@@ -77,10 +81,20 @@
          * the session. The controller becomes unavailable afterwards and the callback wouldn't
          * be called.
          * <p>
-         * It will be also called after the {@link #release()}, so you can put clean up code here.
-         * You don't need to call {@link #release()} after this.
+         * It will be also called after the {@link #close()}, so you can put clean up code here.
+         * You don't need to call {@link #close()} after this.
          */
         public void onDisconnected() { }
+
+        /**
+         * Called when the session sets the custom layout through the
+         * {@link MediaSession2#setCustomLayout(ControllerInfo, List)}.
+         * <p>
+         * Can be called before {@link #onConnected(CommandGroup)} is called.
+         *
+         * @param layout
+         */
+        public void onCustomLayoutChanged(List<CommandButton> layout) { }
     }
 
     private final MediaController2Provider mProvider;
@@ -104,7 +118,13 @@
         // session whose session binder is only valid while it's active.
         // prevent a controller from reusable after the
         // session is released and recreated.
-        mProvider = ApiLoader.getProvider(context)
+        mProvider = createProvider(context, token, callback, executor);
+    }
+
+    MediaController2Provider createProvider(@NonNull Context context,
+            @NonNull SessionToken token, @NonNull ControllerCallback callback,
+            @NonNull Executor executor) {
+        return ApiLoader.getProvider(context)
                 .createMediaController2(this, context, token, callback, executor);
     }
 
@@ -112,8 +132,9 @@
      * Release this object, and disconnect from the session. After this, callbacks wouldn't be
      * received.
      */
-    public void release() {
-        mProvider.release_impl();
+    @Override
+    public void close() {
+        mProvider.close_impl();
     }
 
     /**
@@ -138,32 +159,27 @@
         return mProvider.isConnected_impl();
     }
 
-    @Override
     public void play() {
         mProvider.play_impl();
     }
 
-    @Override
     public void pause() {
         mProvider.pause_impl();
     }
 
-    @Override
     public void stop() {
         mProvider.stop_impl();
     }
 
-    @Override
     public void skipToPrevious() {
         mProvider.skipToPrevious_impl();
     }
 
-    @Override
     public void skipToNext() {
         mProvider.skipToNext_impl();
     }
 
-    @Override
+
     public @Nullable PlaybackState getPlaybackState() {
         return mProvider.getPlaybackState_impl();
     }
@@ -179,7 +195,6 @@
     // TODO(jaewan): Match with the addSessionAvailabilityListener() that tells the current state
     //               through the listener.
     // TODO(jaewan): Can handler be null? Follow the API guideline after it's finalized.
-    @Override
     public void addPlaybackListener(@NonNull PlaybackListener listener, @NonNull Handler handler) {
         mProvider.addPlaybackListener_impl(listener, handler);
     }
@@ -190,7 +205,6 @@
      * @param listener the listener to be removed
      * @throws IllegalArgumentException if the listener is {@code null}.
      */
-    @Override
     public void removePlaybackListener(@NonNull PlaybackListener listener) {
         mProvider.removePlaybackListener_impl(listener);
     }
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 690d740..063186d 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -26,6 +26,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
+import android.os.PersistableBundle;
 import android.util.Log;
 import dalvik.system.CloseGuard;
 import java.lang.annotation.Retention;
@@ -678,12 +679,14 @@
         private int mRequestType;
 
         /**
-         * Key request type is initial license request
+         * Key request type is initial license request. A license request
+         * is necessary to load keys.
          */
         public static final int REQUEST_TYPE_INITIAL = 0;
 
         /**
-         * Key request type is license renewal
+         * Key request type is license renewal. A license request is
+         * necessary to prevent the keys from expiring.
          */
         public static final int REQUEST_TYPE_RENEWAL = 1;
 
@@ -692,11 +695,25 @@
          */
         public static final int REQUEST_TYPE_RELEASE = 2;
 
+        /**
+         * Keys are already loaded. No license request is necessary, and no
+         * key request data is returned.
+         */
+        public static final int REQUEST_TYPE_NONE = 3;
+
+        /**
+         * Keys have been loaded but an additional license request is needed
+         * to update their values.
+         */
+        public static final int REQUEST_TYPE_UPDATE = 4;
+
         /** @hide */
         @IntDef({
             REQUEST_TYPE_INITIAL,
             REQUEST_TYPE_RENEWAL,
             REQUEST_TYPE_RELEASE,
+            REQUEST_TYPE_NONE,
+            REQUEST_TYPE_UPDATE,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface RequestType {}
@@ -737,7 +754,8 @@
         /**
          * Get the type of the request
          * @return one of {@link #REQUEST_TYPE_INITIAL},
-         * {@link #REQUEST_TYPE_RENEWAL} or {@link #REQUEST_TYPE_RELEASE}
+         * {@link #REQUEST_TYPE_RENEWAL}, {@link #REQUEST_TYPE_RELEASE},
+         * {@link #REQUEST_TYPE_NONE} or {@link #REQUEST_TYPE_UPDATE}
          */
         @RequestType
         public int getRequestType() { return mRequestType; }
@@ -1201,7 +1219,6 @@
     public native void setPropertyByteArray(@NonNull @ArrayProperty
             String propertyName, @NonNull byte[] value);
 
-
     private static final native void setCipherAlgorithmNative(
             @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
 
@@ -1228,6 +1245,25 @@
             @NonNull byte[] keyId, @NonNull byte[] message, @NonNull byte[] signature);
 
     /**
+     * Return Metrics data about the current MediaDrm instance.
+     *
+     * @return a {@link PersistableBundle} containing the set of attributes and values
+     * available for this instance of MediaDrm.
+     * The attributes are described in {@link MetricsConstants}.
+     *
+     * 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();
+        return bundle;
+    }
+
+    private native PersistableBundle getMetricsNative();
+
+    /**
      * In addition to supporting decryption of DASH Common Encrypted Media, the
      * MediaDrm APIs provide the ability to securely deliver session keys from
      * an operator's session key server to a client device, based on the factory-installed
@@ -1531,4 +1567,31 @@
         System.loadLibrary("media_jni");
         native_init();
     }
+
+    /**
+     * 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
+    {
+        private MetricsConstants() {}
+
+        /**
+         * Key to extract the number of successful {@link #openSession} calls
+         * from the {@link PersistableBundle} returned by a
+         * {@link #getMetrics} call.
+         */
+        public static final String OPEN_SESSION_OK_COUNT
+            = "/drm/mediadrm/open_session/ok/count";
+
+        /**
+         * Key to extract the number of failed {@link #openSession} calls
+         * from the {@link PersistableBundle} returned by a
+         * {@link #getMetrics} call.
+         */
+        public static final String OPEN_SESSION_ERROR_COUNT
+            = "/drm/mediadrm/open_session/error/count";
+    }
 }
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
new file mode 100644
index 0000000..bbc9407
--- /dev/null
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.MediaSession2.BuilderBase;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.update.ApiLoader;
+import android.media.update.MediaSessionService2Provider;
+import android.os.Bundle;
+import android.service.media.MediaBrowserService.BrowserRoot;
+
+/**
+ * Base class for media library services.
+ * <p>
+ * Media library services enable applications to browse media content provided by an application
+ * and ask the application to start playing it. They may also be used to control content that
+ * is already playing by way of a {@link MediaSession2}.
+ * <p>
+ * To extend this class, adding followings directly to your {@code AndroidManifest.xml}.
+ * <pre>
+ * &lt;service android:name="component_name_of_your_implementation" &gt;
+ *   &lt;intent-filter&gt;
+ *     &lt;action android:name="android.media.MediaLibraryService2" /&gt;
+ *   &lt;/intent-filter&gt;
+ * &lt;/service&gt;</pre>
+ * <p>
+ * A {@link MediaLibraryService2} is extension of {@link MediaSessionService2}. IDs shouldn't
+ * be shared between the {@link MediaSessionService2} and {@link MediaSession2}. By
+ * default, an empty string will be used for ID of the service. If you want to specify an ID,
+ * 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
+     * support -- that is, this is the action it uses for its intent filter.
+     */
+    public static final String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
+
+    /**
+     * Session for the media library service.
+     */
+    public class MediaLibrarySession extends MediaSession2 {
+        MediaLibrarySession(Context context, MediaPlayerBase player, String id,
+                SessionCallback callback) {
+            super(context, player, id, callback);
+        }
+        // TODO(jaewan): Place public methods here.
+    }
+
+    public static abstract class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
+        /**
+         * Called to get the root information for browsing by a particular client.
+         * <p>
+         * The implementation should verify that the client package has permission
+         * to access browse media information before returning the root id; it
+         * should return null if the client is not allowed to access this
+         * information.
+         *
+         * @param controllerInfo information of the controller requesting access to browse media.
+         * @param rootHints An optional bundle of service-specific arguments to send
+         * to the media browser service when connecting and retrieving the
+         * root id for browsing, or null if none. The contents of this
+         * bundle may affect the information returned when browsing.
+         * @return The {@link BrowserRoot} for accessing this app's content or null.
+         * @see BrowserRoot#EXTRA_RECENT
+         * @see BrowserRoot#EXTRA_OFFLINE
+         * @see BrowserRoot#EXTRA_SUGGESTED
+         */
+        public abstract @Nullable BrowserRoot onGetRoot(
+                @NonNull ControllerInfo controllerInfo, @Nullable Bundle rootHints);
+    }
+
+    /**
+     * Builder for {@link MediaLibrarySession}.
+     */
+    // TODO(jaewan): Move this to updatable.
+    public class MediaLibrarySessionBuilder
+            extends BuilderBase<MediaLibrarySessionBuilder, MediaLibrarySessionCallback> {
+        public MediaLibrarySessionBuilder(
+                @NonNull Context context, @NonNull MediaPlayerBase player,
+                @NonNull MediaLibrarySessionCallback callback) {
+            super(context, player);
+            setSessionCallback(callback);
+        }
+
+        @Override
+        public MediaLibrarySessionBuilder setSessionCallback(
+                @NonNull MediaLibrarySessionCallback callback) {
+            if (callback == null) {
+                throw new IllegalArgumentException("MediaLibrarySessionCallback cannot be null");
+            }
+            return super.setSessionCallback(callback);
+        }
+
+        @Override
+        public MediaLibrarySession build() throws IllegalStateException {
+            return new MediaLibrarySession(mContext, mPlayer, mId, mCallback);
+        }
+    }
+
+    @Override
+    MediaSessionService2Provider createProvider() {
+        return ApiLoader.getProvider(this).createMediaLibraryService2(this);
+    }
+
+    /**
+     * Called when another app requested to start this service.
+     * <p>
+     * Library service will accept or reject the connection with the
+     * {@link MediaLibrarySessionCallback} in the created session.
+     * <p>
+     * Service wouldn't run if {@code null} is returned or session's ID doesn't match with the
+     * expected ID that you've specified through the AndroidManifest.xml.
+     * <p>
+     * This method will be called on the main thread.
+     *
+     * @param sessionId session id written in the AndroidManifest.xml.
+     * @return a new browser session
+     * @see MediaLibrarySessionBuilder
+     * @see #getSession()
+     * @throws RuntimeException if returned session is invalid
+     */
+    @Override
+    public @NonNull abstract MediaLibrarySession onCreateSession(String sessionId);
+}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 807535b..22f3f09 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -16,10 +16,12 @@
 
 package android.media;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaPlayerBase.PlaybackListener;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.Callback;
 import android.media.session.PlaybackState;
@@ -29,12 +31,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcelable;
-import android.os.Process;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -55,20 +54,17 @@
  * instead. With it, your playback can be revived even after you've finished playback. See
  * {@link MediaSessionService2} for details.
  * <p>
- * A session can be obtained by {@link #getInstance(Context, Handler)}. The owner of the session may
- * pass its session token to other processes to allow them to create a {@link MediaController2}
- * to interact with the session.
+ * A session can be obtained by {@link Builder}. The owner of the session may pass its session token
+ * to other processes to allow them to create a {@link MediaController2} to interact with the
+ * session.
  * <p>
- * To receive transport control commands, an underlying media player must be set with
- * {@link #setPlayer(MediaPlayerBase)}. Commands will be sent to the underlying player directly
- * on the thread that had been specified by {@link #getInstance(Context, Handler)}.
+ * When a session receive transport control commands, the session sends the commands directly to
+ * the the underlying media player set by {@link Builder} or {@link #setPlayer(MediaPlayerBase)}.
  * <p>
- * When an app is finished performing playback it must call
- * {@link #setPlayer(MediaPlayerBase)} with {@code null} to clean up the session and notify any
- * controllers. It's developers responsibility of cleaning the session and releasing resources.
+ * When an app is finished performing playback it must call {@link #close()} to clean up the session
+ * and notify any controllers.
  * <p>
- * MediaSession2 objects should be used on the handler's thread that is initially given by
- * {@link #getInstance(Context, Handler)}.
+ * {@link MediaSession2} objects should be used on the thread on the looper.
  *
  * @see MediaSessionService2
  * @hide
@@ -81,7 +77,7 @@
 // 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 final class MediaSession2 extends MediaPlayerBase {
+public class MediaSession2 implements AutoCloseable {
     private final MediaSession2Provider mProvider;
 
     // Note: Do not define IntDef because subclass can add more command code on top of these.
@@ -102,11 +98,11 @@
     // TODO(jaewan): Move this into the updatable.
     public static final class Command {
         private static final String KEY_COMMAND_CODE
-                = "android.media.mediasession2.command.command_command";
+                = "android.media.media_session2.command.command_code";
         private static final String KEY_COMMAND_CUSTOM_COMMAND
-                = "android.media.mediasession2.command.custom_command";
+                = "android.media.media_session2.command.custom_command";
         private static final String KEY_COMMAND_EXTRA
-                = "android.media.mediasession2.command.extra";
+                = "android.media.media_session2.command.extra";
 
         private final int mCommandCode;
         // Nonnull if it's custom command
@@ -321,19 +317,16 @@
     };
 
     /**
-     * Builder for {@link MediaSession2}.
-     * <p>
-     * Any incoming event from the {@link MediaController2} will be handled on the thread
-     * that created session with the {@link Builder#build()}.
+     * Base builder class for MediaSession2 and its subclass.
+     *
+     * @hide
      */
-    // TODO(jaewan): Move this to updatable
-    // TODO(jaewan): Add setRatingType()
-    // TODO(jaewan): Add setSessionActivity()
-    public final static class Builder {
-        private final Context mContext;
-        private final MediaPlayerBase mPlayer;
-        private String mId;
-        private SessionCallback mCallback;
+    static abstract class BuilderBase
+            <T extends MediaSession2.BuilderBase<T, C>, C extends SessionCallback> {
+        final Context mContext;
+        final MediaPlayerBase mPlayer;
+        String mId;
+        C mCallback;
 
         /**
          * Constructor.
@@ -343,17 +336,14 @@
          * @throws IllegalArgumentException if any parameter is null, or the player is a
          *      {@link MediaSession2} or {@link MediaController2}.
          */
-        public Builder(@NonNull Context context, @NonNull MediaPlayerBase player) {
+        // TODO(jaewan): Also need executor
+        public BuilderBase(@NonNull Context context, @NonNull MediaPlayerBase player) {
             if (context == null) {
                 throw new IllegalArgumentException("context shouldn't be null");
             }
             if (player == null) {
                 throw new IllegalArgumentException("player shouldn't be null");
             }
-            if (player instanceof MediaSession2 || player instanceof MediaController2) {
-                throw new IllegalArgumentException("player doesn't accept MediaSession2 nor"
-                        + " MediaController2");
-            }
             mContext = context;
             mPlayer = player;
             // Ensure non-null
@@ -370,12 +360,12 @@
          * @throws IllegalArgumentException if id is {@code null}
          * @return
          */
-        public Builder setId(@NonNull String id) {
+        public T setId(@NonNull String id) {
             if (id == null) {
                 throw new IllegalArgumentException("id shouldn't be null");
             }
             mId = id;
-            return this;
+            return (T) this;
         }
 
         /**
@@ -384,9 +374,9 @@
          * @param callback session callback.
          * @return
          */
-        public Builder setSessionCallback(@Nullable SessionCallback callback) {
+        public T setSessionCallback(@Nullable C callback) {
             mCallback = callback;
-            return this;
+            return (T) this;
         }
 
         /**
@@ -396,6 +386,24 @@
          * @throws IllegalStateException if the session with the same id is already exists for the
          *      package.
          */
+        public abstract MediaSession2 build() throws IllegalStateException;
+    }
+
+    /**
+     * Builder for {@link MediaSession2}.
+     * <p>
+     * Any incoming event from the {@link MediaController2} will be handled on the thread
+     * that created session with the {@link Builder#build()}.
+     */
+    // TODO(jaewan): Move this to updatable
+    // TODO(jaewan): Add setRatingType()
+    // TODO(jaewan): Add setSessionActivity()
+    public static final class Builder extends BuilderBase<Builder, SessionCallback> {
+        public Builder(Context context, @NonNull MediaPlayerBase player) {
+            super(context, player);
+        }
+
+        @Override
         public MediaSession2 build() throws IllegalStateException {
             if (mCallback == null) {
                 mCallback = new SessionCallback();
@@ -473,12 +481,181 @@
 
         @Override
         public String toString() {
+            // TODO(jaewan): Move this to updatable.
             return "ControllerInfo {pkg=" + getPackageName() + ", uid=" + getUid() + ", trusted="
                     + isTrusted() + "}";
         }
     }
 
     /**
+     * Button for a {@link Command} that will be shown by the controller.
+     * <p>
+     * It's up to the controller's decision to respect or ignore this customization request.
+     */
+    // TODO(jaewan): Move this to updatable.
+    public static class CommandButton {
+        private static final String KEY_COMMAND
+                = "android.media.media_session2.command_button.command";
+        private static final String KEY_ICON_RES_ID
+                = "android.media.media_session2.command_button.icon_res_id";
+        private static final String KEY_DISPLAY_NAME
+                = "android.media.media_session2.command_button.display_name";
+        private static final String KEY_EXTRA
+                = "android.media.media_session2.command_button.extra";
+        private static final String KEY_ENABLED
+                = "android.media.media_session2.command_button.enabled";
+
+        private Command mCommand;
+        private int mIconResId;
+        private String mDisplayName;
+        private Bundle mExtra;
+        private boolean mEnabled;
+
+        private CommandButton(@Nullable Command command, int iconResId,
+                @Nullable String displayName, Bundle extra, boolean enabled) {
+            mCommand = command;
+            mIconResId = iconResId;
+            mDisplayName = displayName;
+            mExtra = extra;
+            mEnabled = enabled;
+        }
+
+        /**
+         * Get command associated with this button. Can be {@code null} if the button isn't enabled
+         * and only providing placeholder.
+         *
+         * @return command or {@code null}
+         */
+        public @Nullable Command getCommand() {
+            return mCommand;
+        }
+
+        /**
+         * Resource id of the button in this package. Can be {@code 0} if the command is predefined
+         * and custom icon isn't needed.
+         *
+         * @return resource id of the icon. Can be {@code 0}.
+         */
+        public int getIconResId() {
+            return mIconResId;
+        }
+
+        /**
+         * Display name of the button. Can be {@code null} or empty if the command is predefined
+         * and custom name isn't needed.
+         *
+         * @return custom display name. Can be {@code null} or empty.
+         */
+        public @Nullable String getDisplayName() {
+            return mDisplayName;
+        }
+
+        /**
+         * Extra information of the button. It's private information between session and controller.
+         *
+         * @return
+         */
+        public @Nullable Bundle getExtra() {
+            return mExtra;
+        }
+
+        /**
+         * Return whether it's enabled
+         *
+         * @return {@code true} if enabled. {@code false} otherwise.
+         */
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+
+        /**
+         * @hide
+         */
+        // TODO(jaewan): @SystemApi
+        public @NonNull Bundle toBundle() {
+            Bundle bundle = new Bundle();
+            bundle.putBundle(KEY_COMMAND, mCommand.toBundle());
+            bundle.putInt(KEY_ICON_RES_ID, mIconResId);
+            bundle.putString(KEY_DISPLAY_NAME, mDisplayName);
+            bundle.putBundle(KEY_EXTRA, mExtra);
+            bundle.putBoolean(KEY_ENABLED, mEnabled);
+            return bundle;
+        }
+
+        /**
+         * @hide
+         */
+        // TODO(jaewan): @SystemApi
+        public static @Nullable CommandButton fromBundle(Bundle bundle) {
+            Builder builder = new Builder();
+            builder.setCommand(Command.fromBundle(bundle.getBundle(KEY_COMMAND)));
+            builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0));
+            builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME));
+            builder.setExtra(bundle.getBundle(KEY_EXTRA));
+            builder.setEnabled(bundle.getBoolean(KEY_ENABLED));
+            try {
+                return builder.build();
+            } catch (IllegalStateException e) {
+                // Malformed or version mismatch. Return null for now.
+                return null;
+            }
+        }
+
+        /**
+         * Builder for {@link CommandButton}.
+         */
+        public static class Builder {
+            private Command mCommand;
+            private int mIconResId;
+            private String mDisplayName;
+            private Bundle mExtra;
+            private boolean mEnabled;
+
+            public Builder() {
+                mEnabled = true;
+            }
+
+            public Builder setCommand(Command command) {
+                mCommand = command;
+                return this;
+            }
+
+            public Builder setIconResId(int resId) {
+                mIconResId = resId;
+                return this;
+            }
+
+            public Builder setDisplayName(String displayName) {
+                mDisplayName = displayName;
+                return this;
+            }
+
+            public Builder setEnabled(boolean enabled) {
+                mEnabled = enabled;
+                return this;
+            }
+
+            public Builder setExtra(Bundle extra) {
+                mExtra = extra;
+                return this;
+            }
+
+            public CommandButton build() {
+                if (mEnabled && mCommand == null) {
+                    throw new IllegalStateException("Enabled button needs Command"
+                            + " for controller to invoke the command");
+                }
+                if (mCommand != null && mCommand.getCommandCode() == COMMAND_CODE_CUSTOM
+                        && (mIconResId == 0 || TextUtils.isEmpty(mDisplayName))) {
+                    throw new IllegalStateException("Custom commands needs icon and"
+                            + " and name to display");
+                }
+                return new CommandButton(mCommand, mIconResId, mDisplayName, mExtra, mEnabled);
+            }
+        }
+    }
+
+    /**
      * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}.
      * <p>
      * This intended behavior and here's the reasons.
@@ -492,7 +669,7 @@
      *       framework had to add heuristics to figure out if an app is
      * @hide
      */
-    private MediaSession2(Context context, MediaPlayerBase player, String id,
+    MediaSession2(Context context, MediaPlayerBase player, String id,
             SessionCallback callback) {
         super();
         mProvider = ApiLoader.getProvider(context)
@@ -520,14 +697,17 @@
      *
      * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
      *      It shouldn't be {@link MediaSession2} nor {@link MediaController2}.
-     * @throws IllegalArgumentException if the player is either {@link MediaSession2}
-     *      or {@link MediaController2}.
+     * @throws IllegalArgumentException if the player is {@code null}.
      */
-    // TODO(jaewan): Add release instead of setPlayer(null).
-    public void setPlayer(MediaPlayerBase player) throws IllegalArgumentException {
+    public void setPlayer(@NonNull MediaPlayerBase player) throws IllegalArgumentException {
         mProvider.setPlayer_impl(player);
     }
 
+    @Override
+    public void close() {
+        mProvider.close_impl();
+    }
+
     /**
      * @return player
      */
@@ -547,32 +727,93 @@
         return mProvider.getConnectedControllers_impl();
     }
 
-    @Override
+    /**
+     * Sets the {@link AudioAttributes} to be used during the playback of the video.
+     *
+     * @param attributes non-null <code>AudioAttributes</code>.
+     */
+    public void setAudioAttributes(@NonNull AudioAttributes attributes) {
+        mProvider.setAudioAttributes_impl(attributes);
+    }
+
+    /**
+     * 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},
+     * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+     * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. Or use
+     * {@link AudioManager#AUDIOFOCUS_NONE} to express that audio focus should not be
+     * requested when playback starts. You can for instance use this when playing a silent animation
+     * through this class, and you don't want to affect other audio applications playing in the
+     * background.
+     *
+     * @param focusGain the type of audio focus gain that will be requested, or
+     *                  {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during
+     *                  playback.
+     */
+    public void setAudioFocusRequest(int focusGain) {
+        mProvider.setAudioFocusRequest_impl(focusGain);
+    }
+
+    /**
+     * Sets ordered list of {@link CommandButton} for controllers to build UI with it.
+     * <p>
+     * It's up to controller's decision how to represent the layout in its own UI.
+     * Here's the same way
+     * (layout[i] means a CommandButton at index i in the given list)
+     * For 5 icons row
+     *      layout[3] layout[1] layout[0] layout[2] layout[4]
+     * For 3 icons row
+     *      layout[1] layout[0] layout[2]
+     * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button)
+     *      expanded row:   layout[5] layout[6] layout[7] layout[8] layout[9]
+     *      main row:       layout[3] layout[1] layout[0] layout[2] layout[4]
+     * <p>
+     * This API can be called in the {@link SessionCallback#onConnect(ControllerInfo)}.
+     *
+     * @param controller controller to specify layout.
+     * @param layout oredered list of layout.
+     */
+    public void setCustomLayout(@NonNull ControllerInfo controller,
+            @NonNull List<CommandButton> layout) {
+        mProvider.setCustomLayout_impl(controller, layout);
+    }
+
+    /**
+     * Play playback
+     */
     public void play() {
         mProvider.play_impl();
     }
 
-    @Override
+    /**
+     * Pause playback
+     */
     public void pause() {
         mProvider.pause_impl();
     }
 
-    @Override
+    /**
+     * Stop playback
+     */
     public void stop() {
         mProvider.stop_impl();
     }
 
-    @Override
+    /**
+     * Rewind playback
+     */
     public void skipToPrevious() {
         mProvider.skipToPrevious_impl();
     }
 
-    @Override
+    /**
+     * Rewind playback
+     */
     public void skipToNext() {
         mProvider.skipToNext_impl();
     }
 
-    @Override
     public @NonNull PlaybackState getPlaybackState() {
         return mProvider.getPlaybackState_impl();
     }
@@ -589,7 +830,6 @@
      * @throws IllegalArgumentException when either the listener or handler is {@code null}.
      */
     // TODO(jaewan): Can handler be null? Follow API guideline after it's finalized.
-    @Override
     public void addPlaybackListener(@NonNull PlaybackListener listener, @NonNull Handler handler) {
         mProvider.addPlaybackListener_impl(listener, handler);
     }
@@ -600,7 +840,6 @@
      * @param listener the listener to be removed
      * @throws IllegalArgumentException if the listener is {@code null}.
      */
-    @Override
     public void removePlaybackListener(PlaybackListener listener) {
         mProvider.removePlaybackListener_impl(listener);
     }
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index f1f5467..1a12d68 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -29,7 +29,7 @@
 import android.os.IBinder;
 
 /**
- * Service version of the {@link MediaSession2}.
+ * Base class for media session services, which is the service version of the {@link MediaSession2}.
  * <p>
  * It's highly recommended for an app to use this instead of {@link MediaSession2} if it wants
  * to keep media playback in the background.
@@ -43,11 +43,11 @@
  * </ul>
  * For example, user's voice command can start playback of your app even when it's not running.
  * <p>
- * To use this class, adding followings directly to your {@code AndroidManifest.xml}.
+ * To extend this class, adding followings directly to your {@code AndroidManifest.xml}.
  * <pre>
  * &lt;service android:name="component_name_of_your_implementation" &gt;
  *   &lt;intent-filter&gt;
- *     &lt;action android:name="android.media.session.MediaSessionService2" /&gt;
+ *     &lt;action android:name="android.media.MediaSessionService2" /&gt;
  *   &lt;/intent-filter&gt;
  * &lt;/service&gt;</pre>
  * <p>
@@ -58,7 +58,7 @@
  * <pre>
  * &lt;service android:name="component_name_of_your_implementation" &gt;
  *   &lt;intent-filter&gt;
- *     &lt;action android:name="android.media.session.MediaSessionService2" /&gt;
+ *     &lt;action android:name="android.media.MediaSessionService2" /&gt;
  *   &lt;/intent-filter&gt;
  *   &lt;meta-data android:name="android.media.session"
  *       android:value="session_id"/&gt;
@@ -120,8 +120,7 @@
      * This is the interface name that a service implementing a session service should say that it
      * support -- that is, this is the action it uses for its intent filter.
      */
-    public static final String SERVICE_INTERFACE =
-            "android.media.session.MediaSessionService2";
+    public static final String SERVICE_INTERFACE = "android.media.MediaSessionService2";
 
     /**
      * Name under which a MediaSessionService2 component publishes information about itself.
@@ -129,21 +128,13 @@
      */
     public static final String SERVICE_META_DATA = "android.media.session";
 
-    /**
-     * Default notification channel ID used by {@link #onUpdateNotification(PlaybackState)}.
-     *
-     */
-    public static final String DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID = "media_session_service";
-
-    /**
-     * Default notification channel ID used by {@link #onUpdateNotification(PlaybackState)}.
-     *
-     */
-    public static final int DEFAULT_MEDIA_NOTIFICATION_ID = 1001;
-
     public MediaSessionService2() {
         super();
-        mProvider = ApiLoader.getProvider(this).createMediaSessionService2(this);
+        mProvider = createProvider();
+    }
+
+    MediaSessionService2Provider createProvider() {
+        return ApiLoader.getProvider(this).createMediaSessionService2(this);
     }
 
     /**
@@ -168,32 +159,24 @@
      * Service wouldn't run if {@code null} is returned or session's ID doesn't match with the
      * expected ID that you've specified through the AndroidManifest.xml.
      * <p>
-     * This method will be call on the main thread.
+     * This method will be called on the main thread.
      *
      * @param sessionId session id written in the AndroidManifest.xml.
      * @return a new session
      * @see MediaSession2.Builder
      * @see #getSession()
      */
-    // TODO(jaewan): Replace this with onCreateSession(). Its sesssion callback will replace
-    //               this abstract method.
-    // TODO(jaewan): Should we also include/documents notification listener access?
-    // TODO(jaewan): Is term accepted/rejected correct? For permission, granted is more common.
-    // TODO(jaewan): Return ConnectResult() that encapsulate supported action and player.
     public @NonNull abstract MediaSession2 onCreateSession(String sessionId);
 
     /**
      * Called when the playback state of this session is changed, and notification needs update.
-     * <p>
-     * Default media style notification will be shown if you don't override this or return
-     * {@code null}. Override this method to show your own notification UI.
+     * Override this method to show your own notification UI.
      * <p>
      * With the notification returned here, the service become foreground service when the playback
      * is started. It becomes background service after the playback is stopped.
      *
      * @param state playback state
-     * @return a {@link MediaNotification}. If it's {@code null}, default notification will be shown
-     *     instead.
+     * @return a {@link MediaNotification}. If it's {@code null}, notification wouldn't be shown.
      */
     // TODO(jaewan): Also add metadata
     public MediaNotification onUpdateNotification(PlaybackState state) {
diff --git a/media/java/android/media/SessionToken.java b/media/java/android/media/SessionToken.java
index b470dea..53fc24a 100644
--- a/media/java/android/media/SessionToken.java
+++ b/media/java/android/media/SessionToken.java
@@ -42,12 +42,13 @@
 // TODO(jaewan): Find better name for this (SessionToken or Session2Token)
 public final class SessionToken {
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE})
+    @IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
     public @interface TokenType {
     }
 
     public static final int TYPE_SESSION = 0;
     public static final int TYPE_SESSION_SERVICE = 1;
+    public static final int TYPE_LIBRARY_SERVICE = 2;
 
     private static final String KEY_TYPE = "android.media.token.type";
     private static final String KEY_PACKAGE_NAME = "android.media.token.package_name";
@@ -73,6 +74,7 @@
      * @hide
      */
     // TODO(jaewan): UID is also needed.
+    // TODO(jaewan): Unhide
     public SessionToken(@TokenType int type, @NonNull String packageName, @NonNull String id,
             @Nullable String serviceName, @Nullable IMediaSession2 sessionBinder) {
         // TODO(jaewan): Add sanity check.
diff --git a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl b/media/java/android/media/update/MediaBrowser2Provider.java
similarity index 68%
copy from core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
copy to media/java/android/media/update/MediaBrowser2Provider.java
index 5385738..355dbc9 100644
--- a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
+++ b/media/java/android/media/update/MediaBrowser2Provider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,13 @@
  * limitations under the License.
  */
 
-package android.security.keystore.recovery;
+package android.media.update;
 
-/* @hide */
-parcelable KeychainProtectionParams;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+public interface MediaBrowser2Provider extends MediaController2Provider {
+    void getBrowserRoot_impl(Bundle rootHints);
+}
diff --git a/media/java/android/media/update/MediaControlView2Provider.java b/media/java/android/media/update/MediaControlView2Provider.java
index 83763b4..e0e4cef 100644
--- a/media/java/android/media/update/MediaControlView2Provider.java
+++ b/media/java/android/media/update/MediaControlView2Provider.java
@@ -40,7 +40,6 @@
     void show_impl(int timeout);
     boolean isShowing_impl();
     void hide_impl();
-    void showCCButton_impl();
     boolean isPlaying_impl();
     int getCurrentPosition_impl();
     int getBufferPercentage_impl();
@@ -49,4 +48,6 @@
     boolean canSeekForward_impl();
     void showSubtitle_impl();
     void hideSubtitle_impl();
+    void setPrevNextListeners_impl(View.OnClickListener next, View.OnClickListener prev);
+    void setButtonVisibility_impl(int button, boolean visible);
 }
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index b15d6db..9ad5a68 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -16,13 +16,20 @@
 
 package android.media.update;
 
+import android.media.MediaPlayerBase;
 import android.media.SessionToken;
+import android.media.session.PlaybackState;
+import android.os.Handler;
 
 /**
  * @hide
  */
-public interface MediaController2Provider extends MediaPlayerBaseProvider {
-    void release_impl();
+public interface MediaController2Provider extends TransportControlProvider {
+    void close_impl();
     SessionToken getSessionToken_impl();
     boolean isConnected_impl();
+
+    PlaybackState getPlaybackState_impl();
+    void addPlaybackListener_impl(MediaPlayerBase.PlaybackListener listener, Handler handler);
+    void removePlaybackListener_impl(MediaPlayerBase.PlaybackListener listener);
 }
diff --git a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl b/media/java/android/media/update/MediaLibraryService2Provider.java
similarity index 72%
copy from core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
copy to media/java/android/media/update/MediaLibraryService2Provider.java
index 5385738..7e3444f 100644
--- a/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl
+++ b/media/java/android/media/update/MediaLibraryService2Provider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-package android.security.keystore.recovery;
+package android.media.update;
 
-/* @hide */
-parcelable KeychainProtectionParams;
+/**
+ * @hide
+ */
+public interface MediaLibraryService2Provider extends MediaSessionService2Provider {
+    // Nothing new for now
+}
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 36fd182..af46628 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -16,20 +16,28 @@
 
 package android.media.update;
 
+import android.media.AudioAttributes;
 import android.media.MediaPlayerBase;
+import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.SessionToken;
+import android.media.session.PlaybackState;
+import android.os.Handler;
 
 import java.util.List;
 
 /**
  * @hide
  */
-public interface MediaSession2Provider extends MediaPlayerBaseProvider {
+public interface MediaSession2Provider extends TransportControlProvider {
+    void close_impl();
     void setPlayer_impl(MediaPlayerBase player) throws IllegalArgumentException;
     MediaPlayerBase getPlayer_impl();
     SessionToken getToken_impl();
     List<ControllerInfo> getConnectedControllers_impl();
+    void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
+    void setAudioAttributes_impl(AudioAttributes attributes);
+    void setAudioFocusRequest_impl(int focusGain);
 
     /**
      * @hide
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 91c9c66..fef2cbb 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -19,7 +19,11 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.media.IMediaSession2Callback;
+import android.media.MediaBrowser2;
+import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
+import android.media.MediaLibraryService2;
 import android.media.MediaPlayerBase;
 import android.media.MediaSession2;
 import android.media.MediaSessionService2;
@@ -53,7 +57,12 @@
             String packageName, IMediaSession2Callback callback);
     MediaController2Provider createMediaController2(
             MediaController2 instance, Context context, SessionToken token,
-            MediaController2.ControllerCallback callback, Executor executor);
+            ControllerCallback callback, Executor executor);
+    MediaBrowser2Provider createMediaBrowser2(
+            MediaBrowser2 instance, Context context, SessionToken token,
+            BrowserCallback callback, Executor executor);
     MediaSessionService2Provider createMediaSessionService2(
             MediaSessionService2 instance);
+    MediaSessionService2Provider createMediaLibraryService2(
+            MediaLibraryService2 instance);
 }
diff --git a/media/java/android/media/update/MediaPlayerBaseProvider.java b/media/java/android/media/update/TransportControlProvider.java
similarity index 93%
rename from media/java/android/media/update/MediaPlayerBaseProvider.java
rename to media/java/android/media/update/TransportControlProvider.java
index 5b13e74..1b6b201 100644
--- a/media/java/android/media/update/MediaPlayerBaseProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -23,7 +23,8 @@
 /**
  * @hide
  */
-public interface MediaPlayerBaseProvider {
+// TODO(jaewan): SystemApi
+public interface TransportControlProvider {
     void play_impl();
     void pause_impl();
     void stop_impl();
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index b7a24e5..416ea98 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -17,10 +17,12 @@
 package android.media.update;
 
 import android.media.AudioAttributes;
+import android.media.MediaPlayerBase;
 import android.net.Uri;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -50,10 +52,12 @@
     int getAudioSessionId_impl();
     void showSubtitle_impl();
     void hideSubtitle_impl();
+    void setFullScreen_impl(boolean fullScreen);
     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);
     void setVideoPath_impl(String path);
     void setVideoURI_impl(Uri uri);
     void setVideoURI_impl(Uri uri, Map<String, String> headers);
@@ -65,4 +69,5 @@
     void setOnErrorListener_impl(VideoView2.OnErrorListener l);
     void setOnInfoListener_impl(VideoView2.OnInfoListener l);
     void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l);
+    void setFullScreenChangedListener_impl(VideoView2.OnFullScreenChangedListener l);
 }
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 1dddbee..95b07f1 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "android_media_MediaDrm.h"
+#include "android_media_MediaMetricsJNI.h"
 
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
@@ -113,6 +114,8 @@
     jint kKeyRequestTypeInitial;
     jint kKeyRequestTypeRenewal;
     jint kKeyRequestTypeRelease;
+    jint kKeyRequestTypeNone;
+    jint kKeyRequestTypeUpdate;
 } gKeyRequestTypes;
 
 struct CertificateTypes {
@@ -691,6 +694,10 @@
     gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
     gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_NONE", "I");
+    gKeyRequestTypes.kKeyRequestTypeNone = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_UPDATE", "I");
+    gKeyRequestTypes.kKeyRequestTypeUpdate = env->GetStaticIntField(clazz, field);
 
     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
     GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
@@ -921,6 +928,15 @@
                 env->SetIntField(keyObj, gFields.keyRequest.requestType,
                         gKeyRequestTypes.kKeyRequestTypeRelease);
                 break;
+            case DrmPlugin::kKeyRequestType_None:
+                env->SetIntField(keyObj, gFields.keyRequest.requestType,
+                        gKeyRequestTypes.kKeyRequestTypeNone);
+                break;
+            case DrmPlugin::kKeyRequestType_Update:
+                env->SetIntField(keyObj, gFields.keyRequest.requestType,
+                        gKeyRequestTypes.kKeyRequestTypeUpdate);
+                break;
+
             default:
                 throwStateException(env, "DRM plugin failure: unknown key request type",
                         ERROR_DRM_UNKNOWN);
@@ -1603,6 +1619,31 @@
     return match;
 }
 
+static jobject
+android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
+{
+    sp<IDrm> drm = GetDrm(env, thiz);
+    if (drm == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "MediaDrm obj is null");
+        return NULL;
+    }
+
+    // Retrieve current metrics snapshot from drm.
+    MediaAnalyticsItem item ;
+    status_t err = drm->getMetrics(&item);
+    if (err != OK) {
+        ALOGE("getMetrics failed: %d", (int)err);
+        return (jobject) NULL;
+    }
+
+    jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, &item, NULL);
+    if (mybundle == NULL) {
+        ALOGE("getMetrics metric conversion failed");
+    }
+
+    return mybundle;
+}
 
 static jbyteArray android_media_MediaDrm_signRSANative(
     JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
@@ -1739,6 +1780,9 @@
 
     { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
       (void *)android_media_MediaDrm_signRSANative },
+
+    { "getMetricsNative", "()Landroid/os/PersistableBundle;",
+      (void *)android_media_MediaDrm_native_getMetrics },
 };
 
 int register_android_media_Drm(JNIEnv *env) {
diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk
index 34d6508..51396d3 100644
--- a/nfc-extras/tests/Android.mk
+++ b/nfc-extras/tests/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := \
-    android.test.runner \
+    android.test.runner.stubs \
     com.android.nfc_extras \
     android.test.base.stubs
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 3c46d99..d001e66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -21,10 +21,9 @@
 import android.os.UserManager;
 import android.print.PrintManager;
 import android.provider.Settings;
-
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.drawable.UserIconDrawable;
-
+import com.android.settingslib.wrapper.LocationManagerWrapper;
 import java.text.NumberFormat;
 
 public class Utils {
@@ -45,6 +44,24 @@
         com.android.internal.R.drawable.ic_wifi_signal_4
     };
 
+    public static void updateLocationEnabled(Context context, boolean enabled, int userId) {
+        Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
+
+        final int oldMode = Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
+        final int newMode = enabled
+                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+                : Settings.Secure.LOCATION_MODE_OFF;
+        intent.putExtra(CURRENT_MODE_KEY, oldMode);
+        intent.putExtra(NEW_MODE_KEY, newMode);
+        context.sendBroadcastAsUser(
+                intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        LocationManager locationManager =
+                (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+        LocationManagerWrapper wrapper = new LocationManagerWrapper(locationManager);
+        wrapper.setLocationEnabledForUser(enabled, UserHandle.of(userId));
+    }
+
     public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) {
         Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
         intent.putExtra(CURRENT_MODE_KEY, oldMode);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/LocationManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/LocationManagerWrapper.java
new file mode 100644
index 0000000..1a268a6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/LocationManagerWrapper.java
@@ -0,0 +1,64 @@
+/*
+ * 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 com.android.settingslib.wrapper;
+
+import android.location.LocationManager;
+import android.os.UserHandle;
+
+/**
+ * This class replicates some methods of android.location.LocationManager that are new and not
+ * yet available in our current version of Robolectric. It provides a thin wrapper to call the real
+ * methods in production and a mock in tests.
+ */
+public class LocationManagerWrapper {
+
+    private LocationManager mLocationManager;
+
+    public LocationManagerWrapper(LocationManager locationManager) {
+        mLocationManager = locationManager;
+    }
+
+    /** Returns the real {@code LocationManager} object */
+    public LocationManager getLocationManager() {
+        return mLocationManager;
+    }
+
+    /** Wraps {@code LocationManager.isProviderEnabled} method */
+    public boolean isProviderEnabled(String provider) {
+        return mLocationManager.isProviderEnabled(provider);
+    }
+
+    /** Wraps {@code LocationManager.setProviderEnabledForUser} method */
+    public void setProviderEnabledForUser(String provider, boolean enabled, UserHandle userHandle) {
+        mLocationManager.setProviderEnabledForUser(provider, enabled, userHandle);
+    }
+
+    /** Wraps {@code LocationManager.isLocationEnabled} method */
+    public boolean isLocationEnabled() {
+        return mLocationManager.isLocationEnabled();
+    }
+
+    /** Wraps {@code LocationManager.isLocationEnabledForUser} method */
+    public boolean isLocationEnabledForUser(UserHandle userHandle) {
+        return mLocationManager.isLocationEnabledForUser(userHandle);
+    }
+
+    /** Wraps {@code LocationManager.setLocationEnabledForUser} method */
+    public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
+        mLocationManager.setLocationEnabledForUser(enabled, userHandle);
+    }
+}
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 976bbee..327c1c8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -15,28 +15,8 @@
  */
 package com.android.settingslib;
 
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.location.LocationManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
-import android.text.TextUtils;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.ArgumentMatchers;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -44,7 +24,28 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
+import android.location.LocationManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import com.android.settingslib.wrapper.LocationManagerWrapper;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadows.ShadowSettings;
@@ -53,7 +54,9 @@
 @Config(
         manifest = TestConfig.MANIFEST_PATH,
         sdk = TestConfig.SDK_VERSION,
-        shadows = {UtilsTest.ShadowSecure.class})
+        shadows = {
+            UtilsTest.ShadowSecure.class,
+            UtilsTest.ShadowLocationManagerWrapper.class})
 public class UtilsTest {
     private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
     private static final String PERCENTAGE_0 = "0%";
@@ -63,10 +66,14 @@
     private static final String PERCENTAGE_100 = "100%";
 
     private Context mContext;
+    @Mock
+    private LocationManager mLocationManager;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
         ShadowSecure.reset();
     }
 
@@ -86,6 +93,17 @@
     }
 
     @Test
+    public void testUpdateLocationEnabled_sendBroadcast() {
+        int currentUserId = ActivityManager.getCurrentUser();
+        Utils.updateLocationEnabled(mContext, true, currentUserId);
+
+        verify(mContext).sendBroadcastAsUser(
+            argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
+            ArgumentMatchers.eq(UserHandle.of(currentUserId)),
+            ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+    }
+
+    @Test
     public void testFormatPercentage_RoundTrue_RoundUpIfPossible() {
         final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1,
                 PERCENTAGE_1, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50,
@@ -137,8 +155,26 @@
             return true;
         }
 
+        @Implementation
+        public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+            if (map.containsKey(name)) {
+                return map.get(name);
+            } else {
+                return def;
+            }
+        }
+
         public static void reset() {
             map.clear();
         }
     }
+
+    @Implements(value = LocationManagerWrapper.class)
+    public static class ShadowLocationManagerWrapper {
+
+        @Implementation
+        public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
+            // Do nothing
+        }
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index c7ba4d6..dd89df1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -35,6 +35,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.SettingsValidators.Validator;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.BackupUtils;
@@ -155,6 +156,9 @@
             new ArraySet<String>(Arrays.asList(new String[] {
                 KEY_NETWORK_POLICIES,
                 KEY_WIFI_NEW_CONFIG,
+                KEY_SYSTEM,
+                KEY_SECURE,
+                KEY_GLOBAL,
             }));
 
     private SettingsHelper mSettingsHelper;
@@ -223,6 +227,15 @@
             Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
                     + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT);
         }
+
+        boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(),
+                Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1;
+        if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) {
+            Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API"
+                    + Build.VERSION.SDK_INT + " due to settings flag override.");
+            return;
+        }
+
         // versionCode of com.android.providers.settings corresponds to SDK_INT
         mRestoredFromSdkInt = appVersionCode;
 
@@ -571,15 +584,19 @@
         // Figure out the white list and redirects to the global table.  We restore anything
         // in either the backup whitelist or the legacy-restore whitelist for this table.
         final String[] whitelist;
+        Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
             whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.Secure.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
             whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
                     Settings.System.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.System.VALIDATORS;
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
             whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.Global.VALIDATORS;
         } else {
             throw new IllegalArgumentException("Unknown URI: " + contentUri);
         }
@@ -627,6 +644,13 @@
                 continue;
             }
 
+            // only restore the settings that have valid values
+            if (!isValidSettingValue(key, value, validators)) {
+                Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
+                        + " validation, value: " + value);
+                continue;
+            }
+
             final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
                     ? Settings.Global.CONTENT_URI
                     : contentUri;
@@ -639,6 +663,15 @@
         }
     }
 
+    private boolean isValidSettingValue(String key, String value,
+            Map<String, Validator> validators) {
+        if (key == null || validators == null) {
+            return false;
+        }
+        Validator validator = validators.get(key);
+        return (validator != null) && validator.validate(value);
+    }
+
     private final String[] concat(String[] first, @Nullable String[] second) {
         if (second == null || second.length == 0) {
             return first;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index fc765f4..cfd33a1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.settings;
 
+import android.os.Process;
 import com.android.internal.R;
 import com.android.internal.app.LocalePicker;
 import com.android.internal.annotations.VisibleForTesting;
@@ -288,12 +289,12 @@
         }
         final String GPS = LocationManager.GPS_PROVIDER;
         boolean enabled =
-                GPS.equals(value) ||
+            GPS.equals(value) ||
                 value.startsWith(GPS + ",") ||
                 value.endsWith("," + GPS) ||
                 value.contains("," + GPS + ",");
-        Settings.Secure.setLocationProviderEnabled(
-                mContext.getContentResolver(), GPS, enabled);
+        LocationManager lm = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        lm.setProviderEnabledForUser(GPS, enabled, Process.myUserHandle());
     }
 
     private void setSoundEffects(boolean enable) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 5a75681..55f7a0a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1223,9 +1223,6 @@
         dumpSetting(s, p,
                 Settings.Secure.LOCATION_MODE,
                 SecureSettingsProto.LOCATION_MODE);
-        dumpSetting(s, p,
-                Settings.Secure.LOCATION_PREVIOUS_MODE,
-                SecureSettingsProto.LOCATION_PREVIOUS_MODE);
         // Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS intentionally excluded since it's deprecated.
         dumpSetting(s, p,
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2a697b8..5435e118 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2892,11 +2892,14 @@
             for (int i = 0; i < users.size(); i++) {
                 final int userId = users.get(i).id;
 
+                // Do we have to increment the generation for users that are not running?
+                // Yeah let's assume so...
+                final int key = makeKey(SETTINGS_TYPE_SECURE, userId);
+                mGenerationRegistry.incrementGeneration(key);
+
                 if (!mUserManager.isUserRunning(UserHandle.of(userId))) {
                     continue;
                 }
-
-                final int key = makeKey(SETTINGS_TYPE_GLOBAL, userId);
                 final Uri uri = getNotificationUriFor(key, Secure.LOCATION_PROVIDERS_ALLOWED);
 
                 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 73fcdd7..251ae2d 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -27,7 +27,12 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+RELATIVE_FINGERPRINT_PATH := ../../core/java/android/hardware/fingerprint
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-Iaidl-files-under, src) \
+    $(call all-Iaidl-files-under, $(RELATIVE_FINGERPRINT_PATH))
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
new file mode 100644
index 0000000..4a77af9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/fingerprint_dialog_bg_color" />
+    <corners android:radius="1dp"
+        android:topLeftRadius="16dp"
+        android:topRightRadius="16dp"
+        android:bottomLeftRadius="0dp"
+        android:bottomRightRadius="0dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_icon.xml b/packages/SystemUI/res/drawable/fingerprint_icon.xml
new file mode 100644
index 0000000..76a86ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fingerprint_icon.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="60dp"
+    android:height="60dp"
+    android:viewportWidth="60"
+    android:viewportHeight="60">
+
+    <path
+        android:fillColor="#1A73E8"
+        android:fillType="evenOdd"
+        android:strokeWidth="1"
+        android:pathData="M 30 0 C 46.5685424949 0 60 13.4314575051 60 30 C 60 46.5685424949 46.5685424949 60 30 60 C 13.4314575051 60 0 46.5685424949 0 30 C 0 13.4314575051 13.4314575051 0 30 0 Z" />
+    <group
+        android:translateX="17.727273"
+        android:translateY="16.363636">
+        <path
+            android:fillColor="#FFFFFF"
+            android:strokeWidth="1"
+            android:pathData="M20.3065726,3.44516129 C20.1974817,3.44516129 20.0883908,3.41788856
+19.9929362,3.36334311 C17.3747544,2.01334311 15.111118,1.44061584
+12.3974817,1.44061584 C9.69748166,1.44061584 7.1338453,2.08152493
+4.80202711,3.36334311 C4.47475439,3.54061584 4.06566348,3.41788856
+3.87475439,3.09061584 C3.69748166,2.76334311 3.82020893,2.34061584
+4.14748166,2.16334311 C6.6838453,0.786070381 9.46566348,0.0769794721
+12.3974817,0.0769794721 C15.3020271,0.0769794721 17.8383908,0.717888563
+20.6202089,2.14970674 C20.961118,2.32697947 21.0838453,2.73607038
+20.9065726,3.06334311 C20.7838453,3.30879765 20.5520271,3.44516129
+20.3065726,3.44516129 L20.3065726,3.44516129 Z M0.792936205,10.6042522
+C0.656572568,10.6042522 0.520208932,10.5633431 0.397481659,10.4815249
+C0.0838452956,10.2633431 0.0156634774,9.84061584 0.233845296,9.52697947
+C1.5838453,7.61788856 3.30202711,6.11788856 5.34748166,5.06788856
+C9.62929984,2.85879765 15.111118,2.84516129 19.4065726,5.0542522
+C21.4520271,6.1042522 23.1702089,7.59061584 24.5202089,9.48607038
+C24.7383908,9.78607038 24.6702089,10.222434 24.3565726,10.4406158
+C24.0429362,10.6587977 23.6202089,10.5906158 23.4020271,10.2769795
+C22.1747544,8.55879765 20.6202089,7.20879765 18.7792998,6.26788856
+C14.8656635,4.26334311 9.86111802,4.26334311 5.96111802,6.28152493
+C4.10657257,7.23607038 2.55202711,8.59970674 1.32475439,10.3178886
+C1.21566348,10.5087977 1.01111802,10.6042522 0.792936205,10.6042522
+L0.792936205,10.6042522 Z M9.31566348,27.0633431 C9.13839075,27.0633431
+8.96111802,26.9951613 8.83839075,26.8587977 C7.65202711,25.672434
+7.01111802,24.9087977 6.09748166,23.2587977 C5.15657257,21.5815249
+4.66566348,19.5360704 4.66566348,17.3406158 C4.66566348,13.2906158
+8.12929984,9.99061584 12.3838453,9.99061584 C16.6383908,9.99061584
+20.1020271,13.2906158 20.1020271,17.3406158 C20.1020271,17.722434
+19.8020271,18.022434 19.4202089,18.022434 C19.0383908,18.022434
+18.7383908,17.722434 18.7383908,17.3406158 C18.7383908,14.0406158
+15.8883908,11.3542522 12.3838453,11.3542522 C8.87929984,11.3542522
+6.02929984,14.0406158 6.02929984,17.3406158 C6.02929984,19.3042522
+6.46566348,21.1178886 7.29748166,22.5906158 C8.17020893,24.1587977
+8.77020893,24.8269795 9.82020893,25.8906158 C10.0792998,26.1633431
+10.0792998,26.5860704 9.82020893,26.8587977 C9.67020893,26.9951613
+9.4929362,27.0633431 9.31566348,27.0633431 Z M19.0929362,24.5406158
+C17.4702089,24.5406158 16.0383908,24.1315249 14.8656635,23.3269795
+C12.8338453,21.9497067 11.6202089,19.7133431 11.6202089,17.3406158
+C11.6202089,16.9587977 11.9202089,16.6587977 12.3020271,16.6587977
+C12.6838453,16.6587977 12.9838453,16.9587977 12.9838453,17.3406158
+C12.9838453,19.2633431 13.9656635,21.0769795 15.6292998,22.1951613
+C16.5974817,22.8497067 17.7292998,23.1633431 19.0929362,23.1633431
+C19.4202089,23.1633431 19.9656635,23.122434 20.511118,23.0269795
+C20.8792998,22.9587977 21.2338453,23.2042522 21.3020271,23.5860704
+C21.3702089,23.9542522 21.1247544,24.3087977 20.7429362,24.3769795
+C19.9656635,24.5269795 19.2838453,24.5406158 19.0929362,24.5406158
+L19.0929362,24.5406158 Z M16.3520271,27.3497067 C16.2974817,27.3497067
+16.2292998,27.3360704 16.1747544,27.322434 C14.0065726,26.722434
+12.5883908,25.9178886 11.1020271,24.4587977 C9.1929362,22.5633431
+8.1429362,20.0406158 8.1429362,17.3406158 C8.1429362,15.1315249
+10.0247544,13.3315249 12.3429362,13.3315249 C14.661118,13.3315249
+16.5429362,15.1315249 16.5429362,17.3406158 C16.5429362,18.7997067
+17.811118,19.9860704 19.3792998,19.9860704 C20.9474817,19.9860704
+22.2156635,18.7997067 22.2156635,17.3406158 C22.2156635,12.1997067
+17.7838453,8.02697947 12.3292998,8.02697947 C8.45657257,8.02697947
+4.91111802,10.1815249 3.31566348,13.522434 C2.7838453,14.6269795
+2.51111802,15.922434 2.51111802,17.3406158 C2.51111802,18.4042522
+2.60657257,20.0815249 3.42475439,22.2633431 C3.56111802,22.6178886
+3.3838453,23.0133431 3.02929984,23.1360704 C2.67475439,23.272434
+2.27929984,23.0815249 2.15657257,22.7406158 C1.48839075,20.9542522
+1.16111802,19.1815249 1.16111802,17.3406158 C1.16111802,15.7042522
+1.47475439,14.2178886 2.08839075,12.922434 C3.90202711,9.11788856
+7.92475439,6.64970674 12.3292998,6.64970674 C18.5338453,6.64970674
+23.5792998,11.4360704 23.5792998,17.3269795 C23.5792998,19.5360704
+21.6974817,21.3360704 19.3792998,21.3360704 C17.061118,21.3360704
+15.1792998,19.5360704 15.1792998,17.3269795 C15.1792998,15.8678886
+13.911118,14.6815249 12.3429362,14.6815249 C10.7747544,14.6815249
+9.50657257,15.8678886 9.50657257,17.3269795 C9.50657257,19.6587977
+10.4065726,21.8406158 12.0565726,23.4769795 C13.3520271,24.7587977
+14.5929362,25.4678886 16.5156635,25.9997067 C16.8838453,26.0951613
+17.0883908,26.4769795 16.9929362,26.8315249 C16.9247544,27.1451613
+16.6383908,27.3497067 16.3520271,27.3497067 L16.3520271,27.3497067 Z" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/fingerprint_dialog.xml
new file mode 100644
index 0000000..e5f62b3
--- /dev/null
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="bottom"
+    android:background="@color/fingerprint_dialog_dim_color"
+    android:orientation="vertical">
+
+    <!-- This is not a Space since Spaces cannot be clicked -->
+    <View
+        android:id="@+id/space"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+
+    <LinearLayout
+        android:id="@+id/dialog"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:elevation="2dp"
+        android:background="@drawable/fingerprint_dialog_bg">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:elevation="2dp">
+
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="@dimen/fingerprint_dialog_icon_size"
+                android:layout_height="@dimen/fingerprint_dialog_icon_size"
+                android:layout_marginTop="16dp"
+                android:layout_marginStart="16dp"
+                android:scaleType="centerInside" />
+
+            <TextView
+                android:id="@+id/title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@+id/icon"
+                android:layout_marginEnd="16dp"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="16dp"
+                android:textSize="20sp"
+                android:maxLines="1"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:marqueeRepeatLimit="marquee_forever"
+                android:textColor="@color/fingerprint_dialog_text_color"/>
+
+            <TextView
+                android:id="@+id/subtitle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@+id/icon"
+                android:layout_below="@+id/title"
+                android:layout_marginEnd="16dp"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="4dp"
+                android:textSize="12sp"
+                android:maxLines="2"
+                android:textColor="@color/fingerprint_dialog_text_color"/>
+
+        </RelativeLayout>
+
+        <TextView
+            android:id="@+id/description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="16dp"
+            android:paddingTop="16dp"
+            android:paddingBottom="20dp"
+            android:textSize="16sp"
+            android:maxLines="4"
+            android:textColor="@color/fingerprint_dialog_text_color"/>
+
+        <ImageView
+            android:id="@+id/fingerprint_icon"
+            android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
+            android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
+            android:layout_gravity="center_horizontal"
+            android:scaleType="centerInside"
+            android:src="@drawable/fingerprint_icon"/>
+
+        <TextView
+            android:id="@+id/error"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd = "16dp"
+            android:layout_marginStart="16dp"
+            android:paddingTop="16dp"
+            android:paddingBottom="60dp"
+            android:textSize="12sp"
+            android:visibility="invisible"
+            android:gravity="center_horizontal"
+            android:textColor="@color/fingerprint_error_message_color"/>
+
+        <LinearLayout android:id="@+id/buttonPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="54dip"
+            android:orientation="vertical" >
+            <LinearLayout
+                style="?android:attr/buttonBarStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:paddingTop="4dip"
+                android:paddingStart="2dip"
+                android:paddingEnd="2dip"
+                android:measureWithLargestChild="true">
+                <LinearLayout android:id="@+id/leftSpacer"
+                    android:layout_weight="0.25"
+                    android:layout_width="0dip"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:visibility="gone" />
+                <!-- Positive Button -->
+                <Button android:id="@+id/button1"
+                    android:layout_width="0dip"
+                    android:layout_gravity="start"
+                    android:layout_weight="1"
+                    style="?android:attr/buttonBarButtonStyle"
+                    android:maxLines="2"
+                    android:layout_height="wrap_content"/>
+                <!-- Negative Button -->
+                <Button android:id="@+id/button2"
+                    android:layout_width="0dip"
+                    android:layout_gravity="end"
+                    android:layout_weight="1"
+                    style="?android:attr/buttonBarButtonStyle"
+                    android:maxLines="2"
+                    android:layout_height="wrap_content" />
+                <LinearLayout android:id="@+id/rightSpacer"
+                    android:layout_width="0dip"
+                    android:layout_weight="0.25"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:visibility="gone" />
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/output_chooser.xml b/packages/SystemUI/res/layout/output_chooser.xml
index b96f447..b9f7b15 100644
--- a/packages/SystemUI/res/layout/output_chooser.xml
+++ b/packages/SystemUI/res/layout/output_chooser.xml
@@ -15,47 +15,56 @@
      limitations under the License.
 -->
 <!-- extends LinearLayout -->
-<com.android.systemui.volume.OutputChooserLayout
+<com.android.systemui.HardwareUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:sysui="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/output_chooser"
-    android:minWidth="320dp"
-    android:minHeight="320dp"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:padding="20dp" >
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textDirection="locale"
-        android:textAppearance="@style/TextAppearance.QS.DetailHeader"
-        android:layout_marginBottom="20dp" />
-
-    <com.android.systemui.qs.AutoSizingList
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
+    android:layout_marginBottom="0dp"
+    android:clipToPadding="false"
+    android:theme="@style/qs_theme"
+    android:clipChildren="false">
+    <com.android.systemui.volume.OutputChooserLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:sysui="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/output_chooser"
+        android:layout_width="@dimen/output_chooser_panel_width"
+        android:layout_height="@dimen/output_chooser_panel_width"
+        android:layout_gravity="center_vertical|end"
         android:orientation="vertical"
-        sysui:itemHeight="@dimen/qs_detail_item_height"
-        style="@style/AutoSizingList"/>
-
-    <LinearLayout
-        android:id="@android:id/empty"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"
-        android:gravity="center"
-        android:orientation="vertical">
+        android:translationZ="8dp"
+        android:padding="20dp" >
 
         <TextView
-            android:id="@+id/empty_text"
+            android:id="@+id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textDirection="locale"
-            android:layout_marginTop="20dp"
-            android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
-    </LinearLayout>
-</com.android.systemui.volume.OutputChooserLayout>
+            android:textAppearance="@style/TextAppearance.QS.DetailHeader"
+            android:layout_marginBottom="20dp" />
+
+        <com.android.systemui.qs.AutoSizingList
+            android:id="@android:id/list"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            sysui:itemHeight="@dimen/qs_detail_item_height"
+            style="@style/AutoSizingList"/>
+
+        <LinearLayout
+            android:id="@android:id/empty"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/empty_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textDirection="locale"
+                android:layout_marginTop="20dp"
+                android:textAppearance="@style/TextAppearance.QS.DetailEmpty"/>
+        </LinearLayout>
+    </com.android.systemui.volume.OutputChooserLayout>
+</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 5108f58..117cd14 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -41,6 +41,7 @@
             android:paddingTop="12dp"
             android:paddingBottom="12dp"
             android:background="@drawable/rounded_bg_full"
+            android:translationZ="8dp"
             android:orientation="horizontal" >
                 <!-- volume rows added and removed here! :-) -->
         </LinearLayout>
@@ -57,6 +58,7 @@
             android:background="@drawable/rounded_bg_full"
             android:gravity="center"
             android:layout_gravity="end"
+            android:translationZ="8dp"
             android:orientation="vertical" >
 
             <TextView
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0f4c3b8..4fcfdf7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -156,6 +156,14 @@
 
     <color name="zen_introduction">#ffffffff</color>
 
+
     <color name="smart_reply_button_text">#ff4285f4</color><!-- blue 500 -->
     <color name="smart_reply_button_background">#fff7f7f7</color>
+
+    <!-- Fingerprint dialog colors -->
+    <color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
+    <color name="fingerprint_dialog_text_color">#ff424242</color> <!-- gray 800-->
+    <color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
+    <color name="fingerprint_error_message_color">#ff5722</color>
+
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b33f857..6768470 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -350,6 +350,7 @@
         <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
         <item>com.android.systemui.RoundedCorners</item>
         <item>com.android.systemui.EmulatedDisplayCutout</item>
+        <item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
     </string-array>
 
     <!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 887d3cb..a90106d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -267,6 +267,8 @@
 
     <dimen name="volume_dialog_panel_width">120dp</dimen>
 
+    <dimen name="output_chooser_panel_width">320dp</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
@@ -579,7 +581,7 @@
     <dimen name="keyguard_affordance_icon_width">24dp</dimen>
 
     <dimen name="keyguard_indication_margin_bottom">65dp</dimen>
-    <dimen name="keyguard_indication_margin_bottom_ambient">30dp</dimen>
+    <dimen name="keyguard_indication_margin_bottom_ambient">16dp</dimen>
 
     <!-- The text size for battery level -->
     <dimen name="battery_level_text_size">12sp</dimen>
@@ -889,4 +891,8 @@
     <dimen name="smart_reply_button_spacing">8dp</dimen>
     <dimen name="smart_reply_button_padding_vertical">4dp</dimen>
     <dimen name="smart_reply_button_font_size">14sp</dimen>
+
+    <dimen name="fingerprint_dialog_icon_size">44dp</dimen>
+    <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
+    <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8d6b38f..7dc4587 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -459,7 +459,7 @@
     <string name="accessibility_casting">@string/quick_settings_casting</string>
 
     <!-- Content description of the work mode icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_work_mode">Work mode</string>
+    <string name="accessibility_work_mode">@string/quick_settings_work_mode_on_label</string>
 
     <!-- Content description to tell the user that this button will remove an application from recents -->
     <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
@@ -764,6 +764,11 @@
     <string name="quick_settings_tethering_label">Tethering</string>
     <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_hotspot_label">Hotspot</string>
+    <!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] -->
+    <plurals name="quick_settings_hotspot_num_devices">
+        <item quantity="one">%d device</item>
+        <item quantity="other">%d devices</item>
+    </plurals>
     <!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
     <string name="quick_settings_notifications_label">Notifications</string>
     <!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] -->
@@ -782,8 +787,14 @@
     <string name="quick_settings_cellular_detail_data_limit"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> limit</string>
     <!-- QuickSettings: Cellular detail panel, data warning format string [CHAR LIMIT=NONE] -->
     <string name="quick_settings_cellular_detail_data_warning"><xliff:g id="data_limit" example="2.0 GB">%s</xliff:g> warning</string>
-    <!-- QuickSettings: Work mode [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_work_mode_label">Work mode</string>
+    <!-- QuickSettings: This string is in the easy-to-view settings that a user can pull down from
+    the top of their phone's screen. This is a label for a toggle to turn the work profile on and
+    off. "Work profile" means a separate profile on a user's phone that's specifically for their
+    work apps and managed by their company. "Work" is used as an adjective. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_work_mode_on_label">Work profile</string>
+    <!-- QuickSettings: This is a label for a toggle to turn the work profile on and off and this is
+         shown when work profile is off. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_work_mode_off_label">Notifications &amp; apps are off</string>
     <!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
     <string name="quick_settings_night_display_label">Night Light</string>
     <!-- QuickSettings: Secondary text for when the Night Light will be enabled at sunset. [CHAR LIMIT=20] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 19afcf5..9e4b405 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1257,7 +1257,8 @@
                 mFingerprintCancelSignal.cancel();
             }
             mFingerprintCancelSignal = new CancellationSignal();
-            mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
+            mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null,
+                    userId);
             setFingerprintRunningState(FINGERPRINT_STATE_RUNNING);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index ca34345..9481788 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -58,6 +58,7 @@
     private boolean mRoundedDivider;
     private int mRotation = ROTATION_NONE;
     private boolean mRotatedBackground;
+    private boolean mSwapOrientation = true;
 
     public HardwareUiLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -145,6 +146,10 @@
         updateRotation();
     }
 
+    public void setSwapOrientation(boolean swapOrientation) {
+        mSwapOrientation = swapOrientation;
+    }
+
     private void updateRotation() {
         int rotation = RotationUtils.getRotation(getContext());
         if (rotation != mRotation) {
@@ -173,7 +178,9 @@
                 if (to == ROTATION_SEASCAPE) {
                     swapOrder(linearLayout);
                 }
-                linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+                if (mSwapOrientation) {
+                    linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+                }
                 swapDimens(this.mChild);
             }
         } else {
@@ -184,7 +191,9 @@
                 if (from == ROTATION_SEASCAPE) {
                     swapOrder(linearLayout);
                 }
-                linearLayout.setOrientation(LinearLayout.VERTICAL);
+                if (mSwapOrientation) {
+                    linearLayout.setOrientation(LinearLayout.VERTICAL);
+                }
                 swapDimens(mChild);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
new file mode 100644
index 0000000..262c71a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -0,0 +1,220 @@
+/*
+ * 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.fingerprint;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.fingerprint.FingerprintDialog;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.android.internal.os.SomeArgs;
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.CommandQueue;
+
+public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Callbacks {
+    private static final String TAG = "FingerprintDialogImpl";
+    private static final boolean DEBUG = true;
+
+    protected static final int MSG_SHOW_DIALOG = 1;
+    protected static final int MSG_FINGERPRINT_AUTHENTICATED = 2;
+    protected static final int MSG_FINGERPRINT_HELP = 3;
+    protected static final int MSG_FINGERPRINT_ERROR = 4;
+    protected static final int MSG_HIDE_DIALOG = 5;
+    protected static final int MSG_BUTTON_NEGATIVE = 6;
+    protected static final int MSG_USER_CANCELED = 7;
+    protected static final int MSG_BUTTON_POSITIVE = 8;
+    protected static final int MSG_CLEAR_MESSAGE = 9;
+
+
+    private FingerprintDialogView mDialogView;
+    private WindowManager mWindowManager;
+    private IFingerprintDialogReceiver mReceiver;
+    private boolean mDialogShowing;
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_SHOW_DIALOG:
+                    handleShowDialog((SomeArgs) msg.obj);
+                    break;
+                case MSG_FINGERPRINT_AUTHENTICATED:
+                    handleFingerprintAuthenticated();
+                    break;
+                case MSG_FINGERPRINT_HELP:
+                    handleFingerprintHelp((String) msg.obj);
+                    break;
+                case MSG_FINGERPRINT_ERROR:
+                    handleFingerprintError((String) msg.obj);
+                    break;
+                case MSG_HIDE_DIALOG:
+                    handleHideDialog((Boolean) msg.obj);
+                    break;
+                case MSG_BUTTON_NEGATIVE:
+                    handleButtonNegative();
+                    break;
+                case MSG_USER_CANCELED:
+                    handleUserCanceled();
+                    break;
+                case MSG_BUTTON_POSITIVE:
+                    handleButtonPositive();
+                    break;
+                case MSG_CLEAR_MESSAGE:
+                    handleClearMessage();
+                    break;
+            }
+        }
+    };
+
+    @Override
+    public void start() {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            return;
+        }
+        getComponent(CommandQueue.class).addCallbacks(this);
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        mDialogView = new FingerprintDialogView(mContext, mHandler);
+    }
+
+    @Override
+    public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+        if (DEBUG) Log.d(TAG, "showFingerprintDialog");
+        // Remove these messages as they are part of the previous client
+        mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
+        mHandler.removeMessages(MSG_FINGERPRINT_HELP);
+        mHandler.removeMessages(MSG_FINGERPRINT_AUTHENTICATED);
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = bundle;
+        args.arg2 = receiver;
+        mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
+    }
+
+    @Override
+    public void onFingerprintAuthenticated() {
+        if (DEBUG) Log.d(TAG, "onFingerprintAuthenticated");
+        mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED).sendToTarget();
+    }
+
+    @Override
+    public void onFingerprintHelp(String message) {
+        if (DEBUG) Log.d(TAG, "onFingerprintHelp: " + message);
+        mHandler.obtainMessage(MSG_FINGERPRINT_HELP, message).sendToTarget();
+    }
+
+    @Override
+    public void onFingerprintError(String error) {
+        if (DEBUG) Log.d(TAG, "onFingerprintError: " + error);
+        mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, error).sendToTarget();
+    }
+
+    @Override
+    public void hideFingerprintDialog() {
+        if (DEBUG) Log.d(TAG, "hideFingerprintDialog");
+        mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
+    }
+
+    private void handleShowDialog(SomeArgs args) {
+        if (DEBUG) Log.d(TAG, "handleShowDialog");
+        if (mDialogShowing) {
+            Log.w(TAG, "Dialog already showing");
+            return;
+        }
+        mReceiver = (IFingerprintDialogReceiver) args.arg2;
+        mDialogView.setBundle((Bundle)args.arg1);
+        mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
+        mDialogShowing = true;
+    }
+
+    private void handleFingerprintAuthenticated() {
+        if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated");
+        handleHideDialog(false /* userCanceled */);
+    }
+
+    private void handleFingerprintHelp(String message) {
+        if (DEBUG) Log.d(TAG, "handleFingerprintHelp: " + message);
+        mDialogView.showHelpMessage(message);
+    }
+
+    private void handleFingerprintError(String error) {
+        if (DEBUG) Log.d(TAG, "handleFingerprintError: " + error);
+        if (!mDialogShowing) {
+            if (DEBUG) Log.d(TAG, "Dialog already dismissed");
+            return;
+        }
+        mDialogView.showErrorMessage(error);
+    }
+
+    private void handleHideDialog(boolean userCanceled) {
+        if (DEBUG) Log.d(TAG, "handleHideDialog");
+        if (!mDialogShowing) {
+            // This can happen if there's a race and we get called from both
+            // onAuthenticated and onError, etc.
+            Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled);
+            return;
+        }
+        if (userCanceled) {
+            try {
+                mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_USER_CANCEL);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException when hiding dialog", e);
+            }
+        }
+        mReceiver = null;
+        mWindowManager.removeView(mDialogView);
+        mDialogShowing = false;
+    }
+
+    private void handleButtonNegative() {
+        if (mReceiver == null) {
+            Log.e(TAG, "Receiver is null");
+            return;
+        }
+        try {
+            mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_NEGATIVE);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote exception when handling negative button", e);
+        }
+        handleHideDialog(false /* userCanceled */);
+    }
+
+    private void handleButtonPositive() {
+        if (mReceiver == null) {
+            Log.e(TAG, "Receiver is null");
+            return;
+        }
+        try {
+            mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_POSITIVE);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote exception when handling positive button", e);
+        }
+        handleHideDialog(false /* userCanceled */);
+    }
+
+    private void handleClearMessage() {
+        mDialogView.clearMessage();
+    }
+
+    private void handleUserCanceled() {
+        handleHideDialog(true /* userCanceled */);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
new file mode 100644
index 0000000..19bc2ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -0,0 +1,228 @@
+/*
+ * 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.fingerprint;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.hardware.fingerprint.FingerprintDialog;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+/**
+ * This class loads the view for the system-provided dialog. The view consists of:
+ * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
+ * and positive/negative buttons.
+ */
+public class FingerprintDialogView extends LinearLayout {
+
+    private static final String TAG = "FingerprintDialogView";
+
+    private static final int ANIMATION_DURATION = 250; // ms
+
+    private final IBinder mWindowToken = new Binder();
+    private final ActivityManagerWrapper mActivityManagerWrapper;
+    private final PackageManagerWrapper mPackageManageWrapper;
+    private final Interpolator mLinearOutSlowIn;
+    private final Interpolator mFastOutLinearIn;
+    private final float mAnimationTranslationOffset;
+
+    private ViewGroup mLayout;
+    private final TextView mErrorText;
+    private Handler mHandler;
+    private Bundle mBundle;
+    private final LinearLayout mDialog;
+
+    public FingerprintDialogView(Context context, Handler handler) {
+        super(context);
+        mHandler = handler;
+        mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
+        mPackageManageWrapper = PackageManagerWrapper.getInstance();
+        mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
+        mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
+        mAnimationTranslationOffset = getResources()
+                .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
+
+        // Create the dialog
+        LayoutInflater factory = LayoutInflater.from(getContext());
+        mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
+        addView(mLayout);
+
+        mDialog = mLayout.findViewById(R.id.dialog);
+
+        mErrorText = mLayout.findViewById(R.id.error);
+
+        mLayout.setOnKeyListener(new View.OnKeyListener() {
+            boolean downPressed = false;
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode != KeyEvent.KEYCODE_BACK) {
+                    return false;
+                }
+                if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
+                    downPressed = true;
+                } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    downPressed = false;
+                } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
+                    downPressed = false;
+                    mHandler.obtainMessage(FingerprintDialogImpl.MSG_USER_CANCELED).sendToTarget();
+                }
+                return true;
+            }
+        });
+
+        final View space = mLayout.findViewById(R.id.space);
+        final Button negative = mLayout.findViewById(R.id.button2);
+        final Button positive = mLayout.findViewById(R.id.button1);
+
+        space.setClickable(true);
+        space.setOnTouchListener((View view, MotionEvent event) -> {
+            mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled*/)
+                    .sendToTarget();
+            return true;
+        });
+
+        negative.setOnClickListener((View v) -> {
+            mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_NEGATIVE).sendToTarget();
+        });
+
+        positive.setOnClickListener((View v) -> {
+            mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_POSITIVE).sendToTarget();
+        });
+
+        mLayout.setFocusableInTouchMode(true);
+        mLayout.requestFocus();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        final TextView title = mLayout.findViewById(R.id.title);
+        final TextView subtitle = mLayout.findViewById(R.id.subtitle);
+        final TextView description = mLayout.findViewById(R.id.description);
+        final Button negative = mLayout.findViewById(R.id.button2);
+        final ImageView image = mLayout.findViewById(R.id.icon);
+        final Button positive = mLayout.findViewById(R.id.button1);
+        final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
+
+        title.setText(mBundle.getCharSequence(FingerprintDialog.KEY_TITLE));
+        title.setSelected(true);
+        subtitle.setText(mBundle.getCharSequence(FingerprintDialog.KEY_SUBTITLE));
+        description.setText(mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION));
+        negative.setText(mBundle.getCharSequence(FingerprintDialog.KEY_NEGATIVE_TEXT));
+        image.setImageDrawable(getAppIcon());
+
+        final CharSequence positiveText =
+                mBundle.getCharSequence(FingerprintDialog.KEY_POSITIVE_TEXT);
+        positive.setText(positiveText); // needs to be set for marquee to work
+        if (positiveText != null) {
+            positive.setVisibility(View.VISIBLE);
+        } else {
+            positive.setVisibility(View.GONE);
+        }
+
+        // Dim the background and slide the dialog up
+        mDialog.setTranslationY(mAnimationTranslationOffset);
+        mLayout.setAlpha(0f);
+        postOnAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mLayout.animate()
+                        .alpha(1f)
+                        .setDuration(ANIMATION_DURATION)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .start();
+                mDialog.animate()
+                        .translationY(0)
+                        .setDuration(ANIMATION_DURATION)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .start();
+            }
+        });
+    }
+
+    public void setBundle(Bundle bundle) {
+        mBundle = bundle;
+    }
+
+    protected void clearMessage() {
+        mErrorText.setVisibility(View.INVISIBLE);
+    }
+
+    private void showMessage(String message) {
+        mHandler.removeMessages(FingerprintDialogImpl.MSG_CLEAR_MESSAGE);
+        mErrorText.setText(message);
+        mErrorText.setVisibility(View.VISIBLE);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
+                FingerprintDialog.HIDE_DIALOG_DELAY);
+    }
+
+    public void showHelpMessage(String message) {
+        showMessage(message);
+    }
+
+    public void showErrorMessage(String error) {
+        showMessage(error);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
+                false /* userCanceled */), FingerprintDialog.HIDE_DIALOG_DELAY);
+    }
+
+    private Drawable getAppIcon() {
+        final ActivityManager.RunningTaskInfo taskInfo = mActivityManagerWrapper.getRunningTask();
+        final ComponentName cn = taskInfo.topActivity;
+        final int userId = mActivityManagerWrapper.getCurrentUserId();
+        final ActivityInfo activityInfo = mPackageManageWrapper.getActivityInfo(cn, userId);
+        return mActivityManagerWrapper.getBadgedActivityIcon(activityInfo, userId);
+    }
+
+    public WindowManager.LayoutParams getLayoutParams() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.setTitle("FingerprintDialogView");
+        lp.token = mWindowToken;
+        return lp;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 910b6b1..e1b58fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -37,7 +38,7 @@
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
     static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
-             "com.android.settings", "com.android.settings.TetherSettings"));
+            "com.android.settings", "com.android.settings.TetherSettings"));
 
     private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
     private final Icon mUnavailable = ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
@@ -115,11 +116,19 @@
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
-        if (arg instanceof Boolean) {
-            state.value = (boolean) arg;
+
+        final int numConnectedDevices;
+        if (arg instanceof CallbackInfo) {
+            CallbackInfo info = (CallbackInfo) arg;
+            state.value = info.enabled;
+            numConnectedDevices = info.numConnectedDevices;
         } else {
             state.value = mController.isHotspotEnabled();
+            numConnectedDevices = mController.getNumConnectedDevices();
         }
+
+        state.secondaryLabel = getSecondaryLabel(state.value, numConnectedDevices);
+
         state.icon = mEnabledStatic;
         state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         state.isTransient = mController.isHotspotTransient();
@@ -133,6 +142,18 @@
                 : state.value || state.isTransient ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
+    @Nullable
+    private String getSecondaryLabel(boolean enabled, int numConnectedDevices) {
+        if (numConnectedDevices > 0 && enabled) {
+            return mContext.getResources().getQuantityString(
+                    R.plurals.quick_settings_hotspot_num_devices,
+                    numConnectedDevices,
+                    numConnectedDevices);
+        }
+
+        return null;
+    }
+
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.QS_HOTSPOT;
@@ -148,9 +169,30 @@
     }
 
     private final class Callback implements HotspotController.Callback {
+        final CallbackInfo mCallbackInfo = new CallbackInfo();
+
         @Override
-        public void onHotspotChanged(boolean enabled) {
-            refreshState(enabled);
+        public void onHotspotChanged(boolean enabled, int numConnectedDevices) {
+            mCallbackInfo.enabled = enabled;
+            mCallbackInfo.numConnectedDevices = numConnectedDevices;
+            refreshState(mCallbackInfo);
         }
-    };
+    }
+
+    /**
+     * Holder for any hotspot state info that needs to passed from the callback to
+     * {@link #handleUpdateState(State, Object)}.
+     */
+    protected static final class CallbackInfo {
+        boolean enabled;
+        int numConnectedDevices;
+
+        @Override
+        public String toString() {
+            return new StringBuilder("CallbackInfo[")
+                    .append("enabled=").append(enabled)
+                    .append(",numConnectedDevices=").append(numConnectedDevices)
+                    .append(']').toString();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 5f7d6fb..e098fd8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -83,7 +83,7 @@
 
     @Override
     public CharSequence getTileLabel() {
-        return mContext.getString(R.string.quick_settings_work_mode_label);
+        return mContext.getString(R.string.quick_settings_work_mode_on_label);
     }
 
     @Override
@@ -98,16 +98,17 @@
             state.value = mProfileController.isWorkModeEnabled();
         }
 
-        state.label = mContext.getString(R.string.quick_settings_work_mode_label);
         state.icon = mIcon;
         if (state.value) {
             state.slash.isSlashed = false;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_on);
+            state.label = mContext.getString(R.string.quick_settings_work_mode_on_label);
         } else {
             state.slash.isSlashed = true;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_off);
+            state.label = mContext.getString(R.string.quick_settings_work_mode_off_label);
         }
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c6abcf2..00bc62e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.Rect;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -83,6 +84,11 @@
     private static final int MSG_SHOW_SHUTDOWN_UI              = 36 << MSG_SHIFT;
     private static final int MSG_SET_TOP_APP_HIDES_STATUS_BAR  = 37 << MSG_SHIFT;
     private static final int MSG_ROTATION_PROPOSAL             = 38 << MSG_SHIFT;
+    private static final int MSG_FINGERPRINT_SHOW              = 39 << MSG_SHIFT;
+    private static final int MSG_FINGERPRINT_AUTHENTICATED     = 40 << MSG_SHIFT;
+    private static final int MSG_FINGERPRINT_HELP              = 41 << MSG_SHIFT;
+    private static final int MSG_FINGERPRINT_ERROR             = 42 << MSG_SHIFT;
+    private static final int MSG_FINGERPRINT_HIDE              = 43 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -145,6 +151,12 @@
         default void handleShowShutdownUi(boolean isReboot, String reason) { }
 
         default void onRotationProposal(int rotation, boolean isValid) { }
+
+        default void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) { }
+        default void onFingerprintAuthenticated() { }
+        default void onFingerprintHelp(String message) { }
+        default void onFingerprintError(String error) { }
+        default void hideFingerprintDialog() { }
     }
 
     @VisibleForTesting
@@ -470,6 +482,45 @@
         }
     }
 
+    @Override
+    public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+        synchronized (mLock) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = bundle;
+            args.arg2 = receiver;
+            mHandler.obtainMessage(MSG_FINGERPRINT_SHOW, args)
+                    .sendToTarget();
+        }
+    }
+
+    @Override
+    public void onFingerprintAuthenticated() {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED).sendToTarget();
+        }
+    }
+
+    @Override
+    public void onFingerprintHelp(String message) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_HELP, message).sendToTarget();
+        }
+    }
+
+    @Override
+    public void onFingerprintError(String error) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, error).sendToTarget();
+        }
+    }
+
+    @Override
+    public void hideFingerprintDialog() {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_HIDE).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -671,6 +722,35 @@
                         mCallbacks.get(i).onRotationProposal(msg.arg1, msg.arg2 != 0);
                     }
                     break;
+                case MSG_FINGERPRINT_SHOW:
+                    mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
+                    mHandler.removeMessages(MSG_FINGERPRINT_HELP);
+                    mHandler.removeMessages(MSG_FINGERPRINT_AUTHENTICATED);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showFingerprintDialog(
+                                (Bundle)((SomeArgs)msg.obj).arg1,
+                                (IFingerprintDialogReceiver)((SomeArgs)msg.obj).arg2);
+                    }
+                    break;
+                case MSG_FINGERPRINT_AUTHENTICATED:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).onFingerprintAuthenticated();
+                    }
+                    break;
+                case MSG_FINGERPRINT_HELP:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).onFingerprintHelp((String) msg.obj);
+                    }
+                    break;
+                case MSG_FINGERPRINT_ERROR:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).onFingerprintError((String) msg.obj);
+                    }
+                    break;
+                case MSG_FINGERPRINT_HIDE:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).hideFingerprintDialog();
+                    }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 64df92c..a4c17e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Build;
+import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -31,6 +32,7 @@
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.NotificationColorUtil;
@@ -42,6 +44,7 @@
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.statusbar.policy.SmartReplyView;
 
 /**
  * A frame layout containing the actual payload of the notification, including the contracted,
@@ -72,6 +75,7 @@
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
+    private SmartReplyView mExpandedSmartReplyView;
 
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
@@ -1125,7 +1129,7 @@
         if (mAmbientChild != null) {
             mAmbientWrapper.onContentUpdated(entry.row);
         }
-        applyRemoteInput(entry);
+        applyRemoteInputAndSmartReply(entry);
         updateLegacy();
         mForceSelectNextLayout = true;
         setDark(mDark, false /* animate */, 0 /* delay */);
@@ -1157,20 +1161,34 @@
         }
     }
 
-    private void applyRemoteInput(final NotificationData.Entry entry) {
+    private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
         if (mRemoteInputController == null) {
             return;
         }
 
+        boolean enableSmartReplies = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS, 0) != 0;
+
         boolean hasRemoteInput = false;
+        RemoteInput remoteInputWithChoices = null;
+        PendingIntent pendingIntentWithChoices = null;
 
         Notification.Action[] actions = entry.notification.getNotification().actions;
         if (actions != null) {
             for (Notification.Action a : actions) {
                 if (a.getRemoteInputs() != null) {
                     for (RemoteInput ri : a.getRemoteInputs()) {
-                        if (ri.getAllowFreeFormInput()) {
+                        boolean showRemoteInputView = ri.getAllowFreeFormInput();
+                        boolean showSmartReplyView = enableSmartReplies && ri.getChoices() != null
+                                && ri.getChoices().length > 0;
+                        if (showRemoteInputView) {
                             hasRemoteInput = true;
+                        }
+                        if (showSmartReplyView) {
+                            remoteInputWithChoices = ri;
+                            pendingIntentWithChoices = a.actionIntent;
+                        }
+                        if (showRemoteInputView || showSmartReplyView) {
                             break;
                         }
                     }
@@ -1178,6 +1196,11 @@
             }
         }
 
+        applyRemoteInput(entry, hasRemoteInput);
+        applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices);
+    }
+
+    private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) {
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
             mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
@@ -1274,6 +1297,40 @@
         return null;
     }
 
+    private void applySmartReplyView(RemoteInput remoteInput, PendingIntent pendingIntent) {
+        mExpandedSmartReplyView = mExpandedChild == null ?
+                null : applySmartReplyView(mExpandedChild, remoteInput, pendingIntent);
+    }
+
+    private SmartReplyView applySmartReplyView(
+            View view, RemoteInput remoteInput, PendingIntent pendingIntent) {
+        View smartReplyContainerCandidate = view.findViewById(
+                com.android.internal.R.id.smart_reply_container);
+        if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
+            return null;
+        }
+        LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
+        if (remoteInput == null || pendingIntent == null) {
+            smartReplyContainer.setVisibility(View.GONE);
+            return null;
+        }
+        SmartReplyView smartReplyView = null;
+        if (smartReplyContainer.getChildCount() == 0) {
+            smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
+            smartReplyContainer.addView(smartReplyView);
+        } else if (smartReplyContainer.getChildCount() == 1) {
+            View child = smartReplyContainer.getChildAt(0);
+            if (child instanceof SmartReplyView) {
+                smartReplyView = (SmartReplyView) child;
+            }
+        }
+        if (smartReplyView != null) {
+            smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent);
+            smartReplyContainer.setVisibility(View.VISIBLE);
+        }
+        return smartReplyView;
+    }
+
     public void closeRemoteInput() {
         if (mHeadsUpRemoteInput != null) {
             mHeadsUpRemoteInput.close();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 149ec0b..36f9f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -127,7 +127,7 @@
 
     private final HotspotController.Callback mHotspotCallback = new Callback() {
         @Override
-        public void onHotspotChanged(boolean enabled) {
+        public void onHotspotChanged(boolean enabled, int numDevices) {
             if (mAutoTracker.isAdded(HOTSPOT)) return;
             if (enabled) {
                 mHost.addTile(HOTSPOT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6857337..20b5018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -665,7 +665,7 @@
 
     private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
         @Override
-        public void onHotspotChanged(boolean enabled) {
+        public void onHotspotChanged(boolean enabled, int numDevices) {
             mIconController.setIconVisibility(mSlotHotspot, enabled);
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 6457209..830b50e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -26,7 +26,9 @@
     void setHotspotEnabled(boolean enabled);
     boolean isHotspotSupported();
 
-    public interface Callback {
-        void onHotspotChanged(boolean enabled);
+    int getNumConnectedDevices();
+
+    interface Callback {
+        void onHotspotChanged(boolean enabled, int numDevices);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 1ebb986..8792b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -23,31 +23,35 @@
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
-import android.os.Handler;
 import android.os.UserManager;
 import android.util.Log;
 
+import com.android.systemui.Dependency;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-public class HotspotControllerImpl implements HotspotController {
+public class HotspotControllerImpl implements HotspotController, WifiManager.SoftApCallback {
 
     private static final String TAG = "HotspotController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
-    private final Receiver mReceiver = new Receiver();
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+    private final WifiStateReceiver mWifiStateReceiver = new WifiStateReceiver();
     private final ConnectivityManager mConnectivityManager;
+    private final WifiManager mWifiManager;
     private final Context mContext;
 
     private int mHotspotState;
+    private int mNumConnectedDevices;
     private boolean mWaitingForCallback;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
-        mConnectivityManager = (ConnectivityManager) context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
+        mConnectivityManager =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     }
 
     @Override
@@ -84,7 +88,8 @@
             if (callback == null || mCallbacks.contains(callback)) return;
             if (DEBUG) Log.d(TAG, "addCallback " + callback);
             mCallbacks.add(callback);
-            mReceiver.setListening(!mCallbacks.isEmpty());
+
+            updateWifiStateListeners(!mCallbacks.isEmpty());
         }
     }
 
@@ -94,7 +99,26 @@
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         synchronized (mCallbacks) {
             mCallbacks.remove(callback);
-            mReceiver.setListening(!mCallbacks.isEmpty());
+
+            updateWifiStateListeners(!mCallbacks.isEmpty());
+        }
+    }
+
+    /**
+     * Updates the wifi state receiver to either start or stop listening to get updates to the
+     * hotspot status. Additionally starts listening to wifi manager state to track the number of
+     * connected devices.
+     *
+     * @param shouldListen whether we should start listening to various wifi statuses
+     */
+    private void updateWifiStateListeners(boolean shouldListen) {
+        mWifiStateReceiver.setListening(shouldListen);
+        if (shouldListen) {
+            mWifiManager.registerSoftApCallback(
+                    this,
+                    Dependency.get(Dependency.MAIN_HANDLER));
+        } else {
+            mWifiManager.unregisterSoftApCallback(this);
         }
     }
 
@@ -116,20 +140,55 @@
             if (DEBUG) Log.d(TAG, "Starting tethering");
             mConnectivityManager.startTethering(
                     ConnectivityManager.TETHERING_WIFI, false, callback);
-            fireCallback(isHotspotEnabled());
+            fireHotspotChangedCallback(isHotspotEnabled());
         } else {
             mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
         }
     }
 
-    private void fireCallback(boolean isEnabled) {
+    @Override
+    public int getNumConnectedDevices() {
+        return mNumConnectedDevices;
+    }
+
+    /**
+     * Sends a hotspot changed callback with the new enabled status. Wraps
+     * {@link #fireHotspotChangedCallback(boolean, int)} and assumes that the number of devices has
+     * not changed.
+     *
+     * @param enabled whether the hotspot is enabled
+     */
+    private void fireHotspotChangedCallback(boolean enabled) {
+        fireHotspotChangedCallback(enabled, mNumConnectedDevices);
+    }
+
+    /**
+     * Sends a hotspot changed callback with the new enabled status & the number of devices
+     * connected to the hotspot. Be careful when calling over multiple threads, especially if one of
+     * them is the main thread (as it can be blocked).
+     *
+     * @param enabled whether the hotspot is enabled
+     * @param numConnectedDevices number of devices connected to the hotspot
+     */
+    private void fireHotspotChangedCallback(boolean enabled, int numConnectedDevices) {
         synchronized (mCallbacks) {
             for (Callback callback : mCallbacks) {
-                callback.onHotspotChanged(isEnabled);
+                callback.onHotspotChanged(enabled, numConnectedDevices);
             }
         }
     }
 
+    @Override
+    public void onStateChanged(int state, int failureReason) {
+        // Do nothing - we don't care about changing anything here.
+    }
+
+    @Override
+    public void onNumClientsChanged(int numConnectedDevices) {
+        mNumConnectedDevices = numConnectedDevices;
+        fireHotspotChangedCallback(isHotspotEnabled(), numConnectedDevices);
+    }
+
     private final class OnStartTetheringCallback extends
             ConnectivityManager.OnStartTetheringCallback {
         @Override
@@ -143,12 +202,15 @@
         public void onTetheringFailed() {
             if (DEBUG) Log.d(TAG, "onTetheringFailed");
             mWaitingForCallback = false;
-            fireCallback(isHotspotEnabled());
+            fireHotspotChangedCallback(isHotspotEnabled());
           // TODO: Show error.
         }
     }
 
-    private final class Receiver extends BroadcastReceiver {
+    /**
+     * Class to listen in on wifi state and update the hotspot state
+     */
+    private final class WifiStateReceiver extends BroadcastReceiver {
         private boolean mRegistered;
 
         public void setListening(boolean listening) {
@@ -170,8 +232,17 @@
             int state = intent.getIntExtra(
                     WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
             if (DEBUG) Log.d(TAG, "onReceive " + state);
+
+            // Update internal hotspot state for tracking before using any enabled/callback methods.
             mHotspotState = state;
-            fireCallback(mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED);
+
+            if (!isHotspotEnabled()) {
+                // Reset num devices if the hotspot is no longer enabled so we don't get ghost
+                // counters.
+                mNumConnectedDevices = 0;
+            }
+
+            fireHotspotChangedCallback(isHotspotEnabled());
         }
     }
 }
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 4ee4ef4..0b666a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -16,11 +16,12 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.android.settingslib.Utils.updateLocationEnabled;
+
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -28,19 +29,14 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+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.R;
 import com.android.systemui.util.Utils;
-
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.android.settingslib.Utils.updateLocationMode;
-
 /**
  * A controller to manage changes of location related states and update the views accordingly.
  */
@@ -101,32 +97,27 @@
      * @return true if attempt to change setting was successful.
      */
     public boolean setLocationEnabled(boolean enabled) {
+        // QuickSettings always runs as the owner, so specifically set the settings
+        // for the current foreground user.
         int currentUserId = ActivityManager.getCurrentUser();
         if (isUserLocationRestricted(currentUserId)) {
             return false;
         }
-        final ContentResolver cr = mContext.getContentResolver();
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
-        int currentMode = Settings.Secure.getIntForUser(cr, Settings.Secure.LOCATION_MODE, 
-                Settings.Secure.LOCATION_MODE_OFF, currentUserId);
-        int mode = enabled
-                ? Settings.Secure.LOCATION_MODE_PREVIOUS : Settings.Secure.LOCATION_MODE_OFF;
-        // QuickSettings always runs as the owner, so specifically set the settings
-        // for the current foreground user.
-        return updateLocationMode(mContext, currentMode, mode, currentUserId);
+        updateLocationEnabled(mContext, enabled, currentUserId);
+        return true;
     }
 
     /**
-     * Returns true if location isn't disabled in settings.
+     * Returns true if location is enabled in settings.
      */
     public boolean isLocationEnabled() {
-        ContentResolver resolver = mContext.getContentResolver();
         // QuickSettings always runs as the owner, so specifically retrieve the settings
         // for the current foreground user.
-        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
-                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
-        return mode != Settings.Secure.LOCATION_MODE_OFF;
+        LocationManager locationManager =
+                (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        return locationManager.isLocationEnabledForUser(Process.myUserHandle());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index c377feb..b63c1da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -137,6 +137,7 @@
         Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
                 results);
+        RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT);
 
         mEditText.setEnabled(false);
         mSendButton.setVisibility(INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 1dcdf63..2d829af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -52,6 +52,7 @@
             results.putString(remoteInput.getResultKey(), choice.toString());
             Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
             RemoteInput.addResultsToIntent(new RemoteInput[]{remoteInput}, intent, results);
+            RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
             try {
                 pendingIntent.send(context, 0, intent);
             } catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
index e0af9ba..e3c8503 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
@@ -22,6 +22,7 @@
 
 import static com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription;
 
+import android.app.Dialog;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -30,6 +31,8 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -43,12 +46,16 @@
 import android.telecom.TelecomManager;
 import android.util.Log;
 import android.util.Pair;
+import android.view.Window;
+import android.view.WindowManager;
 
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.Dependency;
+import com.android.systemui.HardwareUiLayout;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 
 import java.io.IOException;
@@ -58,7 +65,7 @@
 import java.util.Comparator;
 import java.util.List;
 
-public class OutputChooserDialog extends SystemUIDialog
+public class OutputChooserDialog extends Dialog
         implements DialogInterface.OnDismissListener, OutputChooserLayout.Callback {
 
     private static final String TAG = Util.logTag(OutputChooserDialog.class);
@@ -82,9 +89,11 @@
     private Drawable mTvIcon;
     private Drawable mSpeakerIcon;
     private Drawable mSpeakerGroupIcon;
+    private HardwareUiLayout mHardwareLayout;
+    private final VolumeDialogController mController;
 
     public OutputChooserDialog(Context context, MediaRouterWrapper router) {
-        super(context);
+        super(context, com.android.systemui.R.style.qs_theme);
         mContext = context;
         mBluetoothController = Dependency.get(BluetoothController.class);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -98,6 +107,22 @@
 
         final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         context.registerReceiver(mReceiver, filter);
+
+        mController = Dependency.get(VolumeDialogController.class);
+
+        // Window initialization
+        Window window = getWindow();
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+        window.addFlags(
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
     }
 
     protected void setIsInCall(boolean inCall) {
@@ -112,6 +137,9 @@
         setOnDismissListener(this::onDismiss);
 
         mView = findViewById(R.id.output_chooser);
+        mHardwareLayout = HardwareUiLayout.get(mView);
+        mHardwareLayout.setOutsideTouchListener(view -> dismiss());
+        mHardwareLayout.setSwapOrientation(false);
         mView.setCallback(this);
 
         if (mIsInCall) {
@@ -151,6 +179,7 @@
                     MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
         }
         mBluetoothController.addCallback(mCallback);
+        mController.addCallback(mControllerCallbackH, mHandler);
         isAttached = true;
     }
 
@@ -158,6 +187,7 @@
     public void onDetachedFromWindow() {
         isAttached = false;
         mRouter.removeCallback(mRouterCallback);
+        mController.removeCallback(mControllerCallbackH);
         mBluetoothController.removeCallback(mCallback);
         super.onDetachedFromWindow();
     }
@@ -169,6 +199,38 @@
     }
 
     @Override
+    public void show() {
+        super.show();
+        mHardwareLayout.setTranslationX(getAnimTranslation());
+        mHardwareLayout.setAlpha(0);
+        mHardwareLayout.animate()
+                .alpha(1)
+                .translationX(0)
+                .setDuration(300)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .withEndAction(() -> getWindow().getDecorView().requestAccessibilityFocus())
+                .start();
+    }
+
+    @Override
+    public void dismiss() {
+        mHardwareLayout.setTranslationX(0);
+        mHardwareLayout.setAlpha(1);
+        mHardwareLayout.animate()
+                .alpha(0)
+                .translationX(getAnimTranslation())
+                .setDuration(300)
+                .withEndAction(() -> super.dismiss())
+                .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+                .start();
+    }
+
+    private float getAnimTranslation() {
+        return getContext().getResources().getDimension(
+                com.android.systemui.R.dimen.output_chooser_panel_width) / 2;
+    }
+
+    @Override
     public void onDetailItemClick(OutputChooserLayout.Item item) {
         if (item == null || item.tag == null) return;
         if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) {
@@ -416,4 +478,41 @@
             }
         }
     };
+
+    private final VolumeDialogController.Callbacks mControllerCallbackH
+            = new VolumeDialogController.Callbacks() {
+        @Override
+        public void onShowRequested(int reason) {
+            dismiss();
+        }
+
+        @Override
+        public void onDismissRequested(int reason) {}
+
+        @Override
+        public void onScreenOff() {
+            dismiss();
+        }
+
+        @Override
+        public void onStateChanged(VolumeDialogController.State state) {}
+
+        @Override
+        public void onLayoutDirectionChanged(int layoutDirection) {}
+
+        @Override
+        public void onConfigurationChanged() {}
+
+        @Override
+        public void onShowVibrateHint() {}
+
+        @Override
+        public void onShowSilentHint() {}
+
+        @Override
+        public void onShowSafetyWarning(int flags) {}
+
+        @Override
+        public void onAccessibilityModeChanged(Boolean showA11yStream) {}
+    };
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e76bf57..385438c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -368,16 +368,16 @@
                 mController.setActiveStream(row.stream);
                 if (row.stream == AudioManager.STREAM_RING) {
                     final boolean hasVibrator = mController.hasVibrator();
-                    if (mState.ringerModeExternal == AudioManager.RINGER_MODE_NORMAL) {
+                    if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
                         if (hasVibrator) {
-                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, true);
+                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
                         } else {
                             final boolean wasZero = row.ss.level == 0;
                             mController.setStreamVolume(stream,
                                     wasZero ? row.lastAudibleLevel : 0);
                         }
                     } else {
-                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, true);
+                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
                         if (row.ss.level == 0) {
                             mController.setStreamVolume(stream, 1);
                         }
@@ -403,15 +403,15 @@
                 return;
             }
             final boolean hasVibrator = mController.hasVibrator();
-            if (mState.ringerModeExternal == AudioManager.RINGER_MODE_NORMAL) {
+            if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
                 if (hasVibrator) {
-                    mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, true);
+                    mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
                 } else {
                     final boolean wasZero = ss.level == 0;
                     mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
                 }
             } else {
-                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, true);
+                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
                 if (ss.level == 0) {
                     mController.setStreamVolume(AudioManager.STREAM_RING, 1);
                 }
@@ -552,7 +552,7 @@
             if (ss == null) {
                 return;
             }
-            switch (mState.ringerModeExternal) {
+            switch (mState.ringerModeInternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
                     mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
@@ -653,9 +653,9 @@
         final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
         final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
         final boolean isRingVibrate = isRingStream
-                && mState.ringerModeExternal == AudioManager.RINGER_MODE_VIBRATE;
+                && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
         final boolean isRingSilent = isRingStream
-                && mState.ringerModeExternal == AudioManager.RINGER_MODE_SILENT;
+                && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
         final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
         final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
         final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
index 1c9cbc1..368194e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -127,17 +128,26 @@
         rotate(mChild, from, to, true);
         ViewGroup rows = mChild.findViewById(R.id.volume_dialog_rows);
         rotate(rows, from, to, true);
+        swapOrientation((LinearLayout) rows);
         int rowCount = rows.getChildCount();
         for (int i = 0; i < rowCount; i++) {
-            View child = rows.getChildAt(i);
+            View row = rows.getChildAt(i);
             if (to == ROTATION_SEASCAPE) {
-                rotateSeekBars(to, 0);
+                rotateSeekBars(row, to, 180);
             } else if (to == ROTATION_LANDSCAPE) {
-                rotateSeekBars(to, 180);
+                rotateSeekBars(row, to, 0);
             } else {
-                rotateSeekBars(to, 270);
+                rotateSeekBars(row, to, 270);
             }
-            rotate(child, from, to, true);
+            rotate(row, from, to, true);
+        }
+    }
+
+    private void swapOrientation(LinearLayout layout) {
+        if(layout.getOrientation() == LinearLayout.HORIZONTAL) {
+            layout.setOrientation(LinearLayout.VERTICAL);
+        } else {
+            layout.setOrientation(LinearLayout.HORIZONTAL);
         }
     }
 
@@ -152,13 +162,13 @@
         v.setLayoutParams(params);
     }
 
-    private void rotateSeekBars(int to, int rotation) {
-        SeekBar seekbar = mChild.findViewById(R.id.volume_row_slider);
+    private void rotateSeekBars(View row, int to, int rotation) {
+        SeekBar seekbar = row.findViewById(R.id.volume_row_slider);
         if (seekbar != null) {
             seekbar.setRotation((float) rotation);
         }
 
-        View parent = mChild.findViewById(R.id.volume_row_slider_frame);
+        View parent = row.findViewById(R.id.volume_row_slider_frame);
         swapDimens(parent);
         ViewGroup.LayoutParams params = seekbar.getLayoutParams();
         ViewGroup.LayoutParams parentParams = parent.getLayoutParams();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 859dc2f..f5e079c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -47,6 +47,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
new file mode 100644
index 0000000..76a3c95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * 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.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/** A simple receiver to wait for broadcast intents in tests. */
+public class BlockingQueueIntentReceiver extends BroadcastReceiver {
+    private final BlockingQueue<Intent> mQueue = new ArrayBlockingQueue<Intent>(1);
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mQueue.add(intent);
+    }
+
+    public Intent waitForIntent() throws InterruptedException {
+        return mQueue.poll(10, TimeUnit.SECONDS);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
new file mode 100644
index 0000000..63920a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.statusbar.policy;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ShortcutManager;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.widget.EditText;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.RemoteInputController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class RemoteInputViewTest extends SysuiTestCase {
+
+    private static final String TEST_RESULT_KEY = "test_result_key";
+    private static final String TEST_REPLY = "hello";
+    private static final String TEST_ACTION = "com.android.ACTION";
+
+    @Mock private RemoteInputController mController;
+    @Mock private ShortcutManager mShortcutManager;
+    private BlockingQueueIntentReceiver mReceiver;
+    private RemoteInputView mView;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mReceiver = new BlockingQueueIntentReceiver();
+        mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
+
+        // Avoid SecurityException RemoteInputView#sendRemoteInput().
+        mContext.addMockSystemService(ShortcutManager.class, mShortcutManager);
+
+        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow();
+        mView = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
+    }
+
+    @Test
+    public void testSendRemoteInput_intentContainsResultsAndSource() throws InterruptedException {
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+                new Intent(TEST_ACTION), 0);
+        RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
+
+        mView.setPendingIntent(pendingIntent);
+        mView.setRemoteInput(new RemoteInput[]{input}, input);
+        mView.focus();
+
+        EditText editText = mView.findViewById(R.id.remote_input_text);
+        editText.setText(TEST_REPLY);
+        ImageButton sendButton = mView.findViewById(R.id.remote_input_send);
+        sendButton.performClick();
+
+        Intent resultIntent = mReceiver.waitForIntent();
+        assertEquals(TEST_REPLY,
+                RemoteInput.getResultsFromIntent(resultIntent).get(TEST_RESULT_KEY));
+        assertEquals(RemoteInput.SOURCE_FREE_FORM_INPUT,
+                RemoteInput.getResultsSource(resultIntent));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
new file mode 100644
index 0000000..0c3637d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.statusbar.policy;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class SmartReplyViewTest extends SysuiTestCase {
+
+    private static final String TEST_RESULT_KEY = "test_result_key";
+    private static final String TEST_ACTION = "com.android.ACTION";
+    private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"};
+
+    private BlockingQueueIntentReceiver mReceiver;
+    private SmartReplyView mView;
+
+    @Before
+    public void setUp() {
+        mReceiver = new BlockingQueueIntentReceiver();
+        mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
+
+        mView = SmartReplyView.inflate(mContext, null);
+    }
+
+    @Test
+    public void testSendSmartReply_intentContainsResultsAndSource() throws InterruptedException {
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+                new Intent(TEST_ACTION), 0);
+        RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(
+                TEST_CHOICES).build();
+
+        mView.setRepliesFromRemoteInput(input, pendingIntent);
+
+        mView.getChildAt(2).performClick();
+
+        Intent resultIntent = mReceiver.waitForIntent();
+        assertEquals(TEST_CHOICES[2],
+                RemoteInput.getResultsFromIntent(resultIntent).get(TEST_RESULT_KEY));
+        assertEquals(RemoteInput.SOURCE_CHOICE, RemoteInput.getResultsSource(resultIntent));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
index 5491147..016160a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
@@ -44,4 +44,9 @@
     public boolean isHotspotSupported() {
         return false;
     }
+
+    @Override
+    public int getNumConnectedDevices() {
+        return 0;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
index 537d606..de99d71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
@@ -38,6 +38,7 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 
 import org.junit.After;
@@ -54,6 +55,8 @@
     OutputChooserDialog mDialog;
 
     @Mock
+    private VolumeDialogController mVolumeController;
+    @Mock
     private BluetoothController mController;
     @Mock
     private WifiManager mWifiManager;
@@ -69,6 +72,7 @@
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mVolumeController = mDependency.injectMockDependency(VolumeDialogController.class);
         mController = mDependency.injectMockDependency(BluetoothController.class);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
 
@@ -78,20 +82,10 @@
         mDialog = new OutputChooserDialog(getContext(), mRouter);
     }
 
-    @After
-    @UiThreadTest
-    public void tearDown() throws Exception {
-        mDialog.dismiss();
-    }
-
-    private void showDialog() {
-        mDialog.show();
-    }
-
     @Test
     @UiThreadTest
     public void testClickMediaRouterItemConnectsMedia() {
-        showDialog();
+        mDialog.show();
 
         OutputChooserLayout.Item item = new OutputChooserLayout.Item();
         item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER;
@@ -102,12 +96,13 @@
         mDialog.onDetailItemClick(item);
         verify(info, times(1)).select();
         verify(mController, never()).connect(any());
+        mDialog.dismiss();
     }
 
     @Test
     @UiThreadTest
     public void testClickBtItemConnectsBt() {
-        showDialog();
+        mDialog.show();
 
         OutputChooserLayout.Item item = new OutputChooserLayout.Item();
         item.deviceType = OutputChooserLayout.Item.DEVICE_TYPE_BT;
@@ -117,25 +112,28 @@
 
         mDialog.onDetailItemClick(item);
         verify(mController, times(1)).connect(any());
+        mDialog.dismiss();
     }
 
     @Test
     @UiThreadTest
     public void testTitleNotInCall() {
-        showDialog();
+        mDialog.show();
 
         assertTrue(((TextView) mDialog.findViewById(R.id.title))
                 .getText().toString().contains("Media"));
+        mDialog.dismiss();
     }
 
     @Test
     @UiThreadTest
     public void testTitleInCall() {
         mDialog.setIsInCall(true);
-        showDialog();
+        mDialog.show();
 
         assertTrue(((TextView) mDialog.findViewById(R.id.title))
                 .getText().toString().contains("Phone"));
+        mDialog.dismiss();
     }
 
     @Test
@@ -155,4 +153,26 @@
 
         verify(mRouter, times(1)).addCallback(any(), any(), anyInt());
     }
+
+    @Test
+    @UiThreadTest
+    public void testRegisterCallbacks() {
+        mDialog.setIsInCall(false);
+        mDialog.onAttachedToWindow();
+
+        verify(mRouter, times(1)).addCallback(any(), any(), anyInt());
+        verify(mController, times(1)).addCallback(any());
+        verify(mVolumeController, times(1)).addCallback(any(), any());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testUnregisterCallbacks() {
+        mDialog.setIsInCall(false);
+        mDialog.onDetachedFromWindow();
+
+        verify(mRouter, times(1)).removeCallback(any());
+        verify(mController, times(1)).removeCallback(any());
+        verify(mVolumeController, times(1)).removeCallback(any());
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 0a03b7f..0bc95f4 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -37,7 +37,9 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.TypedValue;
@@ -154,6 +156,12 @@
             MagnificationController magnificationController,
             boolean detectTripleTap,
             boolean detectShortcutTrigger) {
+        if (DEBUG_ALL) {
+            Log.i(LOG_TAG,
+                    "MagnificationGestureHandler(detectTripleTap = " + detectTripleTap
+                            + ", detectShortcutTrigger = " + detectShortcutTrigger + ")");
+        }
+
         mMagnificationController = magnificationController;
 
         mDelegatingState = new DelegatingState();
@@ -581,7 +589,7 @@
 
         @VisibleForTesting boolean mShortcutTriggered;
 
-        Handler mHandler = new Handler(this);
+        @VisibleForTesting Handler mHandler = new Handler(this);
 
         public DetectingState(Context context) {
             mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
@@ -756,11 +764,14 @@
         @Override
         public void clear() {
             setShortcutTriggered(false);
-            mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
-            mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+            removePendingDelayedMessages();
             clearDelayedMotionEvents();
         }
 
+        private void removePendingDelayedMessages() {
+            mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
+            mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+        }
 
         private void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
                 int policyFlags) {
@@ -811,7 +822,7 @@
         void transitionToDelegatingStateAndClear() {
             transitionTo(mDelegatingState);
             sendDelayedMotionEvents();
-            clear();
+            removePendingDelayedMessages();
         }
 
         private void onTripleTap(MotionEvent up) {
@@ -860,6 +871,7 @@
             if (mShortcutTriggered == state) {
                 return;
             }
+            if (DEBUG_DETECTING) Slog.i(LOG_TAG, "setShortcutTriggered(" + state + ")");
 
             mShortcutTriggered = state;
             mMagnificationController.setForceShowMagnifiableBounds(state);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 978ed253..0e2ca14 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -119,6 +119,7 @@
 
     private final LocalLog mRequestsHistory = new LocalLog(20);
     private final LocalLog mUiLatencyHistory = new LocalLog(20);
+    private final LocalLog mWtfHistory = new LocalLog(50);
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -310,7 +311,8 @@
         AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
         if (service == null) {
             service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
-                    mUiLatencyHistory, resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
+                    mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
+                    mDisabledUsers.get(resolvedUserId));
             mServicesCache.put(userId, service);
         }
         return service;
@@ -878,10 +880,12 @@
                     mUi.dump(pw);
                 }
                 if (showHistory) {
-                    pw.println("Requests history:");
+                    pw.println(); pw.println("Requests history:"); pw.println();
                     mRequestsHistory.reverseDump(fd, pw, args);
-                    pw.println("UI latency history:");
+                    pw.println(); pw.println("UI latency history:"); pw.println();
                     mUiLatencyHistory.reverseDump(fd, pw, args);
+                    pw.println(); pw.println("WTF history:"); pw.println();
+                    mWtfHistory.reverseDump(fd, pw, args);
                 }
             } finally {
                 setDebugLocked(oldDebug);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6bcfc4b..07b0b77 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -43,7 +43,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -116,6 +115,7 @@
 
     private final LocalLog mRequestsHistory;
     private final LocalLog mUiLatencyHistory;
+    private final LocalLog mWtfHistory;
     private final FieldClassificationStrategy mFieldClassificationStrategy;
 
     /**
@@ -179,11 +179,13 @@
     private long mLastPrune = 0;
 
     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
-            LocalLog uiLatencyHistory, int userId, AutoFillUI ui, boolean disabled) {
+            LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
+            boolean disabled) {
         mContext = context;
         mLock = lock;
         mRequestsHistory = requestsHistory;
         mUiLatencyHistory = uiLatencyHistory;
+        mWtfHistory = wtfHistory;
         mUserId = userId;
         mUi = ui;
         mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
@@ -484,8 +486,8 @@
         assertCallerLocked(componentName);
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
-                sessionId, uid, activityToken, appCallbackToken, hasCallback,
-                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
+                sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
+                mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 63f8384..e1fb3a7 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -210,6 +210,9 @@
     @GuardedBy("mLock")
     private final LocalLog mUiLatencyHistory;
 
+    @GuardedBy("mLock")
+    private final LocalLog mWtfHistory;
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -241,7 +244,13 @@
                 // ONE_WAY warning because system_service could block on app calls. We need to
                 // change AssistStructure so it provides a "one-way" writeToParcel() method that
                 // sends all the data
-                structure.ensureData();
+                try {
+                    structure.ensureData();
+                } catch (RuntimeException e) {
+                    wtf(e, "Exception lazy loading assist structure for %s: %s",
+                            structure.getActivityComponent(), e);
+                    return;
+                }
 
                 // Sanitize structure before it's sent to service.
                 final ComponentName componentNameFromApp = structure.getActivityComponent();
@@ -447,6 +456,7 @@
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
+            @NonNull LocalLog wtfHistory,
             @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
             int flags) {
         id = sessionId;
@@ -461,6 +471,7 @@
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
+        mWtfHistory = wtfHistory;
         mComponentName = componentName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
 
@@ -1102,8 +1113,7 @@
         if (userData != null && fcStrategy != null) {
             logFieldClassificationScoreLocked(fcStrategy, ignoredDatasets, changedFieldIds,
                     changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    manuallyFilledIds, userData,
-                    mViewStates.values());
+                    userData, mViewStates.values());
         } else {
             mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                     ignoredDatasets, changedFieldIds, changedDatasetIds,
@@ -1123,7 +1133,6 @@
             @NonNull ArrayList<String> changedDatasetIds,
             @NonNull ArrayList<AutofillId> manuallyFilledFieldIds,
             @NonNull ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @NonNull ArrayMap<AutofillId, ArraySet<String>> manuallyFilledIds,
             @NonNull UserData userData, @NonNull Collection<ViewState> viewStates) {
 
         final String[] userValues = userData.getValues();
@@ -1201,8 +1210,7 @@
                     }
                 }
             } catch (ArrayIndexOutOfBoundsException e) {
-                Slog.wtf(TAG, "Error accessing FC score at " + i + " x " + j + ": "
-                        + Arrays.toString(scores.scores), e);
+                wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
                 return;
             }
 
@@ -2151,9 +2159,10 @@
         final Intent fillInIntent = new Intent();
 
         final FillContext context = getFillContextByRequestIdLocked(requestId);
+
         if (context == null) {
-            Slog.wtf(TAG, "createAuthFillInIntentLocked(): no FillContext. requestId=" + requestId
-                    + "; mContexts= " + mContexts);
+            wtf(null, "createAuthFillInIntentLocked(): no FillContext. requestId=%d; mContexts=%s",
+                    requestId, mContexts);
             return null;
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
@@ -2418,4 +2427,15 @@
     private void writeLog(int category) {
         mMetricsLogger.write(newLogMaker(category));
     }
+
+    private void wtf(@Nullable Exception e, String fmt, Object...args) {
+        final String message = String.format(fmt, args);
+        mWtfHistory.log(message);
+
+        if (e != null) {
+            Slog.wtf(TAG, message, e);
+        } else {
+            Slog.wtf(TAG, message);
+        }
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/internal/BackupState.java b/services/backup/java/com/android/server/backup/internal/BackupState.java
index 4d42c240..937b167 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupState.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupState.java
@@ -5,6 +5,7 @@
  */
 enum BackupState {
     INITIAL,
+    BACKUP_PM,
     RUNNING_QUEUE,
     FINAL
 }
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 289dd14..99ffa12 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -224,6 +224,10 @@
                     beginBackup();
                     break;
 
+                case BACKUP_PM:
+                    backupPm();
+                    break;
+
                 case RUNNING_QUEUE:
                     invokeNextAgent();
                     break;
@@ -239,8 +243,7 @@
         }
     }
 
-    // We're starting a backup pass.  Initialize the transport and send
-    // the PM metadata blob if we haven't already.
+    // We're starting a backup pass.  Initialize the transport if we haven't already.
     private void beginBackup() {
         if (DEBUG_BACKUP_TRACE) {
             backupManagerService.clearBackupTrace();
@@ -320,40 +323,21 @@
                 Slog.d(TAG, "Skipping backup of package metadata.");
                 executeNextState(BackupState.RUNNING_QUEUE);
             } else {
-                // The package manager doesn't have a proper <application> etc, but since
-                // it's running here in the system process we can just set up its agent
-                // directly and use a synthetic BackupRequest.  We always run this pass
-                // because it's cheap and this way we guarantee that we don't get out of
-                // step even if we're selecting among various transports at run time.
+                // As the package manager is running here in the system process we can just set up
+                // its agent directly. Thus we always run this pass because it's cheap and this way
+                // we guarantee that we don't get out of step even if we're selecting among various
+                // transports at run time.
                 if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    PackageManagerBackupAgent pmAgent = backupManagerService.makeMetadataAgent();
-                    mStatus = invokeAgentForBackup(
-                            PACKAGE_MANAGER_SENTINEL,
-                            IBackupAgent.Stub.asInterface(pmAgent.onBind()));
-                    backupManagerService.addBackupTrace("PMBA invoke: " + mStatus);
-
-                    // Because the PMBA is a local instance, it has already executed its
-                    // backup callback and returned.  Blow away the lingering (spurious)
-                    // pending timeout message for it.
-                    backupManagerService.getBackupHandler().removeMessages(
-                            MSG_BACKUP_OPERATION_TIMEOUT);
+                    executeNextState(BackupState.BACKUP_PM);
                 }
             }
-
-            if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
-                // The backend reports that our dataset has been wiped.  Note this in
-                // the event log; the no-success code below will reset the backup
-                // state as well.
-                EventLog.writeEvent(EventLogTags.BACKUP_RESET, transportName);
-            }
         } catch (Exception e) {
-            Slog.e(TAG, "Error in backup thread", e);
-            backupManagerService.addBackupTrace("Exception in backup thread: " + e);
+            Slog.e(TAG, "Error in backup thread during init", e);
+            backupManagerService.addBackupTrace("Exception in backup thread during init: " + e);
             mStatus = BackupTransport.TRANSPORT_ERROR;
         } finally {
-            // If we've succeeded so far, invokeAgentForBackup() will have run the PM
-            // metadata and its completion/timeout callback will continue the state
-            // machine chain.  If it failed that won't happen; we handle that now.
+            // If we've succeeded so far, we will move to the BACKUP_PM state. If something has gone
+            // wrong then that won't have happen so cleanup.
             backupManagerService.addBackupTrace("exiting prelim: " + mStatus);
             if (mStatus != BackupTransport.TRANSPORT_OK) {
                 // if things went wrong at this point, we need to
@@ -367,6 +351,49 @@
         }
     }
 
+    private void backupPm() {
+        try {
+            // The package manager doesn't have a proper <application> etc, but since it's running
+            // here in the system process we can just set up its agent directly and use a synthetic
+            // BackupRequest.
+            PackageManagerBackupAgent pmAgent = backupManagerService.makeMetadataAgent();
+            mStatus = invokeAgentForBackup(
+                    PACKAGE_MANAGER_SENTINEL,
+                    IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+            backupManagerService.addBackupTrace("PMBA invoke: " + mStatus);
+
+            // Because the PMBA is a local instance, it has already executed its backup callback and
+            // returned.  Blow away the lingering (spurious) pending timeout message for it.
+            backupManagerService.getBackupHandler().removeMessages(
+                    MSG_BACKUP_OPERATION_TIMEOUT);
+        } catch (Exception e) {
+            Slog.e(TAG, "Error in backup thread during pm", e);
+            backupManagerService.addBackupTrace("Exception in backup thread during pm: " + e);
+            mStatus = BackupTransport.TRANSPORT_ERROR;
+        } finally {
+            // If we've succeeded so far, invokeAgentForBackup() will have run the PM
+            // metadata and its completion/timeout callback will continue the state
+            // machine chain.  If it failed that won't happen; we handle that now.
+            backupManagerService.addBackupTrace("exiting backupPm: " + mStatus);
+            if (mStatus != BackupTransport.TRANSPORT_OK) {
+                // if things went wrong at this point, we need to
+                // restage everything and try again later.
+                backupManagerService.resetBackupState(mStateDir);  // Just to make sure.
+                BackupObserverUtils.sendBackupFinished(mObserver,
+                        invokeAgentToObserverError(mStatus));
+                executeNextState(BackupState.FINAL);
+            }
+        }
+    }
+
+    private int invokeAgentToObserverError(int error) {
+        if (error == BackupTransport.AGENT_ERROR) {
+            return BackupManager.ERROR_AGENT_FAILURE;
+        } else {
+            return BackupManager.ERROR_TRANSPORT_ABORTED;
+        }
+    }
+
     // Transport has been initialized and the PM metadata submitted successfully
     // if that was warranted.  Now we process the single next thing in the queue.
     private void invokeNextAgent() {
@@ -903,6 +930,7 @@
                 TransportUtils.checkTransportNotNull(transport);
                 size = mBackupDataName.length();
                 if (size > 0) {
+                    boolean isNonIncremental = mSavedStateName.length() == 0;
                     if (mStatus == BackupTransport.TRANSPORT_OK) {
                         backupData = ParcelFileDescriptor.open(mBackupDataName,
                                 ParcelFileDescriptor.MODE_READ_ONLY);
@@ -911,7 +939,7 @@
                         int userInitiatedFlag =
                                 mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
                         int incrementalFlag =
-                                mSavedStateName.length() == 0
+                                isNonIncremental
                                     ? BackupTransport.FLAG_NON_INCREMENTAL
                                     : BackupTransport.FLAG_INCREMENTAL;
                         int flags = userInitiatedFlag | incrementalFlag;
@@ -919,6 +947,19 @@
                         mStatus = transport.performBackup(mCurrentPackage, backupData, flags);
                     }
 
+                    if (isNonIncremental
+                        && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
+                        // TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED is only valid if the backup was
+                        // incremental, as if the backup is non-incremental there is no state to
+                        // clear. This avoids us ending up in a retry loop if the transport always
+                        // returns this code.
+                        Slog.w(TAG,
+                                "Transport requested non-incremental but already the case, error");
+                        backupManagerService.addBackupTrace(
+                                "Transport requested non-incremental but already the case, error");
+                        mStatus = BackupTransport.TRANSPORT_ERROR;
+                    }
+
                     // TODO - We call finishBackup() for each application backed up, because
                     // we need to know now whether it succeeded or failed.  Instead, we should
                     // hold off on finishBackup() until the end, which implies holding off on
@@ -966,6 +1007,31 @@
                     BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
                             BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
                     EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
+
+                } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
+                    Slog.i(TAG, "Transport lost data, retrying package");
+                    backupManagerService.addBackupTrace(
+                            "Transport lost data, retrying package:" + pkgName);
+                    BackupManagerMonitorUtils.monitorEvent(
+                            mMonitor,
+                            BackupManagerMonitor
+                                    .LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED,
+                            mCurrentPackage,
+                            BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+                            /*extras=*/ null);
+
+                    mBackupDataName.delete();
+                    mSavedStateName.delete();
+                    mNewStateName.delete();
+
+                    // Immediately retry the package by adding it back to the front of the queue.
+                    // We cannot add @pm@ to the queue because we back it up separately at the start
+                    // of the backup pass in state BACKUP_PM. Instead we retry this state (see
+                    // below).
+                    if (!PACKAGE_MANAGER_SENTINEL.equals(pkgName)) {
+                        mQueue.add(0, new BackupRequest(pkgName));
+                    }
+
                 } else {
                     // Actual transport-level failure to communicate the data to the backend
                     BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
@@ -991,6 +1057,17 @@
                 // Success or single-package rejection.  Proceed with the next app if any,
                 // otherwise we're done.
                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
+
+            } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
+                // We want to immediately retry the current package.
+                if (PACKAGE_MANAGER_SENTINEL.equals(pkgName)) {
+                    nextState = BackupState.BACKUP_PM;
+                } else {
+                    // This is an ordinary package so we will have added it back into the queue
+                    // above. Thus, we proceed processing the queue.
+                    nextState = BackupState.RUNNING_QUEUE;
+                }
+
             } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
                 if (MORE_DEBUG) {
                     Slog.d(TAG, "Package " + mCurrentPackage.packageName +
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5030dce..145b307 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 
@@ -106,6 +107,7 @@
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
@@ -176,6 +178,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -455,8 +458,8 @@
     private LingerMonitor mLingerMonitor;
 
     // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
-    private final static int MIN_NET_ID = 100; // some reserved marks
-    private final static int MAX_NET_ID = 65535;
+    private static final int MIN_NET_ID = 100; // some reserved marks
+    private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService
     private int mNextNetId = MIN_NET_ID;
 
     // sequence number of NetworkRequests
@@ -733,12 +736,12 @@
         mSystemProperties = getSystemProperties();
 
         mMetricsLog = logger;
-        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
+        mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
         mNetworkRequests.put(mDefaultRequest, defaultNRI);
         mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
 
-        mDefaultMobileDataRequest = createInternetRequestForTransport(
+        mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
                 NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
 
         mHandlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -903,7 +906,7 @@
                 deps);
     }
 
-    private NetworkRequest createInternetRequestForTransport(
+    private NetworkRequest createDefaultInternetRequestForTransport(
             int transportType, NetworkRequest.Type type) {
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1281,7 +1284,11 @@
                         for (Network network : networks) {
                             nai = getNetworkAgentInfoForNetwork(network);
                             nc = getNetworkCapabilitiesInternal(nai);
+                            // nc is a copy of the capabilities in nai, so it's fine to mutate it
+                            // TODO : don't remove the UIDs when communicating with processes
+                            // that have the NETWORK_SETTINGS permission.
                             if (nc != null) {
+                                nc.setSingleUid(userId);
                                 result.put(network, nc);
                             }
                         }
@@ -2079,24 +2086,6 @@
                     if (score != null) updateNetworkScore(nai, score.intValue());
                     break;
                 }
-                case NetworkAgent.EVENT_UID_RANGES_ADDED: {
-                    try {
-                        mNetd.addVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
-                    } catch (Exception e) {
-                        // Never crash!
-                        loge("Exception in addVpnUidRanges: " + e);
-                    }
-                    break;
-                }
-                case NetworkAgent.EVENT_UID_RANGES_REMOVED: {
-                    try {
-                        mNetd.removeVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
-                    } catch (Exception e) {
-                        // Never crash!
-                        loge("Exception in removeVpnUidRanges: " + e);
-                    }
-                    break;
-                }
                 case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
                     if (nai.everConnected && !nai.networkMisc.explicitlySelected) {
                         loge("ERROR: already-connected network explicitly selected.");
@@ -4235,6 +4224,7 @@
         // the system default network.
         if (type == NetworkRequest.Type.TRACK_DEFAULT) {
             networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
+            networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
             enforceAccessPermission();
         } else {
             networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4245,6 +4235,13 @@
             enforceMeteredApnPolicy(networkCapabilities);
         }
         ensureRequestableCapabilities(networkCapabilities);
+        // Set the UID range for this request to the single UID of the requester.
+        // This will overwrite any allowed UIDs in the requested capabilities. Though there
+        // are no visible methods to set the UIDs, an app could use reflection to try and get
+        // networks for other apps so it's essential that the UIDs are overwritten.
+        // TODO : don't forcefully set the UID when communicating with processes
+        // that have the NETWORK_SETTINGS permission.
+        networkCapabilities.setSingleUid(Binder.getCallingUid());
 
         if (timeoutMs < 0) {
             throw new IllegalArgumentException("Bad timeout specified");
@@ -4318,6 +4315,9 @@
         enforceMeteredApnPolicy(networkCapabilities);
         ensureRequestableCapabilities(networkCapabilities);
         ensureValidNetworkSpecifier(networkCapabilities);
+        // TODO : don't forcefully set the UID when communicating with processes
+        // that have the NETWORK_SETTINGS permission.
+        networkCapabilities.setSingleUid(Binder.getCallingUid());
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
                 nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4371,6 +4371,9 @@
         }
 
         NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        // TODO : don't forcefully set the UIDs when communicating with processes
+        // that have the NETWORK_SETTINGS permission.
+        nc.setSingleUid(Binder.getCallingUid());
         if (!ConnectivityManager.checkChangePermission(mContext)) {
             // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
             // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4399,8 +4402,12 @@
         }
         ensureValidNetworkSpecifier(networkCapabilities);
 
-        NetworkRequest networkRequest = new NetworkRequest(
-                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
+        final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        // TODO : don't forcefully set the UIDs when communicating with processes
+        // that have the NETWORK_SETTINGS permission.
+        nc.setSingleUid(Binder.getCallingUid());
+
+        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
         NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
         if (VDBG) log("pendingListenForNetwork for " + nri);
@@ -4543,6 +4550,7 @@
         NetworkInfo networkInfo = na.networkInfo;
         na.networkInfo = null;
         updateNetworkInfo(na, networkInfo);
+        updateUids(na, null, na.networkCapabilities);
     }
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
@@ -4791,6 +4799,8 @@
             nai.networkCapabilities = newNc;
         }
 
+        updateUids(nai, prevNc, newNc);
+
         if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
             // If the requestable capabilities haven't changed, and the score hasn't changed, then
             // the change we're processing can't affect any requests, it can only affect the listens
@@ -4827,6 +4837,34 @@
         }
     }
 
+    private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
+            NetworkCapabilities newNc) {
+        Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
+        Set<UidRange> newRanges = null == newNc ? null : newNc.getUids();
+        if (null == prevRanges) prevRanges = new ArraySet<>();
+        if (null == newRanges) newRanges = new ArraySet<>();
+        final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
+
+        prevRanges.removeAll(newRanges);
+        newRanges.removeAll(prevRangesCopy);
+
+        try {
+            if (!newRanges.isEmpty()) {
+                final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
+                newRanges.toArray(addedRangesArray);
+                mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray);
+            }
+            if (!prevRanges.isEmpty()) {
+                final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
+                prevRanges.toArray(removedRangesArray);
+                mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+            }
+        } catch (Exception e) {
+            // Never crash!
+            loge("Exception in updateUids: " + e);
+        }
+    }
+
     public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
         if (mNetworkForNetId.get(nai.network.netId) != nai) {
             // Ignore updates for disconnected networks
@@ -4918,7 +4956,12 @@
                 break;
             }
             case ConnectivityManager.CALLBACK_CAP_CHANGED: {
-                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+                final NetworkCapabilities nc =
+                        new NetworkCapabilities(networkAgent.networkCapabilities);
+                // TODO : don't remove the UIDs when communicating with processes
+                // that have the NETWORK_SETTINGS permission.
+                nc.setSingleUid(nri.mUid);
+                putParcelable(bundle, nc);
                 break;
             }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
@@ -5442,6 +5485,7 @@
                         }
                     }
                 }
+                updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
         } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
                 state == NetworkInfo.State.SUSPENDED) {
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index de113a6..792fdfe 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.PackageOps;
 import android.app.IActivityManager;
@@ -504,7 +505,7 @@
      */
     void uidToForeground(int uid) {
         synchronized (mLock) {
-            if (!UserHandle.isApp(uid)) {
+            if (UserHandle.isCore(uid)) {
                 return;
             }
             // TODO This can be optimized by calling indexOfKey and sharing the index for get and
@@ -522,7 +523,7 @@
      */
     void uidToBackground(int uid, boolean remove) {
         synchronized (mLock) {
-            if (!UserHandle.isApp(uid)) {
+            if (UserHandle.isCore(uid)) {
                 return;
             }
             // TODO This can be optimized by calling indexOfKey and sharing the index for get and
@@ -825,9 +826,10 @@
     /**
      * @return whether jobs should be restricted for a UID package-name.
      */
-    public boolean areJobsRestricted(int uid, @NonNull String packageName) {
+    public boolean areJobsRestricted(int uid, @NonNull String packageName,
+            boolean hasForegroundExemption) {
         return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
-                /* exemptOnBatterySaver =*/ false);
+                hasForegroundExemption);
     }
 
     /**
@@ -861,10 +863,12 @@
     /**
      * @return whether a UID is in the foreground or not.
      *
-     * Note clients normally shouldn't need to access it. It's only for dumpsys.
+     * Note this information is based on the UID proc state callback, meaning it's updated
+     * asynchronously and may subtly be stale. If the fresh data is needed, use
+     * {@link ActivityManagerInternal#getUidProcessState} instead.
      */
     public boolean isInForeground(int uid) {
-        if (!UserHandle.isApp(uid)) {
+        if (UserHandle.isCore(uid)) {
             return true;
         }
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 24d493e..c2adbfa 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -34,7 +34,9 @@
 import android.net.IpSecSpiResponse;
 import android.net.IpSecTransform;
 import android.net.IpSecTransformResponse;
+import android.net.IpSecTunnelInterfaceResponse;
 import android.net.IpSecUdpEncapResponse;
+import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
 import android.net.util.NetdService;
@@ -50,6 +52,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -62,6 +65,7 @@
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.List;
 
 import libcore.io.IoUtils;
@@ -99,6 +103,7 @@
 
     static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
     static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
+    static final String TUNNEL_INTERFACE_PREFIX = "ipsec";
 
     /* Binder context for this service */
     private final Context mContext;
@@ -347,6 +352,7 @@
     @VisibleForTesting
     static final class UserRecord {
         /* Maximum number of each type of resource that a single UID may possess */
+        public static final int MAX_NUM_TUNNEL_INTERFACES = 2;
         public static final int MAX_NUM_ENCAP_SOCKETS = 2;
         public static final int MAX_NUM_TRANSFORMS = 4;
         public static final int MAX_NUM_SPIS = 8;
@@ -366,6 +372,8 @@
                 new RefcountedResourceArray<>(TransformRecord.class.getSimpleName());
         final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords =
                 new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName());
+        final RefcountedResourceArray<TunnelInterfaceRecord> mTunnelInterfaceRecords =
+                new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName());
 
         /**
          * Trackers for quotas for each of the OwnedResource types.
@@ -379,6 +387,7 @@
         final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
         final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
         final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
+        final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES);
 
         void removeSpiRecord(int resourceId) {
             mSpiRecords.remove(resourceId);
@@ -388,6 +397,10 @@
             mTransformRecords.remove(resourceId);
         }
 
+        void removeTunnelInterfaceRecord(int resourceId) {
+            mTunnelInterfaceRecords.remove(resourceId);
+        }
+
         void removeEncapSocketRecord(int resourceId) {
             mEncapSocketRecords.remove(resourceId);
         }
@@ -594,7 +607,9 @@
                                 mResourceId,
                                 mConfig.getSourceAddress(),
                                 mConfig.getDestinationAddress(),
-                                spi);
+                                spi,
+                                mConfig.getMarkValue(),
+                                mConfig.getMarkMask());
             } catch (ServiceSpecificException e) {
                 // FIXME: get the error code and throw is at an IOException from Errno Exception
             } catch (RemoteException e) {
@@ -657,7 +672,7 @@
                 mSrvConfig
                         .getNetdInstance()
                         .ipSecDeleteSecurityAssociation(
-                                mResourceId, mSourceAddress, mDestinationAddress, mSpi);
+                                mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
             } catch (ServiceSpecificException e) {
                 // FIXME: get the error code and throw is at an IOException from Errno Exception
             } catch (RemoteException e) {
@@ -719,6 +734,145 @@
         }
     }
 
+    // These values have been reserved in ConnectivityService
+    @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
+
+    @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400;
+
+    private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
+    private int mNextTunnelNetIdIndex = 0;
+
+    /**
+     * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
+     *
+     * <p>This method should only be called from Binder threads. Do not call this from within the
+     * system server as it will crash the system on failure.
+     *
+     * @return an integer key within the netId range, if successful
+     * @throws IllegalStateException if unsuccessful (all netId are currently reserved)
+     */
+    @VisibleForTesting
+    int reserveNetId() {
+        synchronized (mTunnelNetIds) {
+            for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
+                int index = mNextTunnelNetIdIndex;
+                int netId = index + TUN_INTF_NETID_START;
+                if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
+                if (!mTunnelNetIds.get(netId)) {
+                    mTunnelNetIds.put(netId, true);
+                    return netId;
+                }
+            }
+        }
+        throw new IllegalStateException("No free netIds to allocate");
+    }
+
+    @VisibleForTesting
+    void releaseNetId(int netId) {
+        synchronized (mTunnelNetIds) {
+            mTunnelNetIds.delete(netId);
+        }
+    }
+
+    private final class TunnelInterfaceRecord extends OwnedResourceRecord {
+        private final String mInterfaceName;
+        private final Network mUnderlyingNetwork;
+
+        // outer addresses
+        private final String mLocalAddress;
+        private final String mRemoteAddress;
+
+        private final int mIkey;
+        private final int mOkey;
+
+        TunnelInterfaceRecord(
+                int resourceId,
+                String interfaceName,
+                Network underlyingNetwork,
+                String localAddr,
+                String remoteAddr,
+                int ikey,
+                int okey) {
+            super(resourceId);
+
+            mInterfaceName = interfaceName;
+            mUnderlyingNetwork = underlyingNetwork;
+            mLocalAddress = localAddr;
+            mRemoteAddress = remoteAddr;
+            mIkey = ikey;
+            mOkey = okey;
+        }
+
+        /** always guarded by IpSecService#this */
+        @Override
+        public void freeUnderlyingResources() {
+            // TODO: Add calls to netd
+            //       Teardown VTI
+            //       Delete global policies
+
+            getResourceTracker().give();
+            releaseNetId(mIkey);
+            releaseNetId(mOkey);
+        }
+
+        public String getInterfaceName() {
+            return mInterfaceName;
+        }
+
+        public Network getUnderlyingNetwork() {
+            return mUnderlyingNetwork;
+        }
+
+        /** Returns the local, outer address for the tunnelInterface */
+        public String getLocalAddress() {
+            return mLocalAddress;
+        }
+
+        /** Returns the remote, outer address for the tunnelInterface */
+        public String getRemoteAddress() {
+            return mRemoteAddress;
+        }
+
+        public int getIkey() {
+            return mIkey;
+        }
+
+        public int getOkey() {
+            return mOkey;
+        }
+
+        @Override
+        protected ResourceTracker getResourceTracker() {
+            return getUserRecord().mTunnelQuotaTracker;
+        }
+
+        @Override
+        public void invalidate() {
+            getUserRecord().removeTunnelInterfaceRecord(mResourceId);
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                    .append("{super=")
+                    .append(super.toString())
+                    .append(", mInterfaceName=")
+                    .append(mInterfaceName)
+                    .append(", mUnderlyingNetwork=")
+                    .append(mUnderlyingNetwork)
+                    .append(", mLocalAddress=")
+                    .append(mLocalAddress)
+                    .append(", mRemoteAddress=")
+                    .append(mRemoteAddress)
+                    .append(", mIkey=")
+                    .append(mIkey)
+                    .append(", mOkey=")
+                    .append(mOkey)
+                    .append("}")
+                    .toString();
+        }
+    }
+
     /**
      * Tracks a UDP encap socket, and manages cleanup paths
      *
@@ -1049,6 +1203,97 @@
         releaseResource(userRecord.mEncapSocketRecords, resourceId);
     }
 
+    /**
+     * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the
+     * tunnel interface and a record of its owner so that it can and must be freed when no longer
+     * needed.
+     */
+    @Override
+    public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
+            String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) {
+        checkNotNull(binder, "Null Binder passed to createTunnelInterface");
+        checkNotNull(underlyingNetwork, "No underlying network was specified");
+        checkInetAddress(localAddr);
+        checkInetAddress(remoteAddr);
+
+        // TODO: Check that underlying network exists, and IP addresses not assigned to a different
+        //       network (b/72316676).
+
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        if (!userRecord.mTunnelQuotaTracker.isAvailable()) {
+            return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
+        }
+
+        final int resourceId = mNextResourceId++;
+        final int ikey = reserveNetId();
+        final int okey = reserveNetId();
+        String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
+
+        // TODO: Add calls to netd:
+        //       Create VTI
+        //       Add inbound/outbound global policies
+        //              (use reqid = 0)
+
+        userRecord.mTunnelInterfaceRecords.put(
+                resourceId,
+                new RefcountedResource<TunnelInterfaceRecord>(
+                        new TunnelInterfaceRecord(
+                                resourceId,
+                                intfName,
+                                underlyingNetwork,
+                                localAddr,
+                                remoteAddr,
+                                ikey,
+                                okey),
+                        binder));
+        return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
+    }
+
+    /**
+     * Adds a new local address to the tunnel interface. This allows packets to be sent and received
+     * from multiple local IP addresses over the same tunnel.
+     */
+    @Override
+    public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) {
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+        // Get tunnelInterface record; if no such interface is found, will throw
+        // IllegalArgumentException
+        TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
+
+        // TODO: Add calls to netd:
+        //       Add address to TunnelInterface
+    }
+
+    /**
+     * Remove a new local address from the tunnel interface. After removal, the address will no
+     * longer be available to send from, or receive on.
+     */
+    @Override
+    public synchronized void removeAddressFromTunnelInterface(
+            int tunnelResourceId, String localAddr) {
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+        // Get tunnelInterface record; if no such interface is found, will throw
+        // IllegalArgumentException
+        TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
+
+        // TODO: Add calls to netd:
+        //       Remove address from TunnelInterface
+    }
+
+    /**
+     * Delete a TunnelInterface that has been been allocated by and registered with the system
+     * server
+     */
+    @Override
+    public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException {
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
+    }
+
     @VisibleForTesting
     void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException {
         IpSecAlgorithm auth = config.getAuthentication();
@@ -1190,6 +1435,8 @@
                             c.getDestinationAddress(),
                             (c.getNetwork() != null) ? c.getNetwork().netId : 0,
                             spiRecord.getSpi(),
+                            c.getMarkValue(),
+                            c.getMarkMask(),
                             (auth != null) ? auth.getName() : "",
                             (auth != null) ? auth.getKey() : new byte[] {},
                             (auth != null) ? auth.getTruncationLengthBits() : 0,
@@ -1245,7 +1492,12 @@
             throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
         }
 
+        // Get config and check that to-be-applied transform has the correct mode
         IpSecConfig c = info.getConfig();
+        Preconditions.checkArgument(
+                c.getMode() == IpSecTransform.MODE_TRANSPORT,
+                "Transform mode was not Transport mode; cannot be applied to a socket");
+
         try {
             mSrvConfig
                     .getNetdInstance()
@@ -1283,6 +1535,42 @@
         }
     }
 
+    /**
+     * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec
+     * security association as a correspondent policy to the provided interface
+     */
+    @Override
+    public synchronized void applyTunnelModeTransform(
+            int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
+        checkDirection(direction);
+
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+        // Get transform record; if no transform is found, will throw IllegalArgumentException
+        TransformRecord transformInfo =
+                userRecord.mTransformRecords.getResourceOrThrow(transformResourceId);
+
+        // Get tunnelInterface record; if no such interface is found, will throw
+        // IllegalArgumentException
+        TunnelInterfaceRecord tunnelInterfaceInfo =
+                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
+
+        // Get config and check that to-be-applied transform has the correct mode
+        IpSecConfig c = transformInfo.getConfig();
+        Preconditions.checkArgument(
+                c.getMode() == IpSecTransform.MODE_TUNNEL,
+                "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface");
+
+        int mark =
+                (direction == IpSecManager.DIRECTION_IN)
+                        ? tunnelInterfaceInfo.getIkey()
+                        : tunnelInterfaceInfo.getOkey();
+
+        // TODO: Add calls to netd:
+        //       Update SA with tunnel mark (ikey or okey based on direction)
+        //       If outbound, add SPI to policy
+    }
+
     @Override
     protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6c63f43..5a4f7ca 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,11 +16,64 @@
 
 package com.android.server;
 
-import android.app.ActivityManager;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.hardware.location.ActivityRecognitionHardware;
+import android.location.Address;
+import android.location.Criteria;
+import android.location.GeocoderParams;
+import android.location.Geofence;
+import android.location.IBatchedLocationCallback;
+import android.location.IGnssMeasurementsListener;
+import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
+import android.location.IGpsGeofenceHardware;
+import android.location.ILocationListener;
+import android.location.ILocationManager;
+import android.location.INetInitiatedListener;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.LocationRequest;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
@@ -45,60 +98,6 @@
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
 import com.android.server.location.MockProvider;
 import com.android.server.location.PassiveProvider;
-
-import android.app.AppOpsManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.Signature;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.hardware.location.ActivityRecognitionHardware;
-import android.location.Address;
-import android.location.Criteria;
-import android.location.GeocoderParams;
-import android.location.Geofence;
-import android.location.IBatchedLocationCallback;
-import android.location.IGnssMeasurementsListener;
-import android.location.IGnssStatusListener;
-import android.location.IGnssStatusProvider;
-import android.location.IGpsGeofenceHardware;
-import android.location.IGnssNavigationMessageListener;
-import android.location.ILocationListener;
-import android.location.ILocationManager;
-import android.location.INetInitiatedListener;
-import android.location.Location;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.location.LocationRequest;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.WorkSource;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Slog;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -1378,10 +1377,7 @@
         if (mDisabledProviders.contains(provider)) {
             return false;
         }
-        // Use system settings
-        ContentResolver resolver = mContext.getContentResolver();
-
-        return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
+        return isLocationProviderEnabledForUser(provider, mCurrentUserId);
     }
 
     /**
@@ -1400,6 +1396,23 @@
     }
 
     /**
+     * Returns "true" if access to the specified location provider is allowed by the specified
+     * user's settings. Access to all location providers is forbidden to non-location-provider
+     * processes belonging to background users.
+     *
+     * @param provider the name of the location provider
+     * @param uid      the requestor's UID
+     * @param userId   the user id to query
+     */
+    private boolean isAllowedByUserSettingsLockedForUser(
+            String provider, int uid, int userId) {
+        if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
+            return false;
+        }
+        return isLocationProviderEnabledForUser(provider, userId);
+    }
+
+    /**
      * Returns the permission string associated with the specified resolution level.
      *
      * @param resolutionLevel the resolution level
@@ -1425,10 +1438,10 @@
      */
     private int getAllowedResolutionLevel(int pid, int uid) {
         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
-                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+                pid, uid) == PERMISSION_GRANTED) {
             return RESOLUTION_LEVEL_FINE;
         } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
-                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+                pid, uid) == PERMISSION_GRANTED) {
             return RESOLUTION_LEVEL_COARSE;
         } else {
             return RESOLUTION_LEVEL_NONE;
@@ -2053,7 +2066,7 @@
         }
         boolean callerHasLocationHardwarePermission =
                 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PackageManager.PERMISSION_GRANTED;
+                        == PERMISSION_GRANTED;
         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
                 callerHasLocationHardwarePermission);
 
@@ -2326,7 +2339,7 @@
         // Require that caller can manage given document
         boolean callerHasLocationHardwarePermission =
                 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PackageManager.PERMISSION_GRANTED;
+                        == PERMISSION_GRANTED;
         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
                 callerHasLocationHardwarePermission);
 
@@ -2476,7 +2489,7 @@
 
         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
         if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
-                != PackageManager.PERMISSION_GRANTED)) {
+                != PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
         }
 
@@ -2546,8 +2559,64 @@
         return null;
     }
 
+    /**
+     * Method for enabling or disabling location.
+     *
+     * @param enabled true to enable location. false to disable location
+     * @param userId the user id to set
+     */
+    @Override
+    public void setLocationEnabledForUser(boolean enabled, int userId) {
+        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+        checkInteractAcrossUsersPermission(userId);
+
+        // enable all location providers
+        synchronized (mLock) {
+            for(String provider : getAllProviders()) {
+                setProviderEnabledForUser(provider, enabled, userId);
+            }
+        }
+    }
+
+    /**
+     * Returns the current enabled/disabled status of location
+     *
+     * @param userId the user id to query
+     * @return true if location is enabled. false if location is disabled.
+     */
+    @Override
+    public boolean isLocationEnabledForUser(int userId) {
+
+        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+        checkInteractAcrossUsersPermission(userId);
+
+        synchronized (mLock) {
+            for (String provider : getAllProviders()) {
+                if (isProviderEnabledForUser(provider, userId)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
     @Override
     public boolean isProviderEnabled(String provider) {
+        return isProviderEnabledForUser(provider, UserHandle.myUserId());
+    }
+
+    /**
+     * Method for determining if a location provider is enabled.
+     *
+     * @param provider the location provider to query
+     * @param userId the user id to query
+     * @return true if the provider is enabled
+     */
+    @Override
+    public boolean isProviderEnabledForUser(String provider, int userId) {
+        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+        checkInteractAcrossUsersPermission(userId);
+
         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
         // so we discourage its use
         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
@@ -2557,7 +2626,8 @@
         try {
             synchronized (mLock) {
                 LocationProviderInterface p = mProvidersByName.get(provider);
-                return p != null && isAllowedByUserSettingsLocked(provider, uid);
+                return p != null
+                    && isAllowedByUserSettingsLockedForUser(provider, uid, userId);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2565,6 +2635,83 @@
     }
 
     /**
+     * Method for enabling or disabling a single location provider.
+     *
+     * @param provider the name of the provider
+     * @param enabled true to enable the provider. false to disable the provider
+     * @param userId the user id to set
+     * @return true if the value was set successfully. false on failure.
+     */
+    @Override
+    public boolean setProviderEnabledForUser(
+            String provider, boolean enabled, int userId) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.WRITE_SECURE_SETTINGS,
+                "Requires WRITE_SECURE_SETTINGS permission");
+
+        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+        checkInteractAcrossUsersPermission(userId);
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                // to ensure thread safety, we write the provider name with a '+' or '-'
+                // and let the SettingsProvider handle it rather than reading and modifying
+                // the list of enabled providers.
+                if (enabled) {
+                    provider = "+" + provider;
+                } else {
+                    provider = "-" + provider;
+                }
+                return Settings.Secure.putStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        provider,
+                        userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Read location provider status from Settings.Secure
+     *
+     * @param provider the location provider to query
+     * @param userId the user id to query
+     * @return true if the provider is enabled
+     */
+    private boolean isLocationProviderEnabledForUser(String provider, int userId) {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            // Use system settings
+            ContentResolver cr = mContext.getContentResolver();
+            String allowedProviders = Settings.Secure.getStringForUser(
+                    cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
+            return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
+     * current user id
+     *
+     * @param userId the user id to get or set value
+     */
+    private void checkInteractAcrossUsersPermission(int userId) {
+        int uid = Binder.getCallingUid();
+        if (UserHandle.getUserId(uid) != userId) {
+            if (ActivityManager.checkComponentPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
+                != PERMISSION_GRANTED) {
+                throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+            }
+        }
+    }
+
+    /**
      * Returns "true" if the UID belongs to a bound location provider.
      *
      * @param uid the uid
@@ -2585,7 +2732,7 @@
 
     private void checkCallerIsProvider() {
         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
-                == PackageManager.PERMISSION_GRANTED) {
+                == PERMISSION_GRANTED) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
index 833def3..1e9a007 100644
--- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
+++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
@@ -24,7 +24,11 @@
     /** Stores the handle to a lockscreen credential to be used for Factory Reset Protection. */
     void setFrpCredentialHandle(byte[] handle);
 
-    /** Retrieves handle to a lockscreen credential to be used for Factory Reset Protection. */
+    /**
+     * Retrieves handle to a lockscreen credential to be used for Factory Reset Protection.
+     *
+     * @throws IllegalStateException if the underlying storage is corrupt or inaccessible.
+     */
     byte[] getFrpCredentialHandle();
 
     /** Update the OEM unlock enabled bit, bypassing user restriction checks. */
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 4298140..21093b9 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -28,6 +28,7 @@
 import android.os.UserManager;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -582,7 +583,12 @@
         @Override
         public boolean hasFrpCredentialHandle() {
             enforcePersistentDataBlockAccess();
-            return mInternalService.getFrpCredentialHandle() != null;
+            try {
+                return mInternalService.getFrpCredentialHandle() != null;
+            } catch (IllegalStateException e) {
+                Slog.e(TAG, "error reading frp handle", e);
+                throw new UnsupportedOperationException("cannot read frp credential");
+            }
         }
     };
 
@@ -638,7 +644,7 @@
         @Override
         public byte[] getFrpCredentialHandle() {
             if (!enforceChecksumValidity()) {
-                return null;
+                throw new IllegalStateException("invalid checksum");
             }
 
             DataInputStream inputStream;
@@ -646,8 +652,7 @@
                 inputStream = new DataInputStream(
                         new FileInputStream(new File(mDataBlockFile)));
             } catch (FileNotFoundException e) {
-                Slog.e(TAG, "partition not available");
-                return null;
+                throw new IllegalStateException("frp partition not available");
             }
 
             try {
@@ -662,8 +667,7 @@
                     return bytes;
                 }
             } catch (IOException e) {
-                Slog.e(TAG, "unable to access persistent partition", e);
-                return null;
+                throw new IllegalStateException("frp handle not readable", e);
             } finally {
                 IoUtils.closeQuietly(inputStream);
             }
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 84e4ea9..4a65733 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -22,6 +22,9 @@
 import android.content.pm.ApplicationInfo;
 import android.os.Bundle;
 import android.util.PrintWriterPrinter;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.ActiveInstrumentationProto;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -119,4 +122,26 @@
         pw.print(prefix); pw.print("mArguments=");
         pw.println(mArguments);
     }
+
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        mClass.writeToProto(proto, ActiveInstrumentationProto.CLASS);
+        proto.write(ActiveInstrumentationProto.FINISHED, mFinished);
+        for (int i=0; i<mRunningProcesses.size(); i++) {
+            mRunningProcesses.get(i).writeToProto(proto,
+                    ActiveInstrumentationProto.RUNNING_PROCESSES);
+        }
+        for (String p : mTargetProcesses) {
+            proto.write(ActiveInstrumentationProto.TARGET_PROCESSES, p);
+        }
+        if (mTargetInfo != null) {
+            mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO);
+        }
+        proto.write(ActiveInstrumentationProto.PROFILE_FILE, mProfileFile);
+        proto.write(ActiveInstrumentationProto.WATCHER, mWatcher.toString());
+        proto.write(ActiveInstrumentationProto.UI_AUTOMATION_CONNECTION,
+                mUiAutomationConnection.toString());
+        proto.write(ActiveInstrumentationProto.ARGUMENTS, mArguments.toString());
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1eec982..5eb5b14 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -216,6 +216,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerInternal.ScreenObserver;
 import android.app.ActivityManagerInternal.SleepToken;
+import android.app.ActivityManagerProto;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.AlertDialog;
@@ -372,6 +373,7 @@
 import android.util.TimingsTraceLog;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.RemoteAnimationDefinition;
@@ -428,12 +430,16 @@
 import com.android.server.ThreadPriorityBooster;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.proto.ActivityManagerServiceProto;
 import com.android.server.am.proto.BroadcastProto;
 import com.android.server.am.proto.GrantUriProto;
+import com.android.server.am.proto.ImportanceTokenProto;
 import com.android.server.am.proto.MemInfoProto;
 import com.android.server.am.proto.NeededUriGrantsProto;
+import com.android.server.am.proto.ProcessOomProto;
+import com.android.server.am.proto.ProcessToGcProto;
+import com.android.server.am.proto.ProcessesProto;
+import com.android.server.am.proto.ProcessesProto.UidObserverRegistrationProto;
 import com.android.server.am.proto.StickyBroadcastProto;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
@@ -939,6 +945,16 @@
             return "ImportanceToken { " + Integer.toHexString(System.identityHashCode(this))
                     + " " + reason + " " + pid + " " + token + " }";
         }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long pToken = proto.start(fieldId);
+            proto.write(ImportanceTokenProto.PID, pid);
+            if (token != null) {
+                proto.write(ImportanceTokenProto.TOKEN, token.toString());
+            }
+            proto.write(ImportanceTokenProto.REASON, reason);
+            proto.end(pToken);
+        }
     }
     final SparseArray<ImportanceToken> mImportantProcesses = new SparseArray<ImportanceToken>();
 
@@ -1317,6 +1333,14 @@
             duration = _duration;
             tag = _tag;
         }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            proto.write(ProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
+            proto.write(ProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
+            proto.write(ProcessesProto.PendingTempWhitelist.TAG, tag);
+            proto.end(token);
+        }
     }
 
     final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>();
@@ -1641,6 +1665,20 @@
 
         final SparseIntArray lastProcStates;
 
+        // Please keep the enum lists in sync
+        private static int[] ORIG_ENUMS = new int[]{
+                ActivityManager.UID_OBSERVER_IDLE,
+                ActivityManager.UID_OBSERVER_ACTIVE,
+                ActivityManager.UID_OBSERVER_GONE,
+                ActivityManager.UID_OBSERVER_PROCSTATE,
+        };
+        private static int[] PROTO_ENUMS = new int[]{
+                ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
+                ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE,
+                ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
+                ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
+        };
+
         UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
             uid = _uid;
             pkg = _pkg;
@@ -1652,6 +1690,25 @@
                 lastProcStates = null;
             }
         }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            proto.write(UidObserverRegistrationProto.UID, uid);
+            proto.write(UidObserverRegistrationProto.PACKAGE, pkg);
+            ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS,
+                    which, ORIG_ENUMS, PROTO_ENUMS);
+            proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint);
+            if (lastProcStates != null) {
+                final int NI = lastProcStates.size();
+                for (int i=0; i<NI; i++) {
+                    final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES);
+                    proto.write(UidObserverRegistrationProto.ProcState.UID, lastProcStates.keyAt(i));
+                    proto.write(UidObserverRegistrationProto.ProcState.STATE, lastProcStates.valueAt(i));
+                    proto.end(pToken);
+                }
+            }
+            proto.end(token);
+        }
     }
 
     final List<ScreenObserver> mScreenObservers = new ArrayList<>();
@@ -8849,7 +8906,7 @@
             case AppOpsManager.MODE_ALLOWED:
                 // If force-background-check is enabled, restrict all apps that aren't whitelisted.
                 if (mForceBackgroundCheck &&
-                        UserHandle.isApp(uid) &&
+                        !UserHandle.isCore(uid) &&
                         !isOnDeviceIdleWhitelistLocked(uid)) {
                     if (DEBUG_BACKGROUND_CHECK) {
                         Slog.i(TAG, "Force background check: " +
@@ -15251,7 +15308,6 @@
         boolean dumpVisibleStacksOnly = false;
         boolean dumpFocusedStackOnly = false;
         String dumpPackage = null;
-        int dumpAppId = -1;
 
         int opti = 0;
         while (opti < args.length) {
@@ -15325,6 +15381,15 @@
                 }
             } else if ("service".equals(cmd)) {
                 mServices.writeToProto(proto);
+            } else if ("processes".equals(cmd) || "p".equals(cmd)) {
+                if (opti < args.length) {
+                    dumpPackage = args[opti];
+                    opti++;
+                }
+                // output proto is ProcessProto
+                synchronized (this) {
+                    writeProcessesToProtoLocked(proto, dumpPackage);
+                }
             } else {
                 // default option, dump everything, output is ActivityManagerServiceProto
                 synchronized (this) {
@@ -15339,6 +15404,10 @@
                     long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
                     mServices.writeToProto(proto);
                     proto.end(serviceToken);
+
+                    long processToken = proto.start(ActivityManagerServiceProto.PROCESSES);
+                    writeProcessesToProtoLocked(proto, dumpPackage);
+                    proto.end(processToken);
                 }
             }
             proto.flush();
@@ -15346,16 +15415,7 @@
             return;
         }
 
-        if (dumpPackage != null) {
-            try {
-                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
-                        dumpPackage, 0);
-                dumpAppId = UserHandle.getAppId(info.uid);
-            } catch (NameNotFoundException e) {
-                e.printStackTrace();
-            }
-        }
-
+        int dumpAppId = getAppId(dumpPackage);
         boolean more = false;
         // Is the caller requesting to dump a particular piece of data?
         if (opti < args.length) {
@@ -15397,33 +15457,17 @@
                     pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid)));
                 }
             } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
-                String[] newArgs;
-                String name;
-                if (opti >= args.length) {
-                    name = null;
-                    newArgs = EMPTY_STRING_ARRAY;
-                } else {
+                if (opti < args.length) {
                     dumpPackage = args[opti];
                     opti++;
-                    newArgs = new String[args.length - opti];
-                    if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
-                            args.length - opti);
                 }
                 synchronized (this) {
                     dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("broadcast-stats".equals(cmd)) {
-                String[] newArgs;
-                String name;
-                if (opti >= args.length) {
-                    name = null;
-                    newArgs = EMPTY_STRING_ARRAY;
-                } else {
+                if (opti < args.length) {
                     dumpPackage = args[opti];
                     opti++;
-                    newArgs = new String[args.length - opti];
-                    if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
-                            args.length - opti);
                 }
                 synchronized (this) {
                     if (dumpCheckinFormat) {
@@ -15434,33 +15478,17 @@
                     }
                 }
             } else if ("intents".equals(cmd) || "i".equals(cmd)) {
-                String[] newArgs;
-                String name;
-                if (opti >= args.length) {
-                    name = null;
-                    newArgs = EMPTY_STRING_ARRAY;
-                } else {
+                if (opti < args.length) {
                     dumpPackage = args[opti];
                     opti++;
-                    newArgs = new String[args.length - opti];
-                    if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
-                            args.length - opti);
                 }
                 synchronized (this) {
                     dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("processes".equals(cmd) || "p".equals(cmd)) {
-                String[] newArgs;
-                String name;
-                if (opti >= args.length) {
-                    name = null;
-                    newArgs = EMPTY_STRING_ARRAY;
-                } else {
+                if (opti < args.length) {
                     dumpPackage = args[opti];
                     opti++;
-                    newArgs = new String[args.length - opti];
-                    if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
-                            args.length - opti);
                 }
                 synchronized (this) {
                     dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage, dumpAppId);
@@ -15881,8 +15909,21 @@
         }
     }
 
+    private int getAppId(String dumpPackage) {
+        if (dumpPackage != null) {
+            try {
+                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                        dumpPackage, 0);
+                return UserHandle.getAppId(info.uid);
+            } catch (NameNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+        return -1;
+    }
+
     boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, SparseArray<UidRecord> uids,
-            String header, boolean needSep) {
+                String header, boolean needSep) {
         boolean printed = false;
         for (int i=0; i<uids.size(); i++) {
             UidRecord uidRec = uids.valueAt(i);
@@ -16100,7 +16141,7 @@
                     "OnHold Norm", "OnHold PERS", dumpPackage);
         }
 
-        needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
+        needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
 
         needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
 
@@ -16385,8 +16426,327 @@
         pw.println("  mForceBackgroundCheck=" + mForceBackgroundCheck);
     }
 
-    boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args,
-            int opti, boolean needSep, boolean dumpAll, String dumpPackage) {
+    void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
+        int numPers = 0;
+
+        final int NP = mProcessNames.getMap().size();
+        for (int ip=0; ip<NP; ip++) {
+            SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+            final int NA = procs.size();
+            for (int ia = 0; ia<NA; ia++) {
+                ProcessRecord r = procs.valueAt(ia);
+                if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+                    continue;
+                }
+                r.writeToProto(proto, ProcessesProto.PROCS);
+                if (r.persistent) {
+                    numPers++;
+                }
+            }
+        }
+
+        for (int i=0; i<mIsolatedProcesses.size(); i++) {
+            ProcessRecord r = mIsolatedProcesses.valueAt(i);
+            if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+                continue;
+            }
+            r.writeToProto(proto, ProcessesProto.ISOLATED_PROCS);
+        }
+
+        for (int i=0; i<mActiveInstrumentation.size(); i++) {
+            ActiveInstrumentation ai = mActiveInstrumentation.get(i);
+            if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
+                    && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
+                continue;
+            }
+            ai.writeToProto(proto, ProcessesProto.ACTIVE_INSTRUMENTATIONS);
+        }
+
+        int whichAppId = getAppId(dumpPackage);
+        for (int i=0; i<mActiveUids.size(); i++) {
+            UidRecord uidRec = mActiveUids.valueAt(i);
+            if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+                continue;
+            }
+            uidRec.writeToProto(proto, ProcessesProto.ACTIVE_UIDS);
+        }
+
+        for (int i=0; i<mValidateUids.size(); i++) {
+            UidRecord uidRec = mValidateUids.valueAt(i);
+            if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+                continue;
+            }
+            uidRec.writeToProto(proto, ProcessesProto.VALIDATE_UIDS);
+        }
+
+        if (mLruProcesses.size() > 0) {
+            long lruToken = proto.start(ProcessesProto.LRU_PROCS);
+            int total = mLruProcesses.size();
+            proto.write(ProcessesProto.LruProcesses.SIZE, total);
+            proto.write(ProcessesProto.LruProcesses.NON_ACT_AT, total-mLruProcessActivityStart);
+            proto.write(ProcessesProto.LruProcesses.NON_SVC_AT, total-mLruProcessServiceStart);
+            writeProcessOomListToProto(proto, ProcessesProto.LruProcesses.LIST, this,
+                    mLruProcesses,false, dumpPackage);
+            proto.end(lruToken);
+        }
+
+        if (dumpPackage != null) {
+            synchronized (mPidsSelfLocked) {
+                for (int i=0; i<mPidsSelfLocked.size(); i++) {
+                    ProcessRecord r = mPidsSelfLocked.valueAt(i);
+                    if (!r.pkgList.containsKey(dumpPackage)) {
+                        continue;
+                    }
+                    r.writeToProto(proto, ProcessesProto.PIDS_SELF_LOCKED);
+                }
+            }
+        }
+
+        if (mImportantProcesses.size() > 0) {
+            synchronized (mPidsSelfLocked) {
+                for (int i=0; i<mImportantProcesses.size(); i++) {
+                    ImportanceToken it = mImportantProcesses.valueAt(i);
+                    ProcessRecord r = mPidsSelfLocked.get(it.pid);
+                    if (dumpPackage != null && (r == null
+                            || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    it.writeToProto(proto, ProcessesProto.IMPORTANT_PROCS);
+                }
+            }
+        }
+
+        for (int i=0; i<mPersistentStartingProcesses.size(); i++) {
+            ProcessRecord r = mPersistentStartingProcesses.get(i);
+            if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                continue;
+            }
+            r.writeToProto(proto, ProcessesProto.PERSISTENT_STARTING_PROCS);
+        }
+
+        for (int i=0; i<mRemovedProcesses.size(); i++) {
+            ProcessRecord r = mRemovedProcesses.get(i);
+            if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                continue;
+            }
+            r.writeToProto(proto, ProcessesProto.REMOVED_PROCS);
+        }
+
+        for (int i=0; i<mProcessesOnHold.size(); i++) {
+            ProcessRecord r = mProcessesOnHold.get(i);
+            if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                continue;
+            }
+            r.writeToProto(proto, ProcessesProto.ON_HOLD_PROCS);
+        }
+
+        writeProcessesToGcToProto(proto, ProcessesProto.GC_PROCS, dumpPackage);
+        mAppErrors.writeToProto(proto, ProcessesProto.APP_ERRORS, dumpPackage);
+
+        if (dumpPackage == null) {
+            mUserController.writeToProto(proto, ProcessesProto.USER_CONTROLLER);
+            getGlobalConfiguration().writeToProto(proto, ProcessesProto.GLOBAL_CONFIGURATION);
+            proto.write(ProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
+        }
+
+        if (mHomeProcess != null && (dumpPackage == null
+                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+            mHomeProcess.writeToProto(proto, ProcessesProto.HOME_PROC);
+        }
+
+        if (mPreviousProcess != null && (dumpPackage == null
+                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+            mPreviousProcess.writeToProto(proto, ProcessesProto.PREVIOUS_PROC);
+            proto.write(ProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+        }
+
+        if (mHeavyWeightProcess != null && (dumpPackage == null
+                || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
+            mHeavyWeightProcess.writeToProto(proto, ProcessesProto.HEAVY_WEIGHT_PROC);
+        }
+
+        for (Map.Entry<String, Integer> entry : mCompatModePackages.getPackages().entrySet()) {
+            String pkg = entry.getKey();
+            int mode = entry.getValue();
+            if (dumpPackage == null || dumpPackage.equals(pkg)) {
+                long compatToken = proto.start(ProcessesProto.SCREEN_COMPAT_PACKAGES);
+                proto.write(ProcessesProto.ScreenCompatPackage.PACKAGE, pkg);
+                proto.write(ProcessesProto.ScreenCompatPackage.MODE, mode);
+                proto.end(compatToken);
+            }
+        }
+
+        final int NI = mUidObservers.getRegisteredCallbackCount();
+        for (int i=0; i<NI; i++) {
+            final UidObserverRegistration reg = (UidObserverRegistration)
+                    mUidObservers.getRegisteredCallbackCookie(i);
+            if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
+                reg.writeToProto(proto, ProcessesProto.UID_OBSERVERS);
+            }
+        }
+
+        for (int v : mDeviceIdleWhitelist) {
+            proto.write(ProcessesProto.DEVICE_IDLE_WHITELIST, v);
+        }
+
+        for (int v : mDeviceIdleTempWhitelist) {
+            proto.write(ProcessesProto.DEVICE_IDLE_TEMP_WHITELIST, v);
+        }
+
+        if (mPendingTempWhitelist.size() > 0) {
+            for (int i=0; i < mPendingTempWhitelist.size(); i++) {
+                mPendingTempWhitelist.valueAt(i).writeToProto(proto,
+                        ProcessesProto.PENDING_TEMP_WHITELIST);
+            }
+        }
+
+        if (dumpPackage == null) {
+            final long sleepToken = proto.start(ProcessesProto.SLEEP_STATUS);
+            proto.write(ProcessesProto.SleepStatus.WAKEFULNESS,
+                    PowerManagerInternal.wakefulnessToProtoEnum(mWakefulness));
+            for (SleepToken st : mStackSupervisor.mSleepTokens) {
+                proto.write(ProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString());
+            }
+            proto.write(ProcessesProto.SleepStatus.SLEEPING, mSleeping);
+            proto.write(ProcessesProto.SleepStatus.SHUTTING_DOWN, mShuttingDown);
+            proto.write(ProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
+            proto.end(sleepToken);
+
+            if (mRunningVoice != null) {
+                final long vrToken = proto.start(ProcessesProto.RUNNING_VOICE);
+                proto.write(ProcessesProto.VoiceProto.SESSION, mRunningVoice.toString());
+                mVoiceWakeLock.writeToProto(proto, ProcessesProto.VoiceProto.WAKELOCK);
+                proto.end(vrToken);
+            }
+
+            mVrController.writeToProto(proto, ProcessesProto.VR_CONTROLLER);
+        }
+
+        if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
+                || mOrigWaitForDebugger) {
+            if (dumpPackage == null || dumpPackage.equals(mDebugApp)
+                    || dumpPackage.equals(mOrigDebugApp)) {
+                final long debugAppToken = proto.start(ProcessesProto.DEBUG);
+                proto.write(ProcessesProto.DebugApp.DEBUG_APP, mDebugApp);
+                proto.write(ProcessesProto.DebugApp.ORIG_DEBUG_APP, mOrigDebugApp);
+                proto.write(ProcessesProto.DebugApp.DEBUG_TRANSIENT, mDebugTransient);
+                proto.write(ProcessesProto.DebugApp.ORIG_WAIT_FOR_DEBUGGER, mOrigWaitForDebugger);
+                proto.end(debugAppToken);
+            }
+        }
+
+        if (mCurAppTimeTracker != null) {
+            mCurAppTimeTracker.writeToProto(proto, ProcessesProto.CURRENT_TRACKER, true);
+        }
+
+        if (mMemWatchProcesses.getMap().size() > 0) {
+            final long token = proto.start(ProcessesProto.MEM_WATCH_PROCESSES);
+            ArrayMap<String, SparseArray<Pair<Long, String>>> procs = mMemWatchProcesses.getMap();
+            for (int i=0; i<procs.size(); i++) {
+                final String proc = procs.keyAt(i);
+                final SparseArray<Pair<Long, String>> uids = procs.valueAt(i);
+                final long ptoken = proto.start(ProcessesProto.MemWatchProcess.PROCS);
+                proto.write(ProcessesProto.MemWatchProcess.Process.NAME, proc);
+                for (int j=0; j<uids.size(); j++) {
+                    final long utoken = proto.start(ProcessesProto.MemWatchProcess.Process.MEM_STATS);
+                    Pair<Long, String> val = uids.valueAt(j);
+                    proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.UID, uids.keyAt(j));
+                    proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.SIZE,
+                            DebugUtils.sizeValueToString(val.first, new StringBuilder()));
+                    proto.write(ProcessesProto.MemWatchProcess.Process.MemStats.REPORT_TO, val.second);
+                    proto.end(utoken);
+                }
+                proto.end(ptoken);
+            }
+
+            final long dtoken = proto.start(ProcessesProto.MemWatchProcess.DUMP);
+            proto.write(ProcessesProto.MemWatchProcess.Dump.PROC_NAME, mMemWatchDumpProcName);
+            proto.write(ProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
+            proto.write(ProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
+            proto.write(ProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
+            proto.end(dtoken);
+
+            proto.end(token);
+        }
+
+        if (mTrackAllocationApp != null) {
+            if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
+                proto.write(ProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp);
+            }
+        }
+
+        if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
+                (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
+            if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
+                final long token = proto.start(ProcessesProto.PROFILE);
+                proto.write(ProcessesProto.Profile.APP_NAME, mProfileApp);
+                mProfileProc.writeToProto(proto,ProcessesProto.Profile.PROC);
+                if (mProfilerInfo != null) {
+                    mProfilerInfo.writeToProto(proto, ProcessesProto.Profile.INFO);
+                    proto.write(ProcessesProto.Profile.TYPE, mProfileType);
+                }
+                proto.end(token);
+            }
+        }
+
+        if (dumpPackage == null || dumpPackage.equals(mNativeDebuggingApp)) {
+            proto.write(ProcessesProto.NATIVE_DEBUGGING_APP, mNativeDebuggingApp);
+        }
+
+        if (dumpPackage == null) {
+            proto.write(ProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
+            if (mController != null) {
+                final long token = proto.start(ProcessesProto.CONTROLLER);
+                proto.write(ProcessesProto.Controller.CONTROLLER, mController.toString());
+                proto.write(ProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
+                proto.end(token);
+            }
+            proto.write(ProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
+            proto.write(ProcessesProto.PROCESSES_READY, mProcessesReady);
+            proto.write(ProcessesProto.SYSTEM_READY, mSystemReady);
+            proto.write(ProcessesProto.BOOTED, mBooted);
+            proto.write(ProcessesProto.FACTORY_TEST, mFactoryTest);
+            proto.write(ProcessesProto.BOOTING, mBooting);
+            proto.write(ProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
+            proto.write(ProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
+            proto.write(ProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
+            mStackSupervisor.mGoingToSleep.writeToProto(proto, ProcessesProto.GOING_TO_SLEEP);
+            mStackSupervisor.mLaunchingActivity.writeToProto(proto, ProcessesProto.LAUNCHING_ACTIVITY);
+            proto.write(ProcessesProto.ADJ_SEQ, mAdjSeq);
+            proto.write(ProcessesProto.LRU_SEQ, mLruSeq);
+            proto.write(ProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
+            proto.write(ProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
+            proto.write(ProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
+            proto.write(ProcessesProto.ALLOW_LOWER_MEM_LEVEL, mAllowLowerMemLevel);
+            proto.write(ProcessesProto.LAST_MEMORY_LEVEL, mLastMemoryLevel);
+            proto.write(ProcessesProto.LAST_NUM_PROCESSES, mLastNumProcesses);
+            long now = SystemClock.uptimeMillis();
+            ProtoUtils.toDuration(proto, ProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
+            proto.write(ProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
+        }
+
+    }
+
+    void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
+        if (mProcessesToGc.size() > 0) {
+            long now = SystemClock.uptimeMillis();
+            for (int i=0; i<mProcessesToGc.size(); i++) {
+                ProcessRecord r = mProcessesToGc.get(i);
+                if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                    continue;
+                }
+                final long token = proto.start(fieldId);
+                r.writeToProto(proto, ProcessToGcProto.PROC);
+                proto.write(ProcessToGcProto.REPORT_LOW_MEMORY, r.reportLowMemory);
+                proto.write(ProcessToGcProto.NOW_UPTIME_MS, now);
+                proto.write(ProcessToGcProto.LAST_GCED_MS, r.lastRequestedGc);
+                proto.write(ProcessToGcProto.LAST_LOW_MEMORY_MS, r.lastLowMemory);
+                proto.end(token);
+            }
+        }
+    }
+
+    boolean dumpProcessesToGc(PrintWriter pw, boolean needSep, String dumpPackage) {
         if (mProcessesToGc.size() > 0) {
             boolean printed = false;
             long now = SystemClock.uptimeMillis();
@@ -16464,7 +16824,7 @@
             needSep = true;
         }
 
-        dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
+        dumpProcessesToGc(pw, needSep, null);
 
         pw.println();
         pw.println("  mHomeProcess: " + mHomeProcess);
@@ -17015,11 +17375,8 @@
         return numPers;
     }
 
-    private static final boolean dumpProcessOomList(PrintWriter pw,
-            ActivityManagerService service, List<ProcessRecord> origList,
-            String prefix, String normalLabel, String persistentLabel,
-            boolean inclDetails, String dumpPackage) {
-
+    private static final ArrayList<Pair<ProcessRecord, Integer>>
+        sortProcessOomList(List<ProcessRecord> origList, String dumpPackage) {
         ArrayList<Pair<ProcessRecord, Integer>> list
                 = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
         for (int i=0; i<origList.size(); i++) {
@@ -17030,10 +17387,6 @@
             list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
         }
 
-        if (list.size() <= 0) {
-            return false;
-        }
-
         Comparator<Pair<ProcessRecord, Integer>> comparator
                 = new Comparator<Pair<ProcessRecord, Integer>>() {
             @Override
@@ -17053,6 +17406,113 @@
         };
 
         Collections.sort(list, comparator);
+        return list;
+    }
+
+    private static final boolean writeProcessOomListToProto(ProtoOutputStream proto, long fieldId,
+            ActivityManagerService service, List<ProcessRecord> origList,
+            boolean inclDetails, String dumpPackage) {
+        ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+        if (list.isEmpty()) return false;
+
+        final long curUptime = SystemClock.uptimeMillis();
+
+        for (int i = list.size() - 1; i >= 0; i--) {
+            ProcessRecord r = list.get(i).first;
+            long token = proto.start(fieldId);
+            String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
+            proto.write(ProcessOomProto.PERSISTENT, r.persistent);
+            proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
+            proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
+            int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
+            switch (r.setSchedGroup) {
+                case ProcessList.SCHED_GROUP_BACKGROUND:
+                    schedGroup = ProcessOomProto.SCHED_GROUP_BACKGROUND;
+                    break;
+                case ProcessList.SCHED_GROUP_DEFAULT:
+                    schedGroup = ProcessOomProto.SCHED_GROUP_DEFAULT;
+                    break;
+                case ProcessList.SCHED_GROUP_TOP_APP:
+                    schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP;
+                    break;
+                case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
+                    schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP_BOUND;
+                    break;
+            }
+            if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) {
+                proto.write(ProcessOomProto.SCHED_GROUP, schedGroup);
+            }
+            if (r.foregroundActivities) {
+                proto.write(ProcessOomProto.ACTIVITIES, true);
+            } else if (r.foregroundServices) {
+                proto.write(ProcessOomProto.SERVICES, true);
+            }
+            proto.write(ProcessOomProto.STATE, ProcessList.makeProcStateProtoEnum(r.curProcState));
+            proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.trimMemoryLevel);
+            r.writeToProto(proto, ProcessOomProto.PROC);
+            proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
+            if (r.adjSource != null || r.adjTarget != null) {
+                if (r.adjTarget instanceof  ComponentName) {
+                    ComponentName cn = (ComponentName) r.adjTarget;
+                    cn.writeToProto(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
+                } else if (r.adjTarget != null) {
+                    proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString());
+                }
+                if (r.adjSource instanceof ProcessRecord) {
+                    ProcessRecord p = (ProcessRecord) r.adjSource;
+                    p.writeToProto(proto, ProcessOomProto.ADJ_SOURCE_PROC);
+                } else if (r.adjSource != null) {
+                    proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString());
+                }
+            }
+            if (inclDetails) {
+                long detailToken = proto.start(ProcessOomProto.DETAIL);
+                proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj);
+                proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.curRawAdj);
+                proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj);
+                proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj);
+                proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj);
+                proto.write(ProcessOomProto.Detail.CURRENT_STATE,
+                        ProcessList.makeProcStateProtoEnum(r.curProcState));
+                proto.write(ProcessOomProto.Detail.SET_STATE,
+                        ProcessList.makeProcStateProtoEnum(r.setProcState));
+                proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString(
+                        r.lastPss*1024, new StringBuilder()));
+                proto.write(ProcessOomProto.Detail.LAST_SWAP_PSS, DebugUtils.sizeValueToString(
+                        r.lastSwapPss*1024, new StringBuilder()));
+                proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString(
+                        r.lastCachedPss*1024, new StringBuilder()));
+                proto.write(ProcessOomProto.Detail.CACHED, r.cached);
+                proto.write(ProcessOomProto.Detail.EMPTY, r.empty);
+                proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient);
+
+                if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+                    if (r.lastCpuTime != 0) {
+                        long uptimeSince = curUptime - service.mLastPowerCheckUptime;
+                        long timeUsed = r.curCpuTime - r.lastCpuTime;
+                        long cpuTimeToken = proto.start(ProcessOomProto.Detail.SERVICE_RUN_TIME);
+                        proto.write(ProcessOomProto.Detail.CpuRunTime.OVER_MS, uptimeSince);
+                        proto.write(ProcessOomProto.Detail.CpuRunTime.USED_MS, timeUsed);
+                        proto.write(ProcessOomProto.Detail.CpuRunTime.ULTILIZATION,
+                                (100.0*timeUsed)/uptimeSince);
+                        proto.end(cpuTimeToken);
+                    }
+                }
+                proto.end(detailToken);
+            }
+            proto.end(token);
+        }
+
+        return true;
+    }
+
+    private static final boolean dumpProcessOomList(PrintWriter pw,
+            ActivityManagerService service, List<ProcessRecord> origList,
+            String prefix, String normalLabel, String persistentLabel,
+            boolean inclDetails, String dumpPackage) {
+
+        ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+        if (list.isEmpty()) return false;
 
         final long curUptime = SystemClock.uptimeMillis();
         final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
@@ -24120,7 +24580,7 @@
         final int size = mActiveUids.size();
         for (int i = 0; i < size; i++) {
             final int uid = mActiveUids.keyAt(i);
-            if (!UserHandle.isApp(uid)) {
+            if (UserHandle.isCore(uid)) {
                 continue;
             }
             final UidRecord uidRec = mActiveUids.valueAt(i);
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index f9932b2..5551914 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -220,7 +220,7 @@
         }
     }
 
-    final int startActivityInPackage(int uid, int realCallingUid, int realCallingPid,
+    final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
             String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
             int userId, TaskRecord inTask, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8595aa3..4dc30dd 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1252,7 +1252,7 @@
                     outActivity[0] = reusedActivity;
                 }
 
-                return START_DELIVERED_TO_TOP;
+                return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
             }
         }
 
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 0da7e0e..c7d93be 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -22,6 +22,7 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.server.RescueParty;
 import com.android.server.Watchdog;
+import com.android.server.am.proto.AppErrorsProto;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -48,6 +49,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -103,8 +105,76 @@
         mContext = context;
     }
 
-    boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep,
-            String dumpPackage) {
+    void writeToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
+        if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
+            return;
+        }
+
+        final long token = proto.start(fieldId);
+        final long now = SystemClock.uptimeMillis();
+        proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
+
+        if (!mProcessCrashTimes.getMap().isEmpty()) {
+            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+            final int procCount = pmap.size();
+            for (int ip = 0; ip < procCount; ip++) {
+                final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+                final String pname = pmap.keyAt(ip);
+                final SparseArray<Long> uids = pmap.valueAt(ip);
+                final int uidCount = uids.size();
+
+                proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+                for (int i = 0; i < uidCount; i++) {
+                    final int puid = uids.keyAt(i);
+                    final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+                    if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+                    proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+                    proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+                            uids.valueAt(i));
+                    proto.end(etoken);
+                }
+                proto.end(ctoken);
+            }
+
+        }
+
+        if (!mBadProcesses.getMap().isEmpty()) {
+            final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+            final int processCount = pmap.size();
+            for (int ip = 0; ip < processCount; ip++) {
+                final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+                final String pname = pmap.keyAt(ip);
+                final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+                final int uidCount = uids.size();
+
+                proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+                for (int i = 0; i < uidCount; i++) {
+                    final int puid = uids.keyAt(i);
+                    final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+                    if (dumpPackage != null && (r == null
+                            || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    final BadProcessInfo info = uids.valueAt(i);
+                    final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+                    proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+                    proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+                    proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+                    proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+                    proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+                    proto.end(etoken);
+                }
+                proto.end(btoken);
+            }
+        }
+
+        proto.end(token);
+    }
+
+    boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
         if (!mProcessCrashTimes.getMap().isEmpty()) {
             boolean printed = false;
             final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/AppTimeTracker.java b/services/core/java/com/android/server/am/AppTimeTracker.java
index 910f33d..d96364a 100644
--- a/services/core/java/com/android/server/am/AppTimeTracker.java
+++ b/services/core/java/com/android/server/am/AppTimeTracker.java
@@ -25,6 +25,10 @@
 import android.util.ArrayMap;
 import android.util.MutableLong;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
+
+import com.android.server.am.proto.AppTimeTrackerProto;
 
 import java.io.PrintWriter;
 
@@ -119,4 +123,22 @@
             pw.print(prefix); pw.print("mStartedPackage="); pw.println(mStartedPackage);
         }
     }
+
+    void writeToProto(ProtoOutputStream proto, long fieldId, boolean details) {
+        final long token = proto.start(fieldId);
+        proto.write(AppTimeTrackerProto.RECEIVER, mReceiver.toString());
+        proto.write(AppTimeTrackerProto.TOTAL_DURATION_MS, mTotalTime);
+        for (int i=0; i<mPackageTimes.size(); i++) {
+            final long ptoken = proto.start(AppTimeTrackerProto.PACKAGE_TIMES);
+            proto.write(AppTimeTrackerProto.PackageTime.PACKAGE, mPackageTimes.keyAt(i));
+            proto.write(AppTimeTrackerProto.PackageTime.DURATION_MS, mPackageTimes.valueAt(i).value);
+            proto.end(ptoken);
+        }
+        if (details && mStartedTime != 0) {
+            ProtoUtils.toDuration(proto, AppTimeTrackerProto.STARTED_TIME,
+                    mStartedTime, SystemClock.elapsedRealtime());
+            proto.write(AppTimeTrackerProto.STARTED_PACKAGE, mStartedPackage);
+        }
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 6df283c..d320fb1 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -20,6 +20,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
 
 import com.android.server.am.proto.ConnectionRecordProto;
 
@@ -37,7 +38,43 @@
     final PendingIntent clientIntent; // How to launch the client.
     String stringName;              // Caching of toString.
     boolean serviceDead;            // Well is it?
-    
+
+    // Please keep the following two enum list synced.
+    private static int[] BIND_ORIG_ENUMS = new int[] {
+            Context.BIND_AUTO_CREATE,
+            Context.BIND_DEBUG_UNBIND,
+            Context.BIND_NOT_FOREGROUND,
+            Context.BIND_IMPORTANT_BACKGROUND,
+            Context.BIND_ABOVE_CLIENT,
+            Context.BIND_ALLOW_OOM_MANAGEMENT,
+            Context.BIND_WAIVE_PRIORITY,
+            Context.BIND_IMPORTANT,
+            Context.BIND_ADJUST_WITH_ACTIVITY,
+            Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+            Context.BIND_FOREGROUND_SERVICE,
+            Context.BIND_TREAT_LIKE_ACTIVITY,
+            Context.BIND_VISIBLE,
+            Context.BIND_SHOWING_UI,
+            Context.BIND_NOT_VISIBLE,
+    };
+    private static int[] BIND_PROTO_ENUMS = new int[] {
+            ConnectionRecordProto.AUTO_CREATE,
+            ConnectionRecordProto.DEBUG_UNBIND,
+            ConnectionRecordProto.NOT_FG,
+            ConnectionRecordProto.IMPORTANT_BG,
+            ConnectionRecordProto.ABOVE_CLIENT,
+            ConnectionRecordProto.ALLOW_OOM_MANAGEMENT,
+            ConnectionRecordProto.WAIVE_PRIORITY,
+            ConnectionRecordProto.IMPORTANT,
+            ConnectionRecordProto.ADJUST_WITH_ACTIVITY,
+            ConnectionRecordProto.FG_SERVICE_WHILE_AWAKE,
+            ConnectionRecordProto.FG_SERVICE,
+            ConnectionRecordProto.TREAT_LIKE_ACTIVITY,
+            ConnectionRecordProto.VISIBLE,
+            ConnectionRecordProto.SHOWING_UI,
+            ConnectionRecordProto.NOT_VISIBLE,
+    };
+
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "binding=" + binding);
         if (activity != null) {
@@ -46,7 +83,7 @@
         pw.println(prefix + "conn=" + conn.asBinder()
                 + " flags=0x" + Integer.toHexString(flags));
     }
-    
+
     ConnectionRecord(AppBindRecord _binding, ActivityRecord _activity,
                IServiceConnection _conn, int _flags,
                int _clientLabel, PendingIntent _clientIntent) {
@@ -131,51 +168,8 @@
         if (binding.client != null) {
             proto.write(ConnectionRecordProto.USER_ID, binding.client.userId);
         }
-        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.AUTO_CREATE);
-        }
-        if ((flags&Context.BIND_DEBUG_UNBIND) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEBUG_UNBIND);
-        }
-        if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.NOT_FG);
-        }
-        if ((flags&Context.BIND_IMPORTANT_BACKGROUND) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.IMPORTANT_BG);
-        }
-        if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ABOVE_CLIENT);
-        }
-        if ((flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ALLOW_OOM_MANAGEMENT);
-        }
-        if ((flags&Context.BIND_WAIVE_PRIORITY) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.WAIVE_PRIORITY);
-        }
-        if ((flags&Context.BIND_IMPORTANT) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.IMPORTANT);
-        }
-        if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ADJUST_WITH_ACTIVITY);
-        }
-        if ((flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.FG_SERVICE_WHILE_WAKE);
-        }
-        if ((flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.FG_SERVICE);
-        }
-        if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.TREAT_LIKE_ACTIVITY);
-        }
-        if ((flags&Context.BIND_VISIBLE) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.VISIBLE);
-        }
-        if ((flags&Context.BIND_SHOWING_UI) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.SHOWING_UI);
-        }
-        if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
-            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.NOT_VISIBLE);
-        }
+        ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, ConnectionRecordProto.FLAGS,
+                flags, BIND_ORIG_ENUMS, BIND_PROTO_ENUMS);
         if (serviceDead) {
             proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEAD);
         }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 77f5c16..29bfebe 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -24,6 +24,7 @@
 import java.nio.ByteBuffer;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerProto;
 import android.os.Build;
 import android.os.SystemClock;
 import com.android.internal.util.MemInfoReader;
@@ -416,6 +417,53 @@
         return procState;
     }
 
+    public static int makeProcStateProtoEnum(int curProcState) {
+        switch (curProcState) {
+            case ActivityManager.PROCESS_STATE_PERSISTENT:
+                return ActivityManagerProto.PROCESS_STATE_PERSISTENT;
+            case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+                return ActivityManagerProto.PROCESS_STATE_PERSISTENT_UI;
+            case ActivityManager.PROCESS_STATE_TOP:
+                return ActivityManagerProto.PROCESS_STATE_TOP;
+            case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                return ActivityManagerProto.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+            case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+                return ActivityManagerProto.PROCESS_STATE_FOREGROUND_SERVICE;
+            case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
+                return ActivityManagerProto.PROCESS_STATE_TOP_SLEEPING;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_BACKGROUND;
+            case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+                return ActivityManagerProto.PROCESS_STATE_TRANSIENT_BACKGROUND;
+            case ActivityManager.PROCESS_STATE_BACKUP:
+                return ActivityManagerProto.PROCESS_STATE_BACKUP;
+            case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+                return ActivityManagerProto.PROCESS_STATE_HEAVY_WEIGHT;
+            case ActivityManager.PROCESS_STATE_SERVICE:
+                return ActivityManagerProto.PROCESS_STATE_SERVICE;
+            case ActivityManager.PROCESS_STATE_RECEIVER:
+                return ActivityManagerProto.PROCESS_STATE_RECEIVER;
+            case ActivityManager.PROCESS_STATE_HOME:
+                return ActivityManagerProto.PROCESS_STATE_HOME;
+            case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+                return ActivityManagerProto.PROCESS_STATE_LAST_ACTIVITY;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY;
+            case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+            case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+                return ActivityManagerProto.PROCESS_STATE_CACHED_RECENT;
+            case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+                return ActivityManagerProto.PROCESS_STATE_CACHED_EMPTY;
+            case ActivityManager.PROCESS_STATE_NONEXISTENT:
+                return ActivityManagerProto.PROCESS_STATE_NONEXISTENT;
+            default:
+                return -1;
+        }
+    }
+
     public static void appendRamKb(StringBuilder sb, long ramKb) {
         for (int j=0, fact=10; j<6; j++, fact*=10) {
             if (ramKb < fact) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a1e5947..03e140d 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -679,6 +679,7 @@
                 proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
             }
         }
+        proto.write(ProcessRecordProto.PERSISTENT, persistent);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 8efcb4f..3886e5a 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -18,13 +18,17 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.ActivityManagerProto;
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.proto.UidRecordProto;
 
 /**
  * Overall information about a uid that has actively running processes.
@@ -86,6 +90,22 @@
     static final int CHANGE_CACHED = 1<<3;
     static final int CHANGE_UNCACHED = 1<<4;
 
+    // Keep the enum lists in sync
+    private static int[] ORIG_ENUMS = new int[] {
+            CHANGE_GONE,
+            CHANGE_IDLE,
+            CHANGE_ACTIVE,
+            CHANGE_CACHED,
+            CHANGE_UNCACHED,
+    };
+    private static int[] PROTO_ENUMS = new int[] {
+            UidRecordProto.CHANGE_GONE,
+            UidRecordProto.CHANGE_IDLE,
+            UidRecordProto.CHANGE_ACTIVE,
+            UidRecordProto.CHANGE_CACHED,
+            UidRecordProto.CHANGE_UNCACHED,
+    };
+
     static final class ChangeItem {
         UidRecord uidRecord;
         int uid;
@@ -125,6 +145,34 @@
         }
     }
 
+
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        long token = proto.start(fieldId);
+        proto.write(UidRecordProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this)));
+        proto.write(UidRecordProto.UID, uid);
+        proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(curProcState));
+        proto.write(UidRecordProto.EPHEMERAL, ephemeral);
+        proto.write(UidRecordProto.FG_SERVICES, foregroundServices);
+        proto.write(UidRecordProto.WHILELIST, curWhitelist);
+        ProtoUtils.toDuration(proto, UidRecordProto.LAST_BACKGROUND_TIME,
+                lastBackgroundTime, SystemClock.elapsedRealtime());
+        proto.write(UidRecordProto.IDLE, idle);
+        if (lastReportedChange != 0) {
+            ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidRecordProto.LAST_REPORTED_CHANGES,
+                    lastReportedChange, ORIG_ENUMS, PROTO_ENUMS);
+        }
+        proto.write(UidRecordProto.NUM_PROCS, numProcs);
+
+        long seqToken = proto.start(UidRecordProto.NETWORK_STATE_UPDATE);
+        proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq);
+        proto.write(UidRecordProto.ProcStateSequence.LAST_NETWORK_UPDATED,
+                lastNetworkUpdatedProcStateSeq);
+        proto.write(UidRecordProto.ProcStateSequence.LAST_DISPATCHED, lastDispatchedProcStateSeq);
+        proto.end(seqToken);
+
+        proto.end(token);
+    }
+
     public String toString() {
         StringBuilder sb = new StringBuilder(128);
         sb.append("UidRecord{");
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5ada484..7b0c714 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -83,6 +83,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimingsTraceLog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -94,6 +95,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
+import com.android.server.am.proto.UserControllerProto;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
@@ -1844,6 +1846,36 @@
         }
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        synchronized (mLock) {
+            long token = proto.start(fieldId);
+            for (int i = 0; i < mStartedUsers.size(); i++) {
+                UserState uss = mStartedUsers.valueAt(i);
+                final long uToken = proto.start(UserControllerProto.STARTED_USERS);
+                proto.write(UserControllerProto.User.ID, uss.mHandle.getIdentifier());
+                uss.writeToProto(proto, UserControllerProto.User.STATE);
+                proto.end(uToken);
+            }
+            for (int i = 0; i < mStartedUserArray.length; i++) {
+                proto.write(UserControllerProto.STARTED_USER_ARRAY, mStartedUserArray[i]);
+            }
+            for (int i = 0; i < mUserLru.size(); i++) {
+                proto.write(UserControllerProto.USER_LRU, mUserLru.get(i));
+            }
+            if (mUserProfileGroupIds.size() > 0) {
+                for (int i = 0; i < mUserProfileGroupIds.size(); i++) {
+                    final long uToken = proto.start(UserControllerProto.USER_PROFILE_GROUP_IDS);
+                    proto.write(UserControllerProto.UserProfile.USER,
+                            mUserProfileGroupIds.keyAt(i));
+                    proto.write(UserControllerProto.UserProfile.PROFILE,
+                            mUserProfileGroupIds.valueAt(i));
+                    proto.end(uToken);
+                }
+            }
+            proto.end(token);
+        }
+    }
+
     void dump(PrintWriter pw, boolean dumpAll) {
         synchronized (mLock) {
             pw.println("  mStartedUsers:");
@@ -1868,10 +1900,6 @@
                 pw.print(mUserLru.get(i));
             }
             pw.println("]");
-            if (dumpAll) {
-                pw.print("  mStartedUserArray: ");
-                pw.println(Arrays.toString(mStartedUserArray));
-            }
             if (mUserProfileGroupIds.size() > 0) {
                 pw.println("  mUserProfileGroupIds:");
                 for (int i=0; i< mUserProfileGroupIds.size(); i++) {
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index d36d9cb..00597e2 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -24,8 +24,10 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ProgressReporter;
+import com.android.server.am.proto.UserStateProto;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -112,10 +114,29 @@
         }
     }
 
+    public static int stateToProtoEnum(int state) {
+        switch (state) {
+            case STATE_BOOTING: return UserStateProto.STATE_BOOTING;
+            case STATE_RUNNING_LOCKED: return UserStateProto.STATE_RUNNING_LOCKED;
+            case STATE_RUNNING_UNLOCKING: return UserStateProto.STATE_RUNNING_UNLOCKING;
+            case STATE_RUNNING_UNLOCKED: return UserStateProto.STATE_RUNNING_UNLOCKED;
+            case STATE_STOPPING: return UserStateProto.STATE_STOPPING;
+            case STATE_SHUTDOWN: return UserStateProto.STATE_SHUTDOWN;
+            default: return state;
+        }
+    }
+
     void dump(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("state="); pw.print(stateToString(state));
         if (switching) pw.print(" SWITCHING");
         pw.println();
     }
+
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(UserStateProto.STATE, stateToProtoEnum(state));
+        proto.write(UserStateProto.SWITCHING, switching);
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index feddfe3..d32db7e 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -20,7 +20,11 @@
 import android.os.Process;
 import android.service.vr.IPersistentVrStateCallbacks;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
+
 import com.android.server.LocalServices;
+import com.android.server.am.proto.ProcessesProto.VrControllerProto;
 import com.android.server.vr.VrManagerInternal;
 
 /**
@@ -49,6 +53,18 @@
     private static final int FLAG_VR_MODE = 1;
     private static final int FLAG_PERSISTENT_VR_MODE = 2;
 
+    // Keep the enum lists in sync
+    private static int[] ORIG_ENUMS = new int[] {
+            FLAG_NON_VR_MODE,
+            FLAG_VR_MODE,
+            FLAG_PERSISTENT_VR_MODE,
+    };
+    private static int[] PROTO_ENUMS = new int[] {
+            VrControllerProto.FLAG_NON_VR_MODE,
+            VrControllerProto.FLAG_VR_MODE,
+            VrControllerProto.FLAG_PERSISTENT_VR_MODE,
+    };
+
     // Invariants maintained for mVrState
     //
     //   Always true:
@@ -420,4 +436,12 @@
     public String toString() {
       return String.format("[VrState=0x%x,VrRenderThreadTid=%d]", mVrState, mVrRenderThreadTid);
     }
+
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, VrControllerProto.VR_MODE,
+                mVrState, ORIG_ENUMS, PROTO_ENUMS);
+        proto.write(VrControllerProto.RENDER_THREAD_ID, mVrRenderThreadTid);
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
new file mode 100644
index 0000000..24865bc
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -0,0 +1,52 @@
+/*
+ * 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.server.connectivity;
+
+/**
+ * A class encapsulating various constants used by Connectivity.
+ * @hide
+ */
+public class ConnectivityConstants {
+    // IPC constants
+    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+    public static final String EXTRA_CELL_ID = "extra_cellid";
+    public static final String EXTRA_SSID = "extra_ssid";
+    public static final String EXTRA_BSSID = "extra_bssid";
+    /** real time since boot */
+    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+
+    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
+
+    // Penalty applied to scores of Networks that have not been validated.
+    public static final int UNVALIDATED_SCORE_PENALTY = 40;
+
+    // Score for explicitly connected network.
+    //
+    // This ensures that a) the explicitly selected network is never trumped by anything else, and
+    // b) the explicitly selected network is never torn down.
+    public static final int MAXIMUM_NETWORK_SCORE = 100;
+    // VPNs typically have priority over other networks. Give them a score that will
+    // let them win every single time.
+    public static final int VPN_DEFAULT_SCORE = 101;
+}
diff --git a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
index 2ccfdd1..f6b73b7 100644
--- a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
+++ b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
@@ -16,6 +16,9 @@
 
 package com.android.server.connectivity;
 
+import static android.net.util.NetworkConstants.IPV4_HEADER_MIN_LEN;
+import static android.net.util.NetworkConstants.UDP_HEADER_LEN;
+
 import android.system.OsConstants;
 import android.net.ConnectivityManager;
 import android.net.NetworkUtils;
@@ -57,9 +60,6 @@
     /** Packet data. A raw byte string of packet data, not including the link-layer header. */
     public final byte[] data;
 
-    private static final int IPV4_HEADER_LENGTH = 20;
-    private static final int UDP_HEADER_LENGTH = 8;
-
     protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
             InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
         this.srcAddress = srcAddress;
@@ -111,7 +111,7 @@
             throw new InvalidPacketException(ERROR_INVALID_PORT);
         }
 
-        int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
+        int length = IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + 1;
         ByteBuffer buf = ByteBuffer.allocate(length);
         buf.order(ByteOrder.BIG_ENDIAN);
         buf.putShort((short) 0x4500);             // IP version and TOS
@@ -130,7 +130,7 @@
         buf.putShort((short) 0);                  // UDP checksum
         buf.put((byte) 0xff);                     // NAT-T keepalive
         buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
-        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
+        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_MIN_LEN));
 
         return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a4d7242..85b70ca 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -223,14 +223,6 @@
 
     // This represents the last score received from the NetworkAgent.
     private int currentScore;
-    // Penalty applied to scores of Networks that have not been validated.
-    private static final int UNVALIDATED_SCORE_PENALTY = 40;
-
-    // Score for explicitly connected network.
-    //
-    // This ensures that a) the explicitly selected network is never trumped by anything else, and
-    // b) the explicitly selected network is never torn down.
-    private static final int MAXIMUM_NETWORK_SCORE = 100;
 
     // The list of NetworkRequests being satisfied by this Network.
     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -428,12 +420,12 @@
         // down an explicitly selected network before the user gets a chance to prefer it when
         // a higher-scoring network (e.g., Ethernet) is available.
         if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
-            return MAXIMUM_NETWORK_SCORE;
+            return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;
         }
 
         int score = currentScore;
         if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
-            score -= UNVALIDATED_SCORE_PENALTY;
+            score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
         }
         if (score < 0) score = 0;
         return score;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 85d1d1e..c471f0c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -24,6 +24,7 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.TrafficStats;
+import android.net.util.NetworkConstants;
 import android.os.SystemClock;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -421,8 +422,6 @@
     private class IcmpCheck extends SimpleSocketCheck implements Runnable {
         private static final int TIMEOUT_SEND = 100;
         private static final int TIMEOUT_RECV = 300;
-        private static final int ICMPV4_ECHO_REQUEST = 8;
-        private static final int ICMPV6_ECHO_REQUEST = 128;
         private static final int PACKET_BUFSIZE = 512;
         private final int mProtocol;
         private final int mIcmpType;
@@ -432,11 +431,11 @@
 
             if (mAddressFamily == AF_INET6) {
                 mProtocol = IPPROTO_ICMPV6;
-                mIcmpType = ICMPV6_ECHO_REQUEST;
+                mIcmpType = NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;
                 mMeasurement.description = "ICMPv6";
             } else {
                 mProtocol = IPPROTO_ICMP;
-                mIcmpType = ICMPV4_ECHO_REQUEST;
+                mIcmpType = NetworkConstants.ICMPV4_ECHO_REQUEST_TYPE;
                 mMeasurement.description = "ICMPv4";
             }
 
@@ -504,7 +503,6 @@
     private class DnsUdpCheck extends SimpleSocketCheck implements Runnable {
         private static final int TIMEOUT_SEND = 100;
         private static final int TIMEOUT_RECV = 500;
-        private static final int DNS_SERVER_PORT = 53;
         private static final int RR_TYPE_A = 1;
         private static final int RR_TYPE_AAAA = 28;
         private static final int PACKET_BUFSIZE = 512;
@@ -546,7 +544,8 @@
             }
 
             try {
-                setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV, DNS_SERVER_PORT);
+                setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV,
+                        NetworkConstants.DNS_SERVER_PORT);
             } catch (ErrnoException | IOException e) {
                 mMeasurement.recordFailure(e.toString());
                 return;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ed268581b..8a2e71c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -122,22 +122,6 @@
         }
     }
 
-    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
-            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
-    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
-    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
-    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
-    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
-    public static final String EXTRA_CELL_ID = "extra_cellid";
-    public static final String EXTRA_SSID = "extra_ssid";
-    public static final String EXTRA_BSSID = "extra_bssid";
-    /** real time since boot */
-    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
-    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-
-    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
-
     // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
     // The network should be used as a default internet connection.  It was found to be:
     // 1. a functioning network providing internet access, or
@@ -1136,7 +1120,8 @@
             return;
         }
 
-        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
+        Intent latencyBroadcast =
+                new Intent(ConnectivityConstants.ACTION_NETWORK_CONDITIONS_MEASURED);
         switch (mNetworkAgentInfo.networkInfo.getType()) {
             case ConnectivityManager.TYPE_WIFI:
                 WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
@@ -1148,15 +1133,18 @@
                     // not change it here as it would become impossible to tell whether the SSID is
                     // simply being surrounded by quotes due to the API, or whether those quotes
                     // are actually part of the SSID.
-                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
-                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
+                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_SSID,
+                            currentWifiInfo.getSSID());
+                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_BSSID,
+                            currentWifiInfo.getBSSID());
                 } else {
                     if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
                     return;
                 }
                 break;
             case ConnectivityManager.TYPE_MOBILE:
-                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
+                latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_NETWORK_TYPE,
+                        mTelephonyManager.getNetworkType());
                 List<CellInfo> info = mTelephonyManager.getAllCellInfo();
                 if (info == null) return;
                 int numRegisteredCellInfo = 0;
@@ -1170,16 +1158,16 @@
                         }
                         if (cellInfo instanceof CellInfoCdma) {
                             CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
                         } else if (cellInfo instanceof CellInfoGsm) {
                             CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
                         } else if (cellInfo instanceof CellInfoLte) {
                             CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
                         } else if (cellInfo instanceof CellInfoWcdma) {
                             CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
                         } else {
                             if (VDBG) logw("Registered cellinfo is unrecognized");
                             return;
@@ -1190,16 +1178,21 @@
             default:
                 return;
         }
-        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType());
-        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
-        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
+        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CONNECTIVITY_TYPE,
+                mNetworkAgentInfo.networkInfo.getType());
+        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_RECEIVED,
+                responseReceived);
+        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_REQUEST_TIMESTAMP_MS,
+                requestTimestampMs);
 
         if (responseReceived) {
-            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
-            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
+            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_IS_CAPTIVE_PORTAL,
+                    isCaptivePortal);
+            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_TIMESTAMP_MS,
+                    responseTimestampMs);
         }
         mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
-                PERMISSION_ACCESS_NETWORK_CONDITIONS);
+                ConnectivityConstants.PERMISSION_ACCESS_NETWORK_CONDITIONS);
     }
 
     private void logNetworkEvent(int evtype) {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index d56fb1a..3a27fcb3 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -54,12 +54,12 @@
  * @hide
  */
 public class PacManager {
-    public static final String PAC_PACKAGE = "com.android.pacprocessor";
-    public static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
-    public static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
+    private static final String PAC_PACKAGE = "com.android.pacprocessor";
+    private static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
+    private static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
 
-    public static final String PROXY_PACKAGE = "com.android.proxyhandler";
-    public static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
+    private static final String PROXY_PACKAGE = "com.android.proxyhandler";
+    private static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
 
     private static final String TAG = "PacManager";
 
@@ -71,8 +71,6 @@
     private static final int DELAY_LONG = 4;
     private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
-    /** Keep these values up-to-date with ProxyService.java */
-    public static final String KEY_PROXY = "keyProxy";
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
     private volatile Uri mPacUrl = Uri.EMPTY;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index aa174e3..bb46d5e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -164,19 +164,6 @@
     private boolean mLockdown = false;
 
     /**
-     * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is
-     * added to this set but that can be changed by adding allowed or disallowed applications. It
-     * is non-null iff the VPN is connected.
-     *
-     * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN.
-     *
-     * @see VpnService.Builder#addAllowedApplication(String)
-     * @see VpnService.Builder#addDisallowedApplication(String)
-     */
-    @GuardedBy("this")
-    private Set<UidRange> mVpnUsers = null;
-
-    /**
      * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
      * when VPN is not running. For example, during system startup or after a crash.
      * @see mLockdown
@@ -688,7 +675,7 @@
                 agentDisconnect();
                 jniReset(mInterface);
                 mInterface = null;
-                mVpnUsers = null;
+                mNetworkCapabilities.setUids(null);
             }
 
             // Revoke the connection or stop LegacyVpnRunner.
@@ -857,10 +844,14 @@
         NetworkMisc networkMisc = new NetworkMisc();
         networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
 
+        mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid());
+        mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
+                mConfig.allowedApplications, mConfig.disallowedApplications));
         long token = Binder.clearCallingIdentity();
         try {
             mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
-                    mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) {
+                    mNetworkInfo, mNetworkCapabilities, lp,
+                    ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {
                             @Override
                             public void unwanted() {
                                 // We are user controlled, not driven by NetworkRequest.
@@ -869,11 +860,6 @@
         } finally {
             Binder.restoreCallingIdentity(token);
         }
-
-        mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle,
-                mConfig.allowedApplications, mConfig.disallowedApplications);
-        mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
-
         mNetworkInfo.setIsAvailable(true);
         updateState(DetailedState.CONNECTED, "agentConnect");
     }
@@ -953,7 +939,7 @@
         Connection oldConnection = mConnection;
         NetworkAgent oldNetworkAgent = mNetworkAgent;
         mNetworkAgent = null;
-        Set<UidRange> oldUsers = mVpnUsers;
+        Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
 
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -1011,7 +997,7 @@
             // restore old state
             mConfig = oldConfig;
             mConnection = oldConnection;
-            mVpnUsers = oldUsers;
+            mNetworkCapabilities.setUids(oldUsers);
             mNetworkAgent = oldNetworkAgent;
             mInterface = oldInterface;
             throw e;
@@ -1131,10 +1117,12 @@
 
     // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
     // apply to userHandle.
-    private List<UidRange> uidRangesForUser(int userHandle) {
+    static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) {
+        // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
+        // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
         final UidRange userRange = UidRange.createForUser(userHandle);
         final List<UidRange> ranges = new ArrayList<UidRange>();
-        for (UidRange range : mVpnUsers) {
+        for (UidRange range : existingRanges) {
             if (userRange.containsRange(range)) {
                 ranges.add(range);
             }
@@ -1142,30 +1130,18 @@
         return ranges;
     }
 
-    private void removeVpnUserLocked(int userHandle) {
-        if (mVpnUsers == null) {
-            throw new IllegalStateException("VPN is not active");
-        }
-        final List<UidRange> ranges = uidRangesForUser(userHandle);
-        if (mNetworkAgent != null) {
-            mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()]));
-        }
-        mVpnUsers.removeAll(ranges);
-    }
-
     public void onUserAdded(int userHandle) {
         // If the user is restricted tie them to the parent user's VPN
         UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
             synchronized(Vpn.this) {
-                if (mVpnUsers != null) {
+                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+                if (existingRanges != null) {
                     try {
-                        addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications,
+                        addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
                                 mConfig.disallowedApplications);
-                        if (mNetworkAgent != null) {
-                            final List<UidRange> ranges = uidRangesForUser(userHandle);
-                            mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()]));
-                        }
+                        mNetworkCapabilities.setUids(existingRanges);
+                        updateCapabilities();
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to add restricted user to owner", e);
                     }
@@ -1180,9 +1156,14 @@
         UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
             synchronized(Vpn.this) {
-                if (mVpnUsers != null) {
+                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+                if (existingRanges != null) {
                     try {
-                        removeVpnUserLocked(userHandle);
+                        final List<UidRange> removedRanges =
+                            uidRangesForUser(userHandle, existingRanges);
+                        existingRanges.removeAll(removedRanges);
+                        mNetworkCapabilities.setUids(existingRanges);
+                        updateCapabilities();
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to remove restricted user to owner", e);
                     }
@@ -1226,15 +1207,6 @@
     private void setVpnForcedLocked(boolean enforce) {
         final List<String> exemptedPackages =
                 isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
-        setVpnForcedWithExemptionsLocked(enforce, exemptedPackages);
-    }
-
-    /**
-     * @see #setVpnForcedLocked
-     */
-    @GuardedBy("this")
-    private void setVpnForcedWithExemptionsLocked(boolean enforce,
-            @Nullable List<String> exemptedPackages) {
         final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
 
         Set<UidRange> addedRanges = Collections.emptySet();
@@ -1314,7 +1286,7 @@
             synchronized (Vpn.this) {
                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
                     mStatusIntent = null;
-                    mVpnUsers = null;
+                    mNetworkCapabilities.setUids(null);
                     mConfig = null;
                     mInterface = null;
                     if (mConnection != null) {
@@ -1433,12 +1405,7 @@
         if (!isRunningLocked()) {
             return false;
         }
-        for (UidRange uidRange : mVpnUsers) {
-            if (uidRange.contains(uid)) {
-                return true;
-            }
-        }
-        return false;
+        return mNetworkCapabilities.appliesToUid(uid);
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index acbc10b..09bce7f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -28,6 +28,8 @@
 import android.telephony.TelephonyManager;
 import android.net.util.SharedLog;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -49,6 +51,7 @@
 public class TetheringConfiguration {
     private static final String TAG = TetheringConfiguration.class.getSimpleName();
 
+    @VisibleForTesting
     public static final int DUN_NOT_REQUIRED = 0;
     public static final int DUN_REQUIRED = 1;
     public static final int DUN_UNSPECIFIED = 2;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 370e569..d30b13c 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -16,18 +16,22 @@
 
 package com.android.server.fingerprint;
 
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
 import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintDialog;
 import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
+
 /**
  * A class to keep track of the authentication state for a given client.
  */
@@ -41,11 +45,99 @@
     public static final int LOCKOUT_TIMED = 1;
     public static final int LOCKOUT_PERMANENT = 2;
 
+    // Callback mechanism received from the client
+    // (FingerprintDialog -> FingerprintManager -> FingerprintService -> AuthenticationClient)
+    private IFingerprintDialogReceiver mDialogReceiverFromClient;
+    private Bundle mBundle;
+    private IStatusBarService mStatusBarService;
+    private boolean mInLockout;
+    private final FingerprintManager mFingerprintManager;
+    protected boolean mDialogDismissed;
+
+    // Receives events from SystemUI
+    protected IFingerprintDialogReceiver mDialogReceiver = new IFingerprintDialogReceiver.Stub() {
+        @Override // binder call
+        public void onDialogDismissed(int reason) {
+            if (mBundle != null && mDialogReceiverFromClient != null) {
+                try {
+                    mDialogReceiverFromClient.onDialogDismissed(reason);
+                    if (reason == FingerprintDialog.DISMISSED_REASON_USER_CANCEL) {
+                        onError(FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED,
+                                0 /* vendorCode */);
+                    }
+                    mDialogDismissed = true;
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to notify dialog dismissed", e);
+                }
+                stop(true /* initiatedByClient */);
+            }
+        }
+    };
+
     public AuthenticationClient(Context context, long halDeviceId, IBinder token,
             IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
-            boolean restricted, String owner) {
+            boolean restricted, String owner, Bundle bundle,
+            IFingerprintDialogReceiver dialogReceiver, IStatusBarService statusBarService) {
         super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
         mOpId = opId;
+        mBundle = bundle;
+        mDialogReceiverFromClient = dialogReceiver;
+        mStatusBarService = statusBarService;
+        mFingerprintManager = (FingerprintManager) getContext()
+                .getSystemService(Context.FINGERPRINT_SERVICE);
+    }
+
+    @Override
+    public void binderDied() {
+        super.binderDied();
+        // When the binder dies, we should stop the client. This probably belongs in
+        // ClientMonitor's binderDied(), but testing all the cases would be tricky.
+        // AuthenticationClient is the most user-visible case.
+        stop(false /* initiatedByClient */);
+    }
+
+    @Override
+    public boolean onAcquired(int acquiredInfo, int vendorCode) {
+        // If the dialog is showing, the client doesn't need to receive onAcquired messages.
+        if (mBundle != null) {
+            try {
+                if (acquiredInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+                    mStatusBarService.onFingerprintHelp(
+                            mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
+                }
+                return false; // acquisition continues
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception when sending acquired message", e);
+                return true; // client failed
+            } finally {
+                // Good scans will keep the device awake
+                if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+                    notifyUserActivity();
+                }
+            }
+        } else {
+            return super.onAcquired(acquiredInfo, vendorCode);
+        }
+    }
+
+    @Override
+    public boolean onError(int error, int vendorCode) {
+        if (mDialogDismissed) {
+            // If user cancels authentication, the application has already received the
+            // FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED message from onDialogDismissed()
+            // and stopped the fingerprint hardware, so there is no need to send a
+            // FingerprintManager.FINGERPRINT_ERROR_CANCELED message.
+            return true;
+        }
+        if (mBundle != null) {
+            try {
+                mStatusBarService.onFingerprintError(
+                        mFingerprintManager.getErrorString(error, vendorCode));
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception when sending error", e);
+            }
+        }
+        return super.onError(error, vendorCode);
     }
 
     @Override
@@ -53,6 +145,20 @@
         boolean result = false;
         boolean authenticated = fingerId != 0;
 
+        // If the fingerprint dialog is showing, notify authentication succeeded
+        if (mBundle != null) {
+            try {
+                if (authenticated) {
+                    mStatusBarService.onFingerprintAuthenticated();
+                } else {
+                    mStatusBarService.onFingerprintHelp(getContext().getResources().getString(
+                            com.android.internal.R.string.fingerprint_not_recognized));
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to notify Authenticated:", e);
+            }
+        }
+
         IFingerprintServiceReceiver receiver = getReceiver();
         if (receiver != null) {
             try {
@@ -85,13 +191,24 @@
             int lockoutMode =  handleFailedAttempt();
             if (lockoutMode != LOCKOUT_NONE) {
                 try {
+                    mInLockout = true;
                     Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
                             lockoutMode + ")");
                     stop(false);
                     int errorCode = lockoutMode == LOCKOUT_TIMED ?
                             FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
                             FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+
+                    // TODO: if the dialog is showing, this error should be delayed. On a similar
+                    // note, AuthenticationClient should override onError and delay all other errors
+                    // as well, if the dialog is showing
                     receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
+
+                    // Send the lockout message to the system dialog
+                    if (mBundle != null) {
+                        mStatusBarService.onFingerprintError(
+                                mFingerprintManager.getErrorString(errorCode, 0 /* vendorCode */));
+                    }
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed to notify lockout:", e);
                 }
@@ -126,6 +243,15 @@
                 return result;
             }
             if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
+
+            // If authenticating with system dialog, show the dialog
+            if (mBundle != null) {
+                try {
+                    mStatusBarService.showFingerprintDialog(mBundle, mDialogReceiver);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to show fingerprint dialog", e);
+                }
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "startAuthentication failed", e);
             return ERROR_ESRCH;
@@ -139,6 +265,7 @@
             Slog.w(TAG, "stopAuthentication: already cancelled!");
             return 0;
         }
+
         IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopAuthentication: no fingerprint HAL!");
@@ -154,6 +281,18 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "stopAuthentication failed", e);
             return ERROR_ESRCH;
+        } finally {
+            // If the user already cancelled authentication (via some interaction with the
+            // dialog, we do not need to hide it since it's already hidden.
+            // If the device is in lockout, don't hide the dialog - it will automatically hide
+            // after FingerprintDialog.HIDE_DIALOG_DELAY
+            if (mBundle != null && !mDialogDismissed && !mInLockout) {
+                try {
+                    mStatusBarService.hideFingerprintDialog();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to hide fingerprint dialog", e);
+                }
+            }
         }
         mAlreadyCancelled = true;
         return 0; // success
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index d0d951b..3e1958d 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -40,6 +40,7 @@
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.hardware.fingerprint.IFingerprintService;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -55,6 +56,7 @@
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
 import android.os.SELinux;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -66,6 +68,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
@@ -131,6 +134,7 @@
     private SparseIntArray mFailedAttempts;
     @GuardedBy("this")
     private IBiometricsFingerprint mDaemon;
+    private IStatusBarService mStatusBarService;
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final UserManager mUserManager;
@@ -222,6 +226,8 @@
         mUserManager = UserManager.get(mContext);
         mTimedLockoutCleared = new SparseBooleanArray();
         mFailedAttempts = new SparseIntArray();
+        mStatusBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
     @Override
@@ -808,13 +814,14 @@
 
     private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
                 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
-                String opPackageName) {
+                String opPackageName, Bundle bundle, IFingerprintDialogReceiver dialogReceiver) {
         updateActiveGroup(groupId, opPackageName);
 
         if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
 
         AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
-                receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
+                receiver, mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
+                dialogReceiver, mStatusBarService) {
             @Override
             public int handleFailedAttempt() {
                 final int currentUser = ActivityManager.getCurrentUser();
@@ -1037,7 +1044,7 @@
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
             checkPermission(MANAGE_FINGERPRINT);
-            final int limit =  mContext.getResources().getInteger(
+            final int limit = mContext.getResources().getInteger(
                     com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
 
             final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
@@ -1085,7 +1092,8 @@
         @Override // Binder call
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
-                final String opPackageName) {
+                final String opPackageName, final Bundle bundle,
+                final IFingerprintDialogReceiver dialogReceiver) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
@@ -1113,7 +1121,7 @@
                     mPerformanceStats = stats;
 
                     startAuthentication(token, opId, callingUserId, groupId, receiver,
-                            flags, restricted, opPackageName);
+                            flags, restricted, opPackageName, bundle, dialogReceiver);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index fa5fdf5..5da470e 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -21,6 +21,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
 import android.app.job.IJobScheduler;
@@ -73,8 +74,10 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.DeviceIdleController;
 import com.android.server.FgThread;
+import com.android.server.ForceAppStandbyTracker;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
@@ -102,6 +105,7 @@
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Responsible for taking jobs representing work to be performed by a client app, and determining
@@ -175,8 +179,10 @@
     final JobSchedulerStub mJobSchedulerStub;
 
     PackageManagerInternal mLocalPM;
+    ActivityManagerInternal mActivityManagerInternal;
     IBatteryStats mBatteryStats;
     DeviceIdleController.LocalService mLocalDeviceIdleController;
+    final ForceAppStandbyTracker mForceAppStandbyTracker;
 
     /**
      * Set to true once we are allowed to run third party apps.
@@ -778,6 +784,22 @@
         mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
     }
 
+    /**
+     * Return whether an UID is in the foreground or not.
+     */
+    private boolean isUidInForeground(int uid) {
+        synchronized (mLock) {
+            if (mUidPriorityOverride.get(uid, 0) > 0) {
+                return true;
+            }
+        }
+        // Note UID observer may not be called in time, so we always check with the AM.
+        return mActivityManagerInternal.getUidProcessState(uid)
+                <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+    }
+
+    private final Predicate<Integer> mIsUidInForegroundPredicate = this::isUidInForeground;
+
     public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
             int userId, String tag) {
         try {
@@ -797,12 +819,25 @@
                 // Fast path: we are adding work to an existing job, and the JobInfo is not
                 // changing.  We can just directly enqueue this work in to the job.
                 if (toCancel.getJob().equals(job)) {
+
                     toCancel.enqueueWorkLocked(ActivityManager.getService(), work);
+
+                    // If any of work item is enqueued when the source is in the foreground,
+                    // exempt the entire job.
+                    toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+
                     return JobScheduler.RESULT_SUCCESS;
                 }
             }
 
             JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
+
+            // Give exemption if the source is in the foreground just now.
+            // Note if it's a sync job, this method is called on the handler so it's not exactly
+            // the state when requestSync() was called, but that should be fine because of the
+            // 1 minute foreground grace period.
+            jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+
             if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
             // Jobs on behalf of others don't apply to the per-app job cap
             if (ENFORCE_MAX_JOBS && packageName == null) {
@@ -1047,6 +1082,8 @@
         super(context);
 
         mLocalPM = LocalServices.getService(PackageManagerInternal.class);
+        mActivityManagerInternal = Preconditions.checkNotNull(
+                LocalServices.getService(ActivityManagerInternal.class));
 
         mHandler = new JobHandler(context.getMainLooper());
         mConstants = new Constants(mHandler);
@@ -1078,6 +1115,8 @@
         mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
         mControllers.add(mDeviceIdleJobsController);
 
+        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
+
         // If the job store determined that it can't yet reschedule persisted jobs,
         // we need to start watching the clock.
         if (!mJobs.jobTimesInflatedValid()) {
@@ -1137,6 +1176,9 @@
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
             mConstants.start(getContext().getContentResolver());
+
+            mForceAppStandbyTracker.start();
+
             // Register br for package removals and user removals.
             final IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 36cacd7a..6da783c 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -72,6 +72,9 @@
  *      This is important b/c {@link com.android.server.job.JobStore.WriteJobsMapToDiskRunnable}
  *      and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
  *      object.
+ *
+ * Test:
+ * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
  */
 public final class JobStore {
     private static final String TAG = "JobStore";
@@ -427,6 +430,9 @@
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
             out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
             out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
+            if (jobStatus.getInternalFlags() != 0) {
+                out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags()));
+            }
 
             out.attribute(null, "lastSuccessfulRunTime",
                     String.valueOf(jobStatus.getLastSuccessfulRunTime()));
@@ -689,6 +695,7 @@
             int uid, sourceUserId;
             long lastSuccessfulRunTime;
             long lastFailedRunTime;
+            int internalFlags = 0;
 
             // Read out job identifier attributes and priority.
             try {
@@ -704,6 +711,10 @@
                 if (val != null) {
                     jobBuilder.setFlags(Integer.parseInt(val));
                 }
+                val = parser.getAttributeValue(null, "internalFlags");
+                if (val != null) {
+                    internalFlags = Integer.parseInt(val);
+                }
                 val = parser.getAttributeValue(null, "sourceUserId");
                 sourceUserId = val == null ? -1 : Integer.parseInt(val);
 
@@ -718,7 +729,6 @@
             }
 
             String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
-
             final String sourceTag = parser.getAttributeValue(null, "sourceTag");
 
             int eventType;
@@ -857,7 +867,7 @@
                     appBucket, currentHeartbeat, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second,
                     lastSuccessfulRunTime, lastFailedRunTime,
-                    (rtcIsGood) ? null : rtcRuntimes);
+                    (rtcIsGood) ? null : rtcRuntimes, internalFlags);
             return js;
         }
 
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 1d053a5..2e4567a 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -197,7 +197,9 @@
         final int uid = jobStatus.getSourceUid();
         final String packageName = jobStatus.getSourcePackageName();
 
-        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName);
+        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName,
+                (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
+                        != 0);
 
         return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
     }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 611f4ec..d9a5ff6 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -46,6 +46,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.function.Predicate;
 
 /**
  * Uniquely identifies a job internally.
@@ -184,6 +185,21 @@
      */
     private int trackingControllers;
 
+    /**
+     * Flag for {@link #mInternalFlags}: this job was scheduled when the app that owns the job
+     * service (not necessarily the caller) was in the foreground and the job has no time
+     * constraints, which makes it exempted from the battery saver job restriction.
+     *
+     * @hide
+     */
+    public static final int INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION = 1 << 0;
+
+    /**
+     * Versatile, persistable flags for a job that's updated within the system server,
+     * as opposed to {@link JobInfo#flags} that's set by callers.
+     */
+    private int mInternalFlags;
+
     // These are filled in by controllers when preparing for execution.
     public ArraySet<Uri> changedUris;
     public ArraySet<String> changedAuthorities;
@@ -248,7 +264,7 @@
     private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
             int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
-            long lastSuccessfulRunTime, long lastFailedRunTime) {
+            long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
         this.job = job;
         this.callingUid = callingUid;
         this.targetSdkVersion = targetSdkVersion;
@@ -304,6 +320,8 @@
         mLastSuccessfulRunTime = lastSuccessfulRunTime;
         mLastFailedRunTime = lastFailedRunTime;
 
+        mInternalFlags = internalFlags;
+
         updateEstimatedNetworkBytesLocked();
     }
 
@@ -315,7 +333,8 @@
                 jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
-                jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
+                jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
+                jobStatus.getInternalFlags());
         mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
         if (jobStatus.mPersistedUtcTimes != null) {
             if (DEBUG) {
@@ -336,12 +355,13 @@
             int standbyBucket, long baseHeartbeat, String sourceTag,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
             long lastSuccessfulRunTime, long lastFailedRunTime,
-            Pair<Long, Long> persistedExecutionTimesUTC) {
+            Pair<Long, Long> persistedExecutionTimesUTC,
+            int innerFlags) {
         this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
                 standbyBucket, baseHeartbeat,
                 sourceTag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
-                lastSuccessfulRunTime, lastFailedRunTime);
+                lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
 
         // Only during initial inflation do we record the UTC-timebase execution bounds
         // read from the persistent store.  If we ever have to recreate the JobStatus on
@@ -365,7 +385,7 @@
                 rescheduling.getStandbyBucket(), newBaseHeartbeat,
                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis,
-                lastSuccessfulRunTime, lastFailedRunTime);
+                lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
     }
 
     /**
@@ -395,10 +415,12 @@
                 sourceUserId, elapsedNow);
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
         long currentHeartbeat = js != null ? js.currentHeartbeat() : 0;
+
         return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
                 standbyBucket, currentHeartbeat, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
-                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
+                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
+                /*innerFlags=*/ 0);
     }
 
     public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
@@ -623,6 +645,28 @@
         return job.getFlags();
     }
 
+    public int getInternalFlags() {
+        return mInternalFlags;
+    }
+
+    public void addInternalFlags(int flags) {
+        mInternalFlags |= flags;
+    }
+
+    public void maybeAddForegroundExemption(Predicate<Integer> uidForegroundChecker) {
+        // Jobs with time constraints shouldn't be exempted.
+        if (job.hasEarlyConstraint() || job.hasLateConstraint()) {
+            return;
+        }
+        // Already exempted, skip the foreground check.
+        if ((mInternalFlags & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
+            return;
+        }
+        if (uidForegroundChecker.test(getSourceUid())) {
+            addInternalFlags(INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION);
+        }
+    }
+
     private void updateEstimatedNetworkBytesLocked() {
         totalNetworkBytes = computeEstimatedNetworkBytesLocked();
     }
@@ -1170,6 +1214,15 @@
                 pw.print(prefix); pw.print("  Flags: ");
                 pw.println(Integer.toHexString(job.getFlags()));
             }
+            if (getInternalFlags() != 0) {
+                pw.print(prefix); pw.print("  Internal flags: ");
+                pw.print(Integer.toHexString(getInternalFlags()));
+
+                if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) {
+                    pw.print(" HAS_FOREGROUND_EXEMPTION");
+                }
+                pw.println();
+            }
             pw.print(prefix); pw.print("  Requires: charging=");
             pw.print(job.isRequireCharging()); pw.print(" batteryNotLow=");
             pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle=");
@@ -1325,6 +1378,7 @@
         proto.write(JobStatusDumpProto.SOURCE_UID, getSourceUid());
         proto.write(JobStatusDumpProto.SOURCE_USER_ID, getSourceUserId());
         proto.write(JobStatusDumpProto.SOURCE_PACKAGE_NAME, getSourcePackageName());
+        proto.write(JobStatusDumpProto.INTERNAL_FLAGS, getInternalFlags());
 
         if (full) {
             final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a6753ab..31c20cb 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -79,9 +79,9 @@
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.security.keystore.UserNotAuthenticatedException;
-import android.security.keystore.recovery.KeychainProtectionParams;
+import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.WrappedApplicationKey;
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
@@ -1598,8 +1598,10 @@
                 userId, progressCallback);
         // The user employs synthetic password based credential.
         if (response != null) {
-            mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
-                    userId);
+            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+                mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
+                        userId);
+            }
             return response;
         }
 
@@ -1980,7 +1982,7 @@
     }
 
     @Override
-    public KeychainSnapshot getRecoveryData(@NonNull byte[] account) throws RemoteException {
+    public KeyChainSnapshot getRecoveryData(@NonNull byte[] account) throws RemoteException {
         return mRecoverableKeyStoreManager.getRecoveryData(account);
     }
 
@@ -2009,7 +2011,7 @@
     }
 
     @Override
-    public void setRecoverySecretTypes(@NonNull @KeychainProtectionParams.UserSecretType
+    public void setRecoverySecretTypes(@NonNull @KeyChainProtectionParams.UserSecretType
             int[] secretTypes) throws RemoteException {
         mRecoverableKeyStoreManager.setRecoverySecretTypes(secretTypes);
     }
@@ -2026,7 +2028,7 @@
     }
 
     @Override
-    public void recoverySecretAvailable(@NonNull KeychainProtectionParams recoverySecret)
+    public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
             throws RemoteException {
         mRecoverableKeyStoreManager.recoverySecretAvailable(recoverySecret);
     }
@@ -2034,7 +2036,7 @@
     @Override
     public byte[] startRecoverySession(@NonNull String sessionId,
             @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams,
-            @NonNull byte[] vaultChallenge, @NonNull List<KeychainProtectionParams> secrets)
+            @NonNull byte[] vaultChallenge, @NonNull List<KeyChainProtectionParams> secrets)
             throws RemoteException {
         return mRecoverableKeyStoreManager.startRecoverySession(sessionId, verifierPublicKey,
                 vaultParams, vaultChallenge, secrets);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 70d6072..f62e8a9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -627,7 +627,12 @@
         if (persistentDataBlock == null) {
             return PersistentData.NONE;
         }
-        return PersistentData.fromBytes(persistentDataBlock.getFrpCredentialHandle());
+        try {
+            return PersistentData.fromBytes(persistentDataBlock.getFrpCredentialHandle());
+        } catch (IllegalStateException e) {
+            Slog.e(TAG, "Error reading persistent data block", e);
+            return PersistentData.NONE;
+        }
     }
 
     public static class PersistentData {
@@ -670,11 +675,11 @@
                     return new PersistentData(type, userId, qualityForUi, payload);
                 } else {
                     Slog.wtf(TAG, "Unknown PersistentData version code: " + version);
-                    return null;
+                    return NONE;
                 }
             } catch (IOException e) {
                 Slog.wtf(TAG, "Could not parse PersistentData", e);
-                return null;
+                return NONE;
             }
         }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 6fcbcbc..e1e769c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -16,13 +16,13 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN;
+import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
 
 import android.annotation.Nullable;
 import android.content.Context;
 import android.security.keystore.recovery.KeyDerivationParams;
-import android.security.keystore.recovery.KeychainProtectionParams;
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.util.Log;
 
@@ -255,12 +255,12 @@
         }
         // TODO: store raw data in RecoveryServiceMetadataEntry and generate Parcelables later
         // TODO: use Builder.
-        KeychainProtectionParams metadata = new KeychainProtectionParams(
+        KeyChainProtectionParams metadata = new KeyChainProtectionParams(
                 /*userSecretType=*/ TYPE_LOCKSCREEN,
                 /*lockScreenUiFormat=*/ getUiFormat(mCredentialType, mCredential),
                 /*keyDerivationParams=*/ KeyDerivationParams.createSha256Params(salt),
                 /*secret=*/ new byte[0]);
-        ArrayList<KeychainProtectionParams> metadataList = new ArrayList<>();
+        ArrayList<KeyChainProtectionParams> metadataList = new ArrayList<>();
         metadataList.add(metadata);
 
         int snapshotVersion = incrementSnapshotVersion(recoveryAgentUid);
@@ -268,13 +268,13 @@
         // If application keys are not updated, snapshot will not be created on next unlock.
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
 
-        mRecoverySnapshotStorage.put(recoveryAgentUid, new KeychainSnapshot.Builder()
+        mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyChainSnapshot.Builder()
                 .setSnapshotVersion(snapshotVersion)
                 .setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS)
                 .setCounterId(counterId)
                 .setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey))
                 .setServerParams(vaultHandle)
-                .setKeychainProtectionParams(metadataList)
+                .setKeyChainProtectionParams(metadataList)
                 .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
                 .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey)
                 .build());
@@ -317,7 +317,7 @@
      */
     private boolean shoudCreateSnapshot(int recoveryAgentUid) {
         int[] types = mRecoverableKeyStoreDb.getRecoverySecretTypes(mUserId, recoveryAgentUid);
-        if (!ArrayUtils.contains(types, KeychainProtectionParams.TYPE_LOCKSCREEN)) {
+        if (!ArrayUtils.contains(types, KeyChainProtectionParams.TYPE_LOCKSCREEN)) {
             // Only lockscreen type is supported.
             // We will need to pass extra argument to KeySyncTask to support custom pass phrase.
             return false;
@@ -340,14 +340,14 @@
      * @return The format - either pattern, pin, or password.
      */
     @VisibleForTesting
-    @KeychainProtectionParams.LockScreenUiFormat static int getUiFormat(
+    @KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(
             int credentialType, String credential) {
         if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
-            return KeychainProtectionParams.TYPE_PATTERN;
+            return KeyChainProtectionParams.UI_FORMAT_PATTERN;
         } else if (isPin(credential)) {
-            return KeychainProtectionParams.TYPE_PIN;
+            return KeyChainProtectionParams.UI_FORMAT_PIN;
         } else {
-            return KeychainProtectionParams.TYPE_PASSWORD;
+            return KeyChainProtectionParams.UI_FORMAT_PASSWORD;
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index ac3cef2..b6c3c66 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -33,8 +33,8 @@
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 
-import android.security.keystore.recovery.KeychainProtectionParams;
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryController;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.util.Log;
@@ -170,11 +170,11 @@
      * @hide
      */
     public @NonNull
-    KeychainSnapshot getRecoveryData(@NonNull byte[] account)
+    KeyChainSnapshot getRecoveryData(@NonNull byte[] account)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int uid = Binder.getCallingUid();
-        KeychainSnapshot snapshot = mSnapshotStorage.get(uid);
+        KeyChainSnapshot snapshot = mSnapshotStorage.get(uid);
         if (snapshot == null) {
             throw new ServiceSpecificException(ERROR_NO_SNAPSHOT_PENDING);
         }
@@ -256,7 +256,7 @@
      * @hide
      */
     public void setRecoverySecretTypes(
-            @NonNull @KeychainProtectionParams.UserSecretType int[] secretTypes)
+            @NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
@@ -291,9 +291,9 @@
     }
 
     public void recoverySecretAvailable(
-            @NonNull KeychainProtectionParams recoverySecret) throws RemoteException {
+            @NonNull KeyChainProtectionParams recoverySecret) throws RemoteException {
         int uid = Binder.getCallingUid();
-        if (recoverySecret.getLockScreenUiFormat() == KeychainProtectionParams.TYPE_LOCKSCREEN) {
+        if (recoverySecret.getLockScreenUiFormat() == KeyChainProtectionParams.TYPE_LOCKSCREEN) {
             throw new SecurityException(
                     "Caller " + uid + " is not allowed to set lock screen secret");
         }
@@ -319,14 +319,14 @@
             @NonNull byte[] verifierPublicKey,
             @NonNull byte[] vaultParams,
             @NonNull byte[] vaultChallenge,
-            @NonNull List<KeychainProtectionParams> secrets)
+            @NonNull List<KeyChainProtectionParams> secrets)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int uid = Binder.getCallingUid();
 
         if (secrets.size() != 1) {
             throw new UnsupportedOperationException(
-                    "Only a single KeychainProtectionParams is supported");
+                    "Only a single KeyChainProtectionParams is supported");
         }
 
         PublicKey publicKey;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index 2b1416e..f2e71b3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -404,7 +404,7 @@
     /**
      * Updates the list of user secret types used for end-to-end encryption.
      * If no secret types are set, recovery snapshot will not be created.
-     * See {@code KeychainProtectionParams}
+     * See {@code KeyChainProtectionParams}
      *
      * @param userId The userId of the profile the application is running under.
      * @param uid The uid of the application.
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
index 7cde7ab..3f93cc6 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
@@ -17,7 +17,7 @@
 package com.android.server.locksettings.recoverablekeystore.storage;
 
 import android.annotation.Nullable;
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -34,12 +34,12 @@
  */
 public class RecoverySnapshotStorage {
     @GuardedBy("this")
-    private final SparseArray<KeychainSnapshot> mSnapshotByUid = new SparseArray<>();
+    private final SparseArray<KeyChainSnapshot> mSnapshotByUid = new SparseArray<>();
 
     /**
      * Sets the latest {@code snapshot} for the recovery agent {@code uid}.
      */
-    public synchronized void put(int uid, KeychainSnapshot snapshot) {
+    public synchronized void put(int uid, KeyChainSnapshot snapshot) {
         mSnapshotByUid.put(uid, snapshot);
     }
 
@@ -47,7 +47,7 @@
      * Returns the latest snapshot for the recovery agent {@code uid}, or null if none exists.
      */
     @Nullable
-    public synchronized KeychainSnapshot get(int uid) {
+    public synchronized KeyChainSnapshot get(int uid) {
         return mSnapshotByUid.get(uid);
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index b25eaa7..c59c5f6 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -81,7 +81,7 @@
     public void onSessionDestroyed() {
         if (mController != null) {
             mControllerCallback.destroy();
-            mController.release();
+            mController.close();
             mController = null;
         }
         mSessionPid = 0;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 6812778..c9c7d04 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -38,6 +38,7 @@
 import android.media.IAudioService;
 import android.media.IMediaSession2;
 import android.media.IRemoteVolumeController;
+import android.media.MediaLibraryService2;
 import android.media.MediaSessionService2;
 import android.media.SessionToken;
 import android.media.session.IActiveSessionsListener;
@@ -445,9 +446,18 @@
         }
 
         // TODO(jaewan): Query per users.
-        List<ResolveInfo> services = getContext().getPackageManager().queryIntentServices(
-                new Intent(MediaSessionService2.SERVICE_INTERFACE),
-                PackageManager.GET_META_DATA);
+        List<ResolveInfo> services = new ArrayList<>();
+        // If multiple actions are declared for a service, browser gets higher priority.
+        List<ResolveInfo> libraryServices = getContext().getPackageManager().queryIntentServices(
+                new Intent(MediaLibraryService2.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+        if (libraryServices != null) {
+            services.addAll(libraryServices);
+        }
+        List<ResolveInfo> sessionServices = getContext().getPackageManager().queryIntentServices(
+                new Intent(MediaSessionService2.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+        if (sessionServices != null) {
+            services.addAll(sessionServices);
+        }
         synchronized (mLock) {
             mSessions.clear();
             if (services == null) {
@@ -470,10 +480,11 @@
                             + " the same ID=" + id + ". Ignoring "
                             + serviceInfo.packageName + "/" + serviceInfo.name);
                 } else {
+                    int type = (libraryServices.contains(services.get(i)))
+                            ? SessionToken.TYPE_LIBRARY_SERVICE : SessionToken.TYPE_SESSION_SERVICE;
                     MediaSessionService2Record record =
                             new MediaSessionService2Record(getContext(), mSessionDestroyedListener,
-                                    SessionToken.TYPE_SESSION_SERVICE,
-                                    serviceInfo.packageName, serviceInfo.name, id);
+                                    type, serviceInfo.packageName, serviceInfo.name, id);
                     mSessions.add(record);
                 }
             }
diff --git a/services/core/java/com/android/server/media/MediaUpdateService.java b/services/core/java/com/android/server/media/MediaUpdateService.java
index 016d062..6921ccd 100644
--- a/services/core/java/com/android/server/media/MediaUpdateService.java
+++ b/services/core/java/com/android/server/media/MediaUpdateService.java
@@ -53,13 +53,10 @@
 
     @Override
     public void onStart() {
-        // TODO: Uncomment below once sepolicy change is landed.
-        /*
         if ("userdebug".equals(android.os.Build.TYPE) || "eng".equals(android.os.Build.TYPE)) {
             connect();
             registerBroadcastReceiver();
         }
-        */
     }
 
     private void connect() {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 78fd4b4..bfc150e 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -887,17 +887,21 @@
 
     @Override
     public long getUidStats(int uid, int type) {
-        return nativeGetUidStat(uid, type);
+        return nativeGetUidStat(uid, type, checkBpfStatsEnable());
     }
 
     @Override
     public long getIfaceStats(String iface, int type) {
-        return nativeGetIfaceStat(iface, type);
+        return nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
     }
 
     @Override
     public long getTotalStats(int type) {
-        return nativeGetTotalStat(type);
+        return nativeGetTotalStat(type, checkBpfStatsEnable());
+    }
+
+    private boolean checkBpfStatsEnable() {
+        return new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
     }
 
     /**
@@ -1668,7 +1672,7 @@
     private static int TYPE_TCP_RX_PACKETS;
     private static int TYPE_TCP_TX_PACKETS;
 
-    private static native long nativeGetTotalStat(int type);
-    private static native long nativeGetIfaceStat(String iface, int type);
-    private static native long nativeGetUidStat(int uid, int type);
+    private static native long nativeGetTotalStat(int type, boolean useBpfStats);
+    private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats);
+    private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats);
 }
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index ee0049b..3b6d59e 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -186,6 +186,10 @@
                     System.currentTimeMillis());
             final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
                     mDbHelper.getAggregatedRecords();
+            if (aggregatedResult == null) {
+                Slog.i(TAG, "Cannot get result from database");
+                return;
+            }
             // Get all digests for watchlist report, it should include all installed
             // application digests and previously recorded app digests.
             final List<String> digestsForReport = getAllDigestsForReport(aggregatedResult);
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index 9559685..c73b0cf 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.net.watchlist;
 
+import android.annotation.Nullable;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -79,7 +80,7 @@
         final Set<String> appDigestList;
 
         // The c&c domain or ip visited before.
-        final String cncDomainVisited;
+        @Nullable final String cncDomainVisited;
 
         // A list of app digests and c&c domain visited.
         final HashMap<String, String> appDigestCNCList;
@@ -155,7 +156,7 @@
                     WhiteListReportContract.TABLE, DIGEST_DOMAIN_PROJECTION, selectStatement,
                     new String[]{"" + twoDaysBefore, "" + yesterday}, null, null,
                     null, null);
-            if (c == null || c.getCount() == 0) {
+            if (c == null) {
                 return null;
             }
             final HashSet<String> appDigestList = new HashSet<>();
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 42093e8..502760a 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -254,13 +254,11 @@
 
         for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
             if (filter != null && !filter.matches(cmpt)) continue;
-
             cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
         }
 
         for (ManagedServiceInfo info : mServices) {
             if (filter != null && !filter.matches(info.component)) continue;
-
             info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
         }
 
@@ -1145,13 +1143,11 @@
 
         public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
             final long token = proto.start(fieldId);
-
             component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
             proto.write(ManagedServiceInfoProto.USER_ID, userid);
             proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
             proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
             proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
-
             proto.end(token);
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 39b7c7c..4c9da89 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -1881,6 +1882,18 @@
                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
             }
+
+            try {
+                getContext().sendBroadcastAsUser(
+                        new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
+                                .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
+                                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                                .setPackage(pkg),
+                        UserHandle.of(UserHandle.getUserId(uid)), null);
+            } catch (SecurityException e) {
+                Slog.w(TAG, "Can't notify app about app block change", e);
+            }
+
             savePolicyFile();
         }
 
@@ -3382,36 +3395,28 @@
     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
         final ProtoOutputStream proto = new ProtoOutputStream(fd);
         synchronized (mNotificationLock) {
-            long records = proto.start(NotificationServiceDumpProto.RECORDS);
             int N = mNotificationList.size();
-            if (N > 0) {
-                for (int i = 0; i < N; i++) {
-                    final NotificationRecord nr = mNotificationList.get(i);
-                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
-                    nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.POSTED);
-                }
+            for (int i = 0; i < N; i++) {
+                final NotificationRecord nr = mNotificationList.get(i);
+                if (filter.filtered && !filter.matches(nr.sbn)) continue;
+                nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
+                        NotificationRecordProto.POSTED);
             }
             N = mEnqueuedNotifications.size();
-            if (N > 0) {
-                for (int i = 0; i < N; i++) {
-                    final NotificationRecord nr = mEnqueuedNotifications.get(i);
-                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
-                    nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.ENQUEUED);
-                }
+            for (int i = 0; i < N; i++) {
+                final NotificationRecord nr = mEnqueuedNotifications.get(i);
+                if (filter.filtered && !filter.matches(nr.sbn)) continue;
+                nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
+                        NotificationRecordProto.ENQUEUED);
             }
             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
             N = snoozed.size();
-            if (N > 0) {
-                for (int i = 0; i < N; i++) {
-                    final NotificationRecord nr = snoozed.get(i);
-                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
-                    nr.dump(proto, filter.redact);
-                    proto.write(NotificationRecordProto.STATE, NotificationRecordProto.SNOOZED);
-                }
+            for (int i = 0; i < N; i++) {
+                final NotificationRecord nr = snoozed.get(i);
+                if (filter.filtered && !filter.matches(nr.sbn)) continue;
+                nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
+                        NotificationRecordProto.SNOOZED);
             }
-            proto.end(records);
 
             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
             mZenModeHelper.dump(proto);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index faa300f2..23b9743 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -361,8 +361,11 @@
     /** @deprecated Use {@link #getUser()} instead. */
     public int getUserId() { return sbn.getUserId(); }
 
-    void dump(ProtoOutputStream proto, boolean redact) {
+    void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
+        final long token = proto.start(fieldId);
+
         proto.write(NotificationRecordProto.KEY, sbn.getKey());
+        proto.write(NotificationRecordProto.STATE, state);
         if (getChannel() != null) {
             proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
         }
@@ -375,8 +378,10 @@
             proto.write(NotificationRecordProto.SOUND, getSound().toString());
         }
         if (getAudioAttributes() != null) {
-            proto.write(NotificationRecordProto.SOUND_USAGE, getAudioAttributes().getUsage());
+            getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
         }
+
+        proto.end(token);
     }
 
     String formatRemoteViews(RemoteViews rv) {
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index c0dccb5..b0e3820 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -973,16 +973,11 @@
                 proto.write(RecordProto.VISIBILITY, r.visibility);
                 proto.write(RecordProto.SHOW_BADGE, r.showBadge);
 
-                long token;
                 for (NotificationChannel channel : r.channels.values()) {
-                    token = proto.start(RecordProto.CHANNELS);
-                    channel.toProto(proto);
-                    proto.end(token);
+                    channel.writeToProto(proto, RecordProto.CHANNELS);
                 }
                 for (NotificationChannelGroup group : r.groups.values()) {
-                    token = proto.start(RecordProto.CHANNEL_GROUPS);
-                    group.toProto(proto);
-                    proto.end(token);
+                    group.writeToProto(proto, RecordProto.CHANNEL_GROUPS);
                 }
 
                 proto.end(fToken);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 8f672b5..932e4f9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -565,7 +565,7 @@
                     proto.write(ZenModeProto.ENABLED_ACTIVE_CONDITIONS, rule.toString());
                 }
             }
-            mConfig.toNotificationPolicy().toProto(proto, ZenModeProto.POLICY);
+            mConfig.toNotificationPolicy().writeToProto(proto, ZenModeProto.POLICY);
             proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index da1bdc7..78200f2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,6 +24,8 @@
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
+import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -108,6 +110,8 @@
 import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
 import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.signingDetailsHasCertificate;
+import static com.android.server.pm.PackageManagerServiceUtils.signingDetailsHasSha256Certificate;
 import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
@@ -5457,6 +5461,73 @@
         }
     }
 
+    @Override
+    public boolean hasSigningCertificate(
+            String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
+
+        synchronized (mPackages) {
+            final PackageParser.Package p = mPackages.get(packageName);
+            if (p == null || p.mExtras == null) {
+                return false;
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            final PackageSetting ps = (PackageSetting) p.mExtras;
+            if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+                return false;
+            }
+            switch (type) {
+                case CERT_INPUT_RAW_X509:
+                    return signingDetailsHasCertificate(certificate, p.mSigningDetails);
+                case CERT_INPUT_SHA256:
+                    return signingDetailsHasSha256Certificate(certificate, p.mSigningDetails);
+                default:
+                    return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean hasUidSigningCertificate(
+            int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        // Map to base uids.
+        uid = UserHandle.getAppId(uid);
+        // reader
+        synchronized (mPackages) {
+            final PackageParser.SigningDetails signingDetails;
+            final Object obj = mSettings.getUserIdLPr(uid);
+            if (obj != null) {
+                if (obj instanceof SharedUserSetting) {
+                    final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
+                    if (isCallerInstantApp) {
+                        return false;
+                    }
+                    signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails;
+                } else if (obj instanceof PackageSetting) {
+                    final PackageSetting ps = (PackageSetting) obj;
+                    if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+                        return false;
+                    }
+                    signingDetails = ps.signatures.mSigningDetails;
+                } else {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+            switch (type) {
+                case CERT_INPUT_RAW_X509:
+                    return signingDetailsHasCertificate(certificate, signingDetails);
+                case CERT_INPUT_SHA256:
+                    return signingDetailsHasSha256Certificate(certificate, signingDetails);
+                default:
+                    return false;
+            }
+        }
+    }
+
     /**
      * This method should typically only be used when granting or revoking
      * permissions, since the app may immediately restart after this call.
@@ -9762,8 +9833,9 @@
      * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
      * </ul>
      */
-    private static @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
-            PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user) {
+    private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
+            PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
+            PackageParser.Package pkg) {
         if (disabledPkgSetting != null) {
             // updated system application, must at least have SCAN_AS_SYSTEM
             scanFlags |= SCAN_AS_SYSTEM;
@@ -9789,6 +9861,30 @@
                 scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
             }
         }
+
+        // Scan as privileged apps that share a user with a priv-app.
+        if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) && !pkg.isPrivileged()
+                && (pkg.mSharedUserId != null)) {
+            SharedUserSetting sharedUserSetting = null;
+            try {
+                sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
+            } catch (PackageManagerException ignore) {}
+            if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
+                // Exempt SharedUsers signed with the platform key.
+                // TODO(b/72378145) Fix this exemption. Force signature apps
+                // to whitelist their privileged permissions just like other
+                // priv-apps.
+                synchronized (mPackages) {
+                    PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+                    if (!pkg.packageName.equals("android")
+                            && (compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
+                                pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
+                        scanFlags |= SCAN_AS_PRIVILEGED;
+                    }
+                }
+            }
+        }
+
         return scanFlags;
     }
 
@@ -9812,7 +9908,7 @@
                     + " was transferred to another, but its .apk remains");
         }
 
-        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user);
+        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
         synchronized (mPackages) {
             applyPolicy(pkg, parseFlags, scanFlags);
             assertPackageIsValid(pkg, parseFlags, scanFlags);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index cfc12de..021c4b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -54,6 +54,7 @@
 import android.system.Os;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.jar.StrictJarFile;
 import android.util.proto.ProtoOutputStream;
@@ -74,6 +75,8 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.text.SimpleDateFormat;
@@ -576,6 +579,69 @@
         return true;
     }
 
+
+    /**
+     * Checks the signing certificates to see if the provided certificate is a member.  Invalid for
+     * {@code SigningDetails} with multiple signing certificates.
+     * @param certificate certificate to check for membership
+     * @param signingDetails signing certificates record whose members are to be searched
+     * @return true if {@code certificate} is in {@code signingDetails}
+     */
+    public static boolean signingDetailsHasCertificate(
+            byte[] certificate, PackageParser.SigningDetails signingDetails) {
+        if (signingDetails == PackageParser.SigningDetails.UNKNOWN) {
+            return false;
+        }
+        Signature signature = new Signature(certificate);
+        if (signingDetails.hasPastSigningCertificates()) {
+            for (int i = 0; i < signingDetails.pastSigningCertificates.length; i++) {
+                if (signingDetails.pastSigningCertificates[i].equals(signature)) {
+                    return true;
+                }
+            }
+        } else {
+            // no signing history, just check the current signer
+            if (signingDetails.signatures.length == 1
+                    && signingDetails.signatures[0].equals(signature)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks the signing certificates to see if the provided certificate is a member.  Invalid for
+     * {@code SigningDetails} with multiple signing certificaes.
+     * @param sha256Certificate certificate to check for membership
+     * @param signingDetails signing certificates record whose members are to be searched
+     * @return true if {@code certificate} is in {@code signingDetails}
+     */
+    public static boolean signingDetailsHasSha256Certificate(
+            byte[] sha256Certificate, PackageParser.SigningDetails signingDetails ) {
+        if (signingDetails == PackageParser.SigningDetails.UNKNOWN) {
+            return false;
+        }
+        if (signingDetails.hasPastSigningCertificates()) {
+            for (int i = 0; i < signingDetails.pastSigningCertificates.length; i++) {
+                byte[] digest = PackageUtils.computeSha256DigestBytes(
+                        signingDetails.pastSigningCertificates[i].toByteArray());
+                if (Arrays.equals(sha256Certificate, digest)) {
+                    return true;
+                }
+            }
+        } else {
+            // no signing history, just check the current signer
+            if (signingDetails.signatures.length == 1) {
+                byte[] digest = PackageUtils.computeSha256DigestBytes(
+                        signingDetails.signatures[0].toByteArray());
+                if (Arrays.equals(sha256Certificate, digest)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /** Returns true to force apk verification if the updated package (in /data) is a priv app. */
     static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) {
         return disabledPs != null && disabledPs.isPrivileged() &&
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c58c208..d67f2d7 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
+import android.hardware.fingerprint.IFingerprintDialogReceiver;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -514,6 +515,56 @@
     }
 
     @Override
+    public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
+        if (mBar != null) {
+            try {
+                mBar.showFingerprintDialog(bundle, receiver);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void onFingerprintAuthenticated() {
+        if (mBar != null) {
+            try {
+                mBar.onFingerprintAuthenticated();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void onFingerprintHelp(String message) {
+        if (mBar != null) {
+            try {
+                mBar.onFingerprintHelp(message);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void onFingerprintError(String error) {
+        if (mBar != null) {
+            try {
+                mBar.onFingerprintError(error);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void hideFingerprintDialog() {
+        if (mBar != null) {
+            try {
+                mBar.hideFingerprintDialog();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
     public void disable(int what, IBinder token, String pkg) {
         disableForUser(what, token, pkg, mCurrentUserId);
     }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 0bc58e0..7540e26 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -104,6 +104,8 @@
         "libhwbinder",
         "libutils",
         "libhwui",
+        "libbpf",
+        "libnetdutils",
         "android.hardware.audio.common@2.0",
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@1.1",
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 8de24e5..3302dea 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -29,6 +29,15 @@
 #include <utils/misc.h>
 #include <utils/Log.h>
 
+#include "android-base/unique_fd.h"
+#include "bpf/BpfNetworkStats.h"
+#include "bpf/BpfUtils.h"
+
+using android::bpf::Stats;
+using android::bpf::hasBpfSupport;
+using android::bpf::bpfGetUidStats;
+using android::bpf::bpfGetIfaceStats;
+
 namespace android {
 
 static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt";
@@ -46,15 +55,6 @@
     TCP_TX_PACKETS = 5
 };
 
-struct Stats {
-    uint64_t rxBytes;
-    uint64_t rxPackets;
-    uint64_t txBytes;
-    uint64_t txPackets;
-    uint64_t tcpRxPackets;
-    uint64_t tcpTxPackets;
-};
-
 static uint64_t getStatsType(struct Stats* stats, StatsType type) {
     switch (type) {
         case RX_BYTES:
@@ -150,9 +150,18 @@
     return 0;
 }
 
-static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
     struct Stats stats;
     memset(&stats, 0, sizeof(Stats));
+
+    if (useBpfStats) {
+        if (bpfGetIfaceStats(NULL, &stats) == 0) {
+            return getStatsType(&stats, (StatsType) type);
+        } else {
+            return UNKNOWN;
+        }
+    }
+
     if (parseIfaceStats(NULL, &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
@@ -160,7 +169,8 @@
     }
 }
 
-static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
+                          jboolean useBpfStats) {
     ScopedUtfChars iface8(env, iface);
     if (iface8.c_str() == NULL) {
         return UNKNOWN;
@@ -168,6 +178,15 @@
 
     struct Stats stats;
     memset(&stats, 0, sizeof(Stats));
+
+    if (useBpfStats) {
+        if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
+            return getStatsType(&stats, (StatsType) type);
+        } else {
+            return UNKNOWN;
+        }
+    }
+
     if (parseIfaceStats(iface8.c_str(), &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
@@ -175,9 +194,18 @@
     }
 }
 
-static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
+static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
     struct Stats stats;
     memset(&stats, 0, sizeof(Stats));
+
+    if (useBpfStats) {
+        if (bpfGetUidStats(uid, &stats) == 0) {
+            return getStatsType(&stats, (StatsType) type);
+        } else {
+            return UNKNOWN;
+        }
+    }
+
     if (parseUidStats(uid, &stats) == 0) {
         return getStatsType(&stats, (StatsType) type);
     } else {
@@ -186,9 +214,9 @@
 }
 
 static const JNINativeMethod gMethods[] = {
-    {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
-    {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
-    {"nativeGetUidStat", "(II)J", (void*) getUidStat},
+    {"nativeGetTotalStat", "(IZ)J", (void*) getTotalStat},
+    {"nativeGetIfaceStat", "(Ljava/lang/String;IZ)J", (void*) getIfaceStat},
+    {"nativeGetUidStat", "(IIZ)J", (void*) getUidStat},
 };
 
 int register_android_server_net_NetworkStatsService(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 4f2866b..886747cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -22,11 +22,13 @@
 import android.os.UserHandle;
 import android.security.keymaster.KeymasterCertificateChain;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.telephony.data.ApnSetting;
 
 import com.android.internal.R;
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -146,4 +148,32 @@
     public List<String> getMeteredDataDisabled(ComponentName admin) {
         return new ArrayList<>();
     }
+
+    @Override
+    public int addOverrideApn(ComponentName admin, ApnSetting apnSetting) {
+        return -1;
+    }
+
+    @Override
+    public boolean updateOverrideApn(ComponentName admin, int apnId, ApnSetting apnSetting) {
+        return false;
+    }
+
+    @Override
+    public boolean removeOverrideApn(ComponentName admin, int apnId) {
+        return false;
+    }
+
+    @Override
+    public List<ApnSetting> getOverrideApns(ComponentName admin) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setOverrideApnsEnabled(ComponentName admin, boolean enabled) {}
+
+    @Override
+    public boolean isOverrideApnEnabled(ComponentName admin) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4d6989b..cb346cc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -58,8 +58,15 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static android.provider.Telephony.Carriers.DPC_URI;
+import static android.provider.Telephony.Carriers.ENFORCE_KEY;
+import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
+        .PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
+        .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.TEXT;
@@ -99,6 +106,7 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -108,8 +116,8 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
@@ -118,6 +126,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.media.AudioManager;
@@ -161,13 +170,14 @@
 import android.security.IKeyChainService;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
+import android.security.KeyStore;
 import android.security.keymaster.KeymasterCertificateChain;
+import android.security.keystore.AttestationUtils;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.ParcelableKeyGenParameterSpec;
-import android.security.KeyStore;
-import android.security.keystore.AttestationUtils;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -217,7 +227,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.IllegalStateException;
 import java.lang.reflect.Constructor;
 import java.nio.charset.StandardCharsets;
 import java.text.DateFormat;
@@ -228,8 +237,8 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map.Entry;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -7283,6 +7292,15 @@
         }
     }
 
+    private void clearOverrideApnUnchecked() {
+        // Disable Override APNs and remove them from database.
+        setOverrideApnsEnabledUnchecked(false);
+        final List<ApnSetting> apns = getOverrideApnsUnchecked();
+        for (int i = 0; i < apns.size(); i ++) {
+            removeOverrideApnUnchecked(apns.get(i).getId());
+        }
+    }
+
     private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
         mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-device-owner");
 
@@ -7303,6 +7321,7 @@
         systemPolicyData.mLastNetworkLogsRetrievalTime = -1;
         saveSettingsLocked(UserHandle.USER_SYSTEM);
         clearUserPoliciesLocked(userId);
+        clearOverrideApnUnchecked();
 
         mOwners.clearDeviceOwner();
         mOwners.writeDeviceOwner();
@@ -12509,4 +12528,185 @@
                     .getResources().getString(R.string.printing_disabled_by, appLabel);
         }
     }
+
+    @Override
+    public int addOverrideApn(@NonNull ComponentName who, @NonNull ApnSetting apnSetting) {
+        if (!mHasFeature) {
+            return -1;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in addOverrideApn");
+        Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        int operatedId = -1;
+        Uri resultUri;
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            resultUri = mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues());
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+        if (resultUri != null) {
+            try {
+                operatedId = Integer.parseInt(resultUri.getLastPathSegment());
+            } catch (NumberFormatException e) {
+                Slog.e(LOG_TAG, "Failed to parse inserted override APN id.", e);
+            }
+        }
+
+        return operatedId;
+    }
+
+    @Override
+    public boolean updateOverrideApn(@NonNull ComponentName who, int apnId,
+            @NonNull ApnSetting apnSetting) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in updateOverrideApn");
+        Preconditions.checkNotNull(apnSetting, "ApnSetting is null in updateOverrideApn");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        if (apnId < 0) {
+            return false;
+        }
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            return mContext.getContentResolver().update(
+                    Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
+                    apnSetting.toContentValues(), null, null) > 0;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+    }
+
+    @Override
+    public boolean removeOverrideApn(@NonNull ComponentName who, int apnId) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in removeOverrideApn");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        return removeOverrideApnUnchecked(apnId);
+    }
+
+    private boolean removeOverrideApnUnchecked(int apnId) {
+        if(apnId < 0) {
+            return false;
+        }
+        int numDeleted = 0;
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            numDeleted = mContext.getContentResolver().delete(
+                    Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), null, null);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+        return numDeleted > 0;
+    }
+
+    @Override
+    public List<ApnSetting> getOverrideApns(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return Collections.emptyList();
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in getOverrideApns");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        return getOverrideApnsUnchecked();
+    }
+
+    private List<ApnSetting> getOverrideApnsUnchecked() {
+        final Cursor cursor;
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            cursor = mContext.getContentResolver().query(DPC_URI, null, null, null, null);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+
+        if (cursor == null) {
+            return Collections.emptyList();
+        }
+        try {
+            List<ApnSetting> apnList = new ArrayList<ApnSetting>();
+            cursor.moveToPosition(-1);
+            while (cursor.moveToNext()) {
+                ApnSetting apn = ApnSetting.makeApnSetting(cursor);
+                apnList.add(apn);
+            }
+            return apnList;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    @Override
+    public void setOverrideApnsEnabled(@NonNull ComponentName who, boolean enabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in setOverrideApnEnabled");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        setOverrideApnsEnabledUnchecked(enabled);
+    }
+
+    private void setOverrideApnsEnabledUnchecked(boolean enabled) {
+        ContentValues value = new ContentValues();
+        value.put(ENFORCE_KEY, enabled);
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            mContext.getContentResolver().update(
+                    ENFORCE_MANAGED_URI, value, null, null);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+    }
+
+    @Override
+    public boolean isOverrideApnEnabled(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null in isOverrideApnEnabled");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        Cursor enforceCursor;
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            enforceCursor = mContext.getContentResolver().query(
+                    ENFORCE_MANAGED_URI, null, null, null, null);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+
+        if (enforceCursor == null) {
+            return false;
+        }
+        try {
+            if (enforceCursor.moveToFirst()) {
+                return enforceCursor.getInt(enforceCursor.getColumnIndex(ENFORCE_KEY)) == 1;
+            }
+        } catch (IllegalArgumentException e) {
+            Slog.e(LOG_TAG, "Cursor returned from ENFORCE_MANAGED_URI doesn't contain "
+                    + "correct info.", e);
+        } finally {
+            enforceCursor.close();
+        }
+        return false;
+    }
 }
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 5a3a8be..984c9f8 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -121,6 +121,14 @@
     public static final int ICMP_ECHO_DATA_OFFSET = 8;
 
     /**
+     * ICMPv4 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc792
+     */
+    public static final int ICMPV4_ECHO_REQUEST_TYPE = 8;
+
+    /**
      * ICMPv6 constants.
      *
      * See also:
@@ -139,6 +147,8 @@
     public static final int ICMPV6_ND_OPTION_TLLA = 2;
     public static final int ICMPV6_ND_OPTION_MTU  = 5;
 
+    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+
     /**
      * UDP constants.
      *
@@ -157,6 +167,14 @@
     public static final int DHCP4_CLIENT_PORT = 68;
 
     /**
+     * DNS constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc1035
+     */
+    public static final int DNS_SERVER_PORT = 53;
+
+    /**
      * Utility functions.
      */
     public static byte asByte(int i) { return (byte) i; }
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index de54e52..a29e169 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.server;
 
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+
 import static com.android.server.ForceAppStandbyTracker.TARGET_OP;
 
 import static org.junit.Assert.assertEquals;
@@ -33,6 +35,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
@@ -259,13 +262,19 @@
     private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY;
 
     private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
-            int restrictionTypes) {
+            int restrictionTypes, boolean exemptFromBatterySaver) {
         assertEquals(((restrictionTypes & JOBS_ONLY) != 0),
-                instance.areJobsRestricted(uid, packageName));
+                instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver));
         assertEquals(((restrictionTypes & ALARMS_ONLY) != 0),
                 instance.areAlarmsRestricted(uid, packageName));
     }
 
+    private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+            int restrictionTypes) {
+        areRestricted(instance, uid, packageName, restrictionTypes,
+                /*exemptFromBatterySaver=*/ false);
+    }
+
     @Test
     public void testAll() throws Exception {
         final ForceAppStandbyTrackerTestable instance = newInstance();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 8d5556e..07262e1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -23,6 +23,8 @@
 
 import static com.android.server.testutils.TestUtils.strictMock;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -32,6 +34,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Handler;
 import android.os.Message;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -46,7 +49,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CompletableFuture;
 import java.util.function.IntConsumer;
+import java.util.function.Supplier;
 
 
 /**
@@ -130,7 +135,7 @@
     }
 
     @NonNull
-    public MagnificationGestureHandler newInstance(boolean detectTripleTap,
+    private MagnificationGestureHandler newInstance(boolean detectTripleTap,
             boolean detectShortcutTrigger) {
         MagnificationGestureHandler h = new MagnificationGestureHandler(
                 mContext, mMagnificationController,
@@ -192,6 +197,16 @@
         });
     }
 
+    @Test
+    public void testTransitionToDelegatingStateAndClear_preservesShortcutTriggeredState() {
+        mMgh.mDetectingState.transitionToDelegatingStateAndClear();
+        assertFalse(mMgh.mDetectingState.mShortcutTriggered);
+
+        goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
+        mMgh.mDetectingState.transitionToDelegatingStateAndClear();
+        assertTrue(mMgh.mDetectingState.mShortcutTriggered);
+    }
+
     /**
      * Covers edges of the graph not covered by "canonical" transitions specified in
      * {@link #goFromStateIdleTo} and {@link #returnToNormalFrom}
@@ -510,14 +525,20 @@
         fastForward(1);
     }
 
+    private static MotionEvent fromTouchscreen(MotionEvent ev) {
+        ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        return ev;
+    }
+
     private MotionEvent moveEvent(float x, float y) {
-        return MotionEvent.obtain(mLastDownTime, mClock.now(), ACTION_MOVE, x, y, 0);
+        return fromTouchscreen(
+        	    MotionEvent.obtain(mLastDownTime, mClock.now(), ACTION_MOVE, x, y, 0));
     }
 
     private MotionEvent downEvent() {
         mLastDownTime = mClock.now();
-        return MotionEvent.obtain(mLastDownTime, mLastDownTime,
-                ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0);
+        return fromTouchscreen(MotionEvent.obtain(mLastDownTime, mLastDownTime,
+                ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0));
     }
 
     private MotionEvent upEvent() {
@@ -525,8 +546,8 @@
     }
 
     private MotionEvent upEvent(long downTime) {
-        return MotionEvent.obtain(downTime, mClock.now(),
-                MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0);
+        return fromTouchscreen(MotionEvent.obtain(downTime, mClock.now(),
+                MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0));
     }
 
     private MotionEvent pointerEvent(int action, float x, float y) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e8d6ed2..5825a8b7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -78,6 +78,7 @@
 import android.security.KeyChain;
 import android.security.keystore.AttestationUtils;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
@@ -4610,6 +4611,23 @@
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
     }
 
+    public void testOverrideApnAPIsFailWithPO() throws Exception {
+        setupProfileOwner();
+        ApnSetting apn = (new ApnSetting.Builder()).build();
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.addOverrideApn(admin1, apn));
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.updateOverrideApn(admin1, 0, apn));
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.removeOverrideApn(admin1, 0));
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.getOverrideApns(admin1));
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.setOverrideApnsEnabled(admin1, false));
+        assertExpectException(SecurityException.class, null, () ->
+                dpm.isOverrideApnEnabled(admin1));
+    }
+
     private void verifyCanGetOwnerInstalledCaCerts(
             final ComponentName caller, final DpmMockContext callerContext) throws Exception {
         final String alias = "cert";
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 0343a52..34c69f5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -32,6 +32,7 @@
 import android.app.backup.IBackupManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -39,8 +40,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
+import android.database.Cursor;
 import android.media.IAudioService;
 import android.net.IIpConnectivityMetrics;
+import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -51,6 +54,7 @@
 import android.provider.Settings;
 import android.security.KeyChain;
 import android.telephony.TelephonyManager;
+import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.util.ArrayMap;
 import android.util.Pair;
@@ -144,6 +148,23 @@
         packageManager = spy(realContext.getPackageManager());
 
         contentResolver = new MockContentResolver();
+        contentResolver.addProvider("telephony", new MockContentProvider(realContext) {
+            @Override
+            public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+                return 0;
+            }
+
+            @Override
+            public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+                    String sortOrder) {
+                return null;
+            }
+
+            @Override
+            public int delete(Uri uri, String selection, String[] selectionArgs) {
+                return 0;
+            }
+        });
         contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
 
         // Add the system user with a fake profile group already set up (this can happen in the real
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 43d026d..e2064aa 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -47,6 +47,8 @@
 
 /**
  * Test reading and writing correctly from file.
+ *
+ * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
  */
 @RunWith(AndroidJUnit4.class)
 public class JobStoreTest {
@@ -116,6 +118,7 @@
                 .setPersisted(true)
                 .build();
         final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
+        ts.addInternalFlags(JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION);
         mTaskStoreUnderTest.add(ts);
         waitForPendingIo();
 
@@ -128,6 +131,8 @@
         assertTasksEqual(task, loadedTaskStatus.getJob());
         assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(ts));
         assertEquals("Different uids.", SOME_UID, loadedTaskStatus.getUid());
+        assertEquals(JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION,
+                loadedTaskStatus.getInternalFlags());
         compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
                 ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
         compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
@@ -272,7 +277,7 @@
                 0 /* sourceUserId */, 0, 0, "someTag",
                 invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
-                persistedExecutionTimesUTC);
+                persistedExecutionTimesUTC, 0 /* innerFlagg */);
 
         mTaskStoreUnderTest.add(js);
         waitForPendingIo();
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index f6a749d..35cba18 100644
--- a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -164,6 +164,6 @@
     private static JobStatus createJobStatus(JobInfo.Builder job, long earliestRunTimeElapsedMillis,
             long latestRunTimeElapsedMillis) {
         return new JobStatus(job.build(), 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
-                latestRunTimeElapsedMillis, 0, 0, null);
+                latestRunTimeElapsedMillis, 0, 0, null, 0);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 15c24ac..d78af22 100644
--- a/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -71,6 +71,6 @@
         final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
         return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
-                latestRunTimeElapsedMillis, 0, 0, null);
+                latestRunTimeElapsedMillis, 0, 0, null, 0);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 4bdd1c5..bc61c58 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -18,11 +18,14 @@
 
 import android.content.Context;
 
+import com.android.server.PersistentDataBlockManagerInternal;
+
 import java.io.File;
 
 public class LockSettingsStorageTestable extends LockSettingsStorage {
 
     public File mStorageDir;
+    public PersistentDataBlockManagerInternal mPersistentDataBlock;
 
     public LockSettingsStorageTestable(Context context, File storageDir) {
         super(context);
@@ -53,6 +56,11 @@
                 userId).getAbsolutePath());
     }
 
+    @Override
+    public PersistentDataBlockManagerInternal getPersistentDataBlock() {
+        return mPersistentDataBlock;
+    }
+
     private File makeDirs(File baseDir, String filePath) {
         File path = new File(filePath);
         if (path.getParent() == null) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index b0325cb..237091d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -29,8 +29,12 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.test.AndroidTestCase;
+import android.util.Log;
+import android.util.Log.TerribleFailure;
+import android.util.Log.TerribleFailureHandler;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
 
@@ -52,7 +56,7 @@
 
     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 33};
 
-    LockSettingsStorage mStorage;
+    LockSettingsStorageTestable mStorage;
     File mStorageDir;
 
     private File mDb;
@@ -346,6 +350,39 @@
         assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
     }
 
+    public void testPersistentDataBlock_unavailable() {
+        mStorage.mPersistentDataBlock = null;
+
+        assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
+    }
+
+    public void testPersistentDataBlock_empty() {
+        mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
+
+        assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
+    }
+
+    public void testPersistentDataBlock_withData() {
+        mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
+        when(mStorage.mPersistentDataBlock.getFrpCredentialHandle())
+                .thenReturn(PersistentData.toBytes(PersistentData.TYPE_SP_WEAVER, SOME_USER_ID,
+                        DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, PAYLOAD));
+
+        PersistentData data = mStorage.readPersistentDataBlock();
+
+        assertEquals(PersistentData.TYPE_SP_WEAVER, data.type);
+        assertEquals(SOME_USER_ID, data.userId);
+        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, data.qualityForUi);
+        assertArrayEquals(PAYLOAD, data.payload);
+    }
+
+    public void testPersistentDataBlock_exception() {
+        mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
+        when(mStorage.mPersistentDataBlock.getFrpCredentialHandle())
+                .thenThrow(new IllegalStateException("oops"));
+        assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
+    }
+
     public void testPersistentData_serializeUnserialize() {
         byte[] serialized = PersistentData.toBytes(PersistentData.TYPE_SP, SOME_USER_ID,
                 DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, PAYLOAD);
@@ -366,6 +403,13 @@
         assertSame(PersistentData.NONE, deserialized);
     }
 
+    public void testPersistentData_unserializeInvalid() {
+        assertNotNull(suppressAndReturnWtf(() -> {
+            PersistentData deserialized = PersistentData.fromBytes(new byte[]{5});
+            assertSame(PersistentData.NONE, deserialized);
+        }));
+    }
+
     public void testPersistentData_unserialize_version1() {
         // This test ensures that we can read serialized VERSION_1 PersistentData even if we change
         // the wire format in the future.
@@ -450,4 +494,19 @@
         assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type);
         assertArrayEquals(pattern, cred.hash);
     }
+
+    /**
+     * Suppresses reporting of the WTF to system_server, so we don't pollute the dropbox with
+     * intentionally caused WTFs.
+     */
+    private TerribleFailure suppressAndReturnWtf(Runnable r) {
+        TerribleFailure[] captured = new TerribleFailure[1];
+        TerribleFailureHandler prevWtfHandler = Log.setWtfHandler((t, w, s) -> captured[0] = w);
+        try {
+            r.run();
+        } finally {
+            Log.setWtfHandler(prevWtfHandler);
+        }
+        return captured[0];
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 6edaf87..6a3a260 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -16,11 +16,11 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN;
+import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
 
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PASSWORD;
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PATTERN;
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PIN;
+import static android.security.keystore.recovery.KeyChainProtectionParams.UI_FORMAT_PASSWORD;
+import static android.security.keystore.recovery.KeyChainProtectionParams.UI_FORMAT_PATTERN;
+import static android.security.keystore.recovery.KeyChainProtectionParams.UI_FORMAT_PIN;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
@@ -41,7 +41,7 @@
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.recovery.KeyDerivationParams;
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
@@ -190,19 +190,19 @@
 
     @Test
     public void getUiFormat_returnsPinIfPin() {
-        assertEquals(TYPE_PIN,
+        assertEquals(UI_FORMAT_PIN,
                 KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234"));
     }
 
     @Test
     public void getUiFormat_returnsPasswordIfPassword() {
-        assertEquals(TYPE_PASSWORD,
+        assertEquals(UI_FORMAT_PASSWORD,
                 KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a"));
     }
 
     @Test
     public void getUiFormat_returnsPatternIfPattern() {
-        assertEquals(TYPE_PATTERN,
+        assertEquals(UI_FORMAT_PATTERN,
                 KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234"));
 
     }
@@ -287,33 +287,33 @@
 
         mKeySyncTask.run();
 
-        KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        KeyDerivationParams KeyDerivationParams =
-                keychainSnapshot.getKeychainProtectionParams().get(0).getKeyDerivationParams();
-        assertThat(KeyDerivationParams.getAlgorithm()).isEqualTo(
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        KeyDerivationParams keyDerivationParams =
+                keyChainSnapshot.getKeyChainProtectionParams().get(0).getKeyDerivationParams();
+        assertThat(keyDerivationParams.getAlgorithm()).isEqualTo(
                 KeyDerivationParams.ALGORITHM_SHA256);
         verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
         byte[] lockScreenHash = KeySyncTask.hashCredentials(
-                KeyDerivationParams.getSalt(),
+                keyDerivationParams.getSalt(),
                 TEST_CREDENTIAL);
         Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
         counterId = 1L; // TODO: use value from the database.
         assertThat(counterId).isNotNull();
         byte[] recoveryKey = decryptThmEncryptedKey(
                 lockScreenHash,
-                keychainSnapshot.getEncryptedRecoveryKeyBlob(),
+                keyChainSnapshot.getEncryptedRecoveryKeyBlob(),
                 /*vaultParams=*/ KeySyncUtils.packVaultParams(
                         mKeyPair.getPublic(),
                         counterId,
                         /*maxAttempts=*/ 10,
                         TEST_VAULT_HANDLE));
-        List<WrappedApplicationKey> applicationKeys = keychainSnapshot.getWrappedApplicationKeys();
+        List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
         assertThat(applicationKeys).hasSize(1);
-        assertThat(keychainSnapshot.getCounterId()).isEqualTo(counterId);
-        assertThat(keychainSnapshot.getMaxAttempts()).isEqualTo(10);
-        assertThat(keychainSnapshot.getTrustedHardwarePublicKey())
+        assertThat(keyChainSnapshot.getCounterId()).isEqualTo(counterId);
+        assertThat(keyChainSnapshot.getMaxAttempts()).isEqualTo(10);
+        assertThat(keyChainSnapshot.getTrustedHardwarePublicKey())
                 .isEqualTo(SecureBox.encodePublicKey(mKeyPair.getPublic()));
-        assertThat(keychainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
+        assertThat(keyChainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
         WrappedApplicationKey keyData = applicationKeys.get(0);
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
         assertThat(keyData.getAlias()).isEqualTo(keyData.getAlias());
@@ -332,14 +332,14 @@
 
         mKeySyncTask.run();
 
-        KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        assertThat(keychainSnapshot.getSnapshotVersion()).isEqualTo(1); // default value;
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(keyChainSnapshot.getSnapshotVersion()).isEqualTo(1); // default value;
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, true);
 
         mKeySyncTask.run();
 
-        keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        assertThat(keychainSnapshot.getSnapshotVersion()).isEqualTo(2); // Updated
+        keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(keyChainSnapshot.getSnapshotVersion()).isEqualTo(2); // Updated
     }
 
     @Test
@@ -362,10 +362,10 @@
 
         mKeySyncTask.run();
 
-        KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        assertThat(keychainSnapshot.getKeychainProtectionParams()).hasSize(1);
-        assertThat(keychainSnapshot.getKeychainProtectionParams().get(0).getLockScreenUiFormat()).
-                isEqualTo(TYPE_PASSWORD);
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
+                isEqualTo(UI_FORMAT_PASSWORD);
     }
 
    @Test
@@ -388,11 +388,11 @@
 
         mKeySyncTask.run();
 
-        KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        assertThat(keychainSnapshot.getKeychainProtectionParams()).hasSize(1);
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
         // Password with only digits is changed to pin.
-        assertThat(keychainSnapshot.getKeychainProtectionParams().get(0).getLockScreenUiFormat()).
-                isEqualTo(TYPE_PIN);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
+                isEqualTo(UI_FORMAT_PIN);
     }
 
     @Test
@@ -415,10 +415,10 @@
 
         mKeySyncTask.run();
 
-        KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
-        assertThat(keychainSnapshot.getKeychainProtectionParams()).hasSize(1);
-        assertThat(keychainSnapshot.getKeychainProtectionParams().get(0).getLockScreenUiFormat()).
-                isEqualTo(TYPE_PATTERN);
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams()).hasSize(1);
+        assertThat(keyChainSnapshot.getKeyChainProtectionParams().get(0).getLockScreenUiFormat()).
+                isEqualTo(UI_FORMAT_PATTERN);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a3a2e47..c863aab 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -16,8 +16,8 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN;
-import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PASSWORD;
+import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
+import static android.security.keystore.recovery.KeyChainProtectionParams.UI_FORMAT_PASSWORD;
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertArrayEquals;
@@ -43,7 +43,7 @@
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.recovery.KeyDerivationParams;
-import android.security.keystore.recovery.KeychainProtectionParams;
+import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.support.test.filters.SmallTest;
 import android.support.test.InstrumentationRegistry;
@@ -250,9 +250,9 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeychainProtectionParams(
+                        new KeyChainProtectionParams(
                                 TYPE_LOCKSCREEN,
-                                TYPE_PASSWORD,
+                                UI_FORMAT_PASSWORD,
                                 KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
@@ -269,9 +269,9 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeychainProtectionParams(
+                        new KeyChainProtectionParams(
                                 TYPE_LOCKSCREEN,
-                                TYPE_PASSWORD,
+                                UI_FORMAT_PASSWORD,
                                 KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
@@ -290,9 +290,9 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeychainProtectionParams(
+                        new KeyChainProtectionParams(
                                 TYPE_LOCKSCREEN,
-                                TYPE_PASSWORD,
+                                UI_FORMAT_PASSWORD,
                                 KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
@@ -309,9 +309,9 @@
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
                 ImmutableList.of(
-                        new KeychainProtectionParams(
+                        new KeyChainProtectionParams(
                                 TYPE_LOCKSCREEN,
-                                TYPE_PASSWORD,
+                                UI_FORMAT_PASSWORD,
                                 KeyDerivationParams.createSha256Params(TEST_SALT),
                                 TEST_SECRET)));
 
@@ -332,7 +332,7 @@
             fail("should have thrown");
         } catch (UnsupportedOperationException e) {
             assertThat(e.getMessage()).startsWith(
-                    "Only a single KeychainProtectionParams is supported");
+                    "Only a single KeyChainProtectionParams is supported");
         }
     }
 
@@ -345,9 +345,9 @@
                     TEST_VAULT_PARAMS,
                     TEST_VAULT_CHALLENGE,
                     ImmutableList.of(
-                            new KeychainProtectionParams(
+                            new KeyChainProtectionParams(
                                     TYPE_LOCKSCREEN,
-                                    TYPE_PASSWORD,
+                                    UI_FORMAT_PASSWORD,
                                     KeyDerivationParams.createSha256Params(TEST_SALT),
                                     TEST_SECRET)));
             fail("should have thrown");
@@ -367,9 +367,9 @@
                     vaultParams,
                     TEST_VAULT_CHALLENGE,
                     ImmutableList.of(
-                            new KeychainProtectionParams(
+                            new KeyChainProtectionParams(
                                     TYPE_LOCKSCREEN,
-                                    TYPE_PASSWORD,
+                                    UI_FORMAT_PASSWORD,
                                     KeyDerivationParams.createSha256Params(TEST_SALT),
                                     TEST_SECRET)));
             fail("should have thrown");
@@ -400,9 +400,9 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeychainProtectionParams(
+                ImmutableList.of(new KeyChainProtectionParams(
                         TYPE_LOCKSCREEN,
-                        TYPE_PASSWORD,
+                        UI_FORMAT_PASSWORD,
                         KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
 
@@ -424,9 +424,9 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeychainProtectionParams(
+                ImmutableList.of(new KeyChainProtectionParams(
                         TYPE_LOCKSCREEN,
-                        TYPE_PASSWORD,
+                        UI_FORMAT_PASSWORD,
                         KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
@@ -456,9 +456,9 @@
                 TEST_PUBLIC_KEY,
                 TEST_VAULT_PARAMS,
                 TEST_VAULT_CHALLENGE,
-                ImmutableList.of(new KeychainProtectionParams(
+                ImmutableList.of(new KeyChainProtectionParams(
                         TYPE_LOCKSCREEN,
-                        TYPE_PASSWORD,
+                        UI_FORMAT_PASSWORD,
                         KeyDerivationParams.createSha256Params(TEST_SALT),
                         TEST_SECRET)));
         byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
index 89c5c6c..d61a294 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
@@ -3,7 +3,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import android.security.keystore.recovery.KeychainSnapshot;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -26,25 +26,25 @@
     @Test
     public void get_returnsSetSnapshot() {
         int userId = 1000;
-        KeychainSnapshot keychainSnapshot = new KeychainSnapshot(
+        KeyChainSnapshot keyChainSnapshot = new KeyChainSnapshot(
                 /*snapshotVersion=*/ 1,
                 new ArrayList<>(),
                 new ArrayList<>(),
                 new byte[0]);
-        mRecoverySnapshotStorage.put(userId, keychainSnapshot);
+        mRecoverySnapshotStorage.put(userId, keyChainSnapshot);
 
-        assertEquals(keychainSnapshot, mRecoverySnapshotStorage.get(userId));
+        assertEquals(keyChainSnapshot, mRecoverySnapshotStorage.get(userId));
     }
 
     @Test
     public void remove_removesSnapshots() {
         int userId = 1000;
-        KeychainSnapshot keychainSnapshot = new KeychainSnapshot(
+        KeyChainSnapshot keyChainSnapshot = new KeyChainSnapshot(
                 /*snapshotVersion=*/ 1,
                 new ArrayList<>(),
                 new ArrayList<>(),
                 new byte[0]);
-        mRecoverySnapshotStorage.put(userId, keychainSnapshot);
+        mRecoverySnapshotStorage.put(userId, keyChainSnapshot);
 
         mRecoverySnapshotStorage.remove(userId);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e0bebee..9ae6f00 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1179,6 +1179,34 @@
     }
 
     @Test
+    public void testUpdateAppNotifyCreatorBlock() throws Exception {
+        mService.setRankingHelper(mRankingHelper);
+
+        mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+        assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
+                captor.getValue().getAction());
+        assertEquals(PKG, captor.getValue().getPackage());
+        assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+    }
+
+    @Test
+    public void testUpdateAppNotifyCreatorUnblock() throws Exception {
+        mService.setRankingHelper(mRankingHelper);
+
+        mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+        assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
+                captor.getValue().getAction());
+        assertEquals(PKG, captor.getValue().getPackage());
+        assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+    }
+
+    @Test
     public void testUpdateChannelNotifyCreatorBlock() throws Exception {
         mService.setRankingHelper(mRankingHelper);
         when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index cb32d1f..4d458b0 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -92,6 +92,17 @@
         return false;
     }
 
+    /**
+     * Returns whether the event type is one caused by user visible
+     * interaction. Excludes those that are internally generated.
+     * @param eventType
+     * @return
+     */
+    private boolean isUserVisibleEvent(int eventType) {
+        return eventType != UsageEvents.Event.SYSTEM_INTERACTION
+                && eventType != UsageEvents.Event.STANDBY_BUCKET_CHANGED;
+    }
+
     void update(String packageName, long timeStamp, int eventType) {
         UsageStats usageStats = getOrCreateUsageStats(packageName);
 
@@ -109,7 +120,7 @@
             usageStats.mLastEvent = eventType;
         }
 
-        if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) {
+        if (isUserVisibleEvent(eventType)) {
             usageStats.mLastTimeUsed = timeStamp;
         }
         usageStats.mEndTimeStamp = timeStamp;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 979feaa..096fdcc 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -115,6 +115,26 @@
 
     AppStandbyController mAppStandby;
 
+    private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
+            new UsageStatsManagerInternal.AppIdleStateChangeListener() {
+                @Override
+                public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+                        int bucket) {
+                    Event event = new Event();
+                    event.mEventType = Event.STANDBY_BUCKET_CHANGED;
+                    event.mBucket = bucket;
+                    event.mPackage = packageName;
+                    // This will later be converted to system time.
+                    event.mTimeStamp = SystemClock.elapsedRealtime();
+                    mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+                }
+
+                @Override
+                public void onParoleStateChanged(boolean isParoleOn) {
+
+                }
+            };
+
     public UsageStatsService(Context context) {
         super(context);
     }
@@ -129,6 +149,7 @@
 
         mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper());
 
+        mAppStandby.addListener(mStandbyChangeListener);
         File systemDataDir = new File(Environment.getDataDirectory(), "system");
         mUsageStatsDir = new File(systemDataDir, "usagestats");
         mUsageStatsDir.mkdirs();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index cc53a9c..d1ed599 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -64,6 +64,7 @@
     private static final String LAST_EVENT_ATTR = "lastEvent";
     private static final String TYPE_ATTR = "type";
     private static final String SHORTCUT_ID_ATTR = "shortcutId";
+    private static final String STANDBY_BUCKET_ATTR = "standbyBucket";
 
     // Time attributes stored as an offset of the beginTime.
     private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
@@ -173,6 +174,9 @@
                 final String id = XmlUtils.readStringAttribute(parser, SHORTCUT_ID_ATTR);
                 event.mShortcutId = (id != null) ? id.intern() : null;
                 break;
+            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+                event.mBucket = XmlUtils.readIntAttribute(parser, STANDBY_BUCKET_ATTR, 0);
+                break;
         }
 
         if (statsOut.events == null) {
@@ -276,6 +280,10 @@
                     XmlUtils.writeStringAttribute(xml, SHORTCUT_ID_ATTR, event.mShortcutId);
                 }
                 break;
+            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+                if (event.mBucket != 0) {
+                    XmlUtils.writeIntAttribute(xml, STANDBY_BUCKET_ATTR, event.mBucket);
+                }
         }
 
         xml.endTag(null, EVENT_TAG);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index f02221c..ec12da2 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -599,6 +599,9 @@
             if (event.mShortcutId != null) {
                 pw.printPair("shortcutId", event.mShortcutId);
             }
+            if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
+                pw.printPair("standbyBucket", event.mBucket);
+            }
             pw.printHexPair("flags", event.mFlags);
             pw.println();
         }
@@ -645,6 +648,8 @@
                 return "CHOOSER_ACTION";
             case UsageEvents.Event.NOTIFICATION_SEEN:
                 return "NOTIFICATION_SEEN";
+            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
+                return "STANDBY_BUCKET_CHANGED";
             default:
                 return "UNKNOWN";
         }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index e633053..8c45724 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1102,6 +1102,16 @@
                 "android.provider.Telephony.MMS_DOWNLOADED";
 
             /**
+             * Broadcast Action: A debug code has been entered in the dialer. These "secret codes"
+             * are used to activate developer menus by dialing certain codes. And they are of the
+             * form {@code *#*#&lt;code&gt;#*#*}. The intent will have the data URI:
+             * {@code android_secret_code://&lt;code&gt;}.
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SECRET_CODE_ACTION =
+                    "android.provider.Telephony.SECRET_CODE";
+
+            /**
              * Broadcast action: When the default SMS package changes,
              * the previous default SMS package and the new default SMS
              * package are sent this broadcast to notify them of the change.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e33b25e..2bdbfdd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
 import android.annotation.WorkerThread;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
@@ -42,6 +43,7 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index b9ed005..88bae33 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -142,11 +142,12 @@
     /**
      * Gets all the profiles on eUicc.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback The callback to get the result code and all the profiles.
      */
-    public void getAllProfiles(ResultCallback<EuiccProfileInfo[]> callback) {
+    public void getAllProfiles(String cardId, ResultCallback<EuiccProfileInfo[]> callback) {
         try {
-            getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(),
+            getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(), cardId,
                     new IGetAllProfilesCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccProfileInfo[] profiles) {
@@ -162,12 +163,13 @@
     /**
      * Gets the profile of the given iccid.
      *
+     * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param callback The callback to get the result code and profile.
      */
-    public void getProfile(String iccid, ResultCallback<EuiccProfileInfo> callback) {
+    public void getProfile(String cardId, String iccid, ResultCallback<EuiccProfileInfo> callback) {
         try {
-            getIEuiccCardController().getProfile(mContext.getOpPackageName(), iccid,
+            getIEuiccCardController().getProfile(mContext.getOpPackageName(), cardId, iccid,
                     new IGetProfileCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccProfileInfo profile) {
@@ -183,14 +185,16 @@
     /**
      * Disables the profile of the given iccid.
      *
+     * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param refresh Whether sending the REFRESH command to modem.
      * @param callback The callback to get the result code.
      */
-    public void disableProfile(String iccid, boolean refresh, ResultCallback<Void> callback) {
+    public void disableProfile(String cardId, String iccid, boolean refresh,
+            ResultCallback<Void> callback) {
         try {
-            getIEuiccCardController().disableProfile(mContext.getOpPackageName(), iccid, refresh,
-                    new IDisableProfileCallback.Stub() {
+            getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
+                    refresh, new IDisableProfileCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode) {
                             callback.onComplete(resultCode, null);
@@ -206,15 +210,16 @@
      * Switches from the current profile to another profile. The current profile will be disabled
      * and the specified profile will be enabled.
      *
+     * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile to switch to.
      * @param refresh Whether sending the REFRESH command to modem.
      * @param callback The callback to get the result code and the EuiccProfileInfo enabled.
      */
-    public void switchToProfile(String iccid, boolean refresh,
+    public void switchToProfile(String cardId, String iccid, boolean refresh,
             ResultCallback<EuiccProfileInfo> callback) {
         try {
-            getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), iccid, refresh,
-                    new ISwitchToProfileCallback.Stub() {
+            getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), cardId, iccid,
+                    refresh, new ISwitchToProfileCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccProfileInfo profile) {
                             callback.onComplete(resultCode, profile);
@@ -227,30 +232,18 @@
     }
 
     /**
-     * Gets the EID of the eUICC.
-     *
-     * @return The EID.
-     */
-    public String getEid() {
-        try {
-            return getIEuiccCardController().getEid();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling getEid", e);
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Sets the nickname of the profile of the given iccid.
      *
+     * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param nickname The nickname of the profile.
      * @param callback The callback to get the result code.
      */
-    public void setNickname(String iccid, String nickname, ResultCallback<Void> callback) {
+    public void setNickname(String cardId, String iccid, String nickname,
+            ResultCallback<Void> callback) {
         try {
-            getIEuiccCardController().setNickname(mContext.getOpPackageName(), iccid, nickname,
-                    new ISetNicknameCallback.Stub() {
+            getIEuiccCardController().setNickname(mContext.getOpPackageName(), cardId, iccid,
+                    nickname, new ISetNicknameCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode) {
                             callback.onComplete(resultCode, null);
@@ -265,12 +258,13 @@
     /**
      * Deletes the profile of the given iccid from eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param iccid The iccid of the profile.
      * @param callback The callback to get the result code.
      */
-    public void deleteProfile(String iccid, ResultCallback<Void> callback) {
+    public void deleteProfile(String cardId, String iccid, ResultCallback<Void> callback) {
         try {
-            getIEuiccCardController().deleteProfile(mContext.getOpPackageName(), iccid,
+            getIEuiccCardController().deleteProfile(mContext.getOpPackageName(), cardId, iccid,
                     new IDeleteProfileCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode) {
@@ -286,13 +280,14 @@
     /**
      * Resets the eUICC memory.
      *
+     * @param cardId The Id of the eUICC.
      * @param options Bits of the options of resetting which parts of the eUICC memory. See
      *     EuiccCard for details.
      * @param callback The callback to get the result code.
      */
-    public void resetMemory(@ResetOption int options, ResultCallback<Void> callback) {
+    public void resetMemory(String cardId, @ResetOption int options, ResultCallback<Void> callback) {
         try {
-            getIEuiccCardController().resetMemory(mContext.getOpPackageName(), options,
+            getIEuiccCardController().resetMemory(mContext.getOpPackageName(), cardId, options,
                     new IResetMemoryCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode) {
@@ -308,11 +303,12 @@
     /**
      * Gets the default SM-DP+ address from eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback The callback to get the result code and the default SM-DP+ address.
      */
-    public void getDefaultSmdpAddress(ResultCallback<String> callback) {
+    public void getDefaultSmdpAddress(String cardId, ResultCallback<String> callback) {
         try {
-            getIEuiccCardController().getDefaultSmdpAddress(mContext.getOpPackageName(),
+            getIEuiccCardController().getDefaultSmdpAddress(mContext.getOpPackageName(), cardId,
                     new IGetDefaultSmdpAddressCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, String address) {
@@ -328,11 +324,12 @@
     /**
      * Gets the SM-DS address from eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback The callback to get the result code and the SM-DS address.
      */
-    public void getSmdsAddress(ResultCallback<String> callback) {
+    public void getSmdsAddress(String cardId, ResultCallback<String> callback) {
         try {
-            getIEuiccCardController().getSmdsAddress(mContext.getOpPackageName(),
+            getIEuiccCardController().getSmdsAddress(mContext.getOpPackageName(), cardId,
                     new IGetSmdsAddressCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, String address) {
@@ -348,12 +345,13 @@
     /**
      * Sets the default SM-DP+ address of eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param defaultSmdpAddress The default SM-DP+ address to set.
      * @param callback The callback to get the result code.
      */
-    public void setDefaultSmdpAddress(String defaultSmdpAddress, ResultCallback<Void> callback) {
+    public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress, ResultCallback<Void> callback) {
         try {
-            getIEuiccCardController().setDefaultSmdpAddress(mContext.getOpPackageName(),
+            getIEuiccCardController().setDefaultSmdpAddress(mContext.getOpPackageName(), cardId,
                     defaultSmdpAddress,
                     new ISetDefaultSmdpAddressCallback.Stub() {
                         @Override
@@ -370,11 +368,12 @@
     /**
      * Gets Rules Authorisation Table.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback the callback to get the result code and the rule authorisation table.
      */
-    public void getRulesAuthTable(ResultCallback<EuiccRulesAuthTable> callback) {
+    public void getRulesAuthTable(String cardId, ResultCallback<EuiccRulesAuthTable> callback) {
         try {
-            getIEuiccCardController().getRulesAuthTable(mContext.getOpPackageName(),
+            getIEuiccCardController().getRulesAuthTable(mContext.getOpPackageName(), cardId,
                     new IGetRulesAuthTableCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccRulesAuthTable rat) {
@@ -390,11 +389,12 @@
     /**
      * Gets the eUICC challenge for new profile downloading.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback the callback to get the result code and the challenge.
      */
-    public void getEuiccChallenge(ResultCallback<byte[]> callback) {
+    public void getEuiccChallenge(String cardId, ResultCallback<byte[]> callback) {
         try {
-            getIEuiccCardController().getEuiccChallenge(mContext.getOpPackageName(),
+            getIEuiccCardController().getEuiccChallenge(mContext.getOpPackageName(), cardId,
                     new IGetEuiccChallengeCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, byte[] challenge) {
@@ -410,11 +410,12 @@
     /**
      * Gets the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback the callback to get the result code and the info1.
      */
-    public void getEuiccInfo1(ResultCallback<byte[]> callback) {
+    public void getEuiccInfo1(String cardId, ResultCallback<byte[]> callback) {
         try {
-            getIEuiccCardController().getEuiccInfo1(mContext.getOpPackageName(),
+            getIEuiccCardController().getEuiccInfo1(mContext.getOpPackageName(), cardId,
                     new IGetEuiccInfo1Callback.Stub() {
                         @Override
                         public void onComplete(int resultCode, byte[] info) {
@@ -430,11 +431,12 @@
     /**
      * Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading.
      *
+     * @param cardId The Id of the eUICC.
      * @param callback the callback to get the result code and the info2.
      */
-    public void getEuiccInfo2(ResultCallback<byte[]> callback) {
+    public void getEuiccInfo2(String cardId, ResultCallback<byte[]> callback) {
         try {
-            getIEuiccCardController().getEuiccInfo2(mContext.getOpPackageName(),
+            getIEuiccCardController().getEuiccInfo2(mContext.getOpPackageName(), cardId,
                     new IGetEuiccInfo2Callback.Stub() {
                         @Override
                         public void onComplete(int resultCode, byte[] info) {
@@ -450,6 +452,7 @@
     /**
      * Authenticates the SM-DP+ server by the eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param matchingId the activation code token defined in GSMA RSP v2.0+ or empty when it is not
      *     required.
      * @param serverSigned1 ASN.1 data in byte array signed and returned by the SM-DP+ server.
@@ -463,12 +466,13 @@
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+.
      */
-    public void authenticateServer(String matchingId, byte[] serverSigned1,
+    public void authenticateServer(String cardId, String matchingId, byte[] serverSigned1,
             byte[] serverSignature1, byte[] euiccCiPkIdToBeUsed, byte[] serverCertificate,
             ResultCallback<byte[]> callback) {
         try {
             getIEuiccCardController().authenticateServer(
                     mContext.getOpPackageName(),
+                    cardId,
                     matchingId,
                     serverSigned1,
                     serverSignature1,
@@ -489,6 +493,7 @@
     /**
      * Prepares the profile download request sent to SM-DP+.
      *
+     * @param cardId The Id of the eUICC.
      * @param hashCc the hash of confirmation code. It can be null if there is no confirmation code
      *     required.
      * @param smdpSigned2 ASN.1 data in byte array indicating the data to be signed by the SM-DP+
@@ -500,11 +505,12 @@
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+
      */
-    public void prepareDownload(@Nullable byte[] hashCc, byte[] smdpSigned2,
+    public void prepareDownload(String cardId, @Nullable byte[] hashCc, byte[] smdpSigned2,
             byte[] smdpSignature2, byte[] smdpCertificate, ResultCallback<byte[]> callback) {
         try {
             getIEuiccCardController().prepareDownload(
                     mContext.getOpPackageName(),
+                    cardId,
                     hashCc,
                     smdpSigned2,
                     smdpSignature2,
@@ -524,15 +530,17 @@
     /**
      * Loads a downloaded bound profile package onto the eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server.
      * @param callback the callback to get the result code and a byte array which represents a
      *     {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+.
      */
-    public void loadBoundProfilePackage(byte[] boundProfilePackage,
+    public void loadBoundProfilePackage(String cardId, byte[] boundProfilePackage,
             ResultCallback<byte[]> callback) {
         try {
             getIEuiccCardController().loadBoundProfilePackage(
                     mContext.getOpPackageName(),
+                    cardId,
                     boundProfilePackage,
                     new ILoadBoundProfilePackageCallback.Stub() {
                         @Override
@@ -549,16 +557,18 @@
     /**
      * Cancels the current profile download session.
      *
+     * @param cardId The Id of the eUICC.
      * @param transactionId the transaction ID returned by SM-DP+ server.
      * @param reason the cancel reason.
      * @param callback the callback to get the result code and an byte[] which represents a
      *     {@code CancelSessionResponse} defined in GSMA RSP v2.0+.
      */
-    public void cancelSession(byte[] transactionId, @CancelReason int reason,
+    public void cancelSession(String cardId, byte[] transactionId, @CancelReason int reason,
             ResultCallback<byte[]> callback) {
         try {
             getIEuiccCardController().cancelSession(
                     mContext.getOpPackageName(),
+                    cardId,
                     transactionId,
                     reason,
                     new ICancelSessionCallback.Stub() {
@@ -576,13 +586,14 @@
     /**
      * Lists all notifications of the given {@code notificationEvents}.
      *
+     * @param cardId The Id of the eUICC.
      * @param events bits of the event types ({@link EuiccNotification.Event}) to list.
      * @param callback the callback to get the result code and the list of notifications.
      */
-    public void listNotifications(@EuiccNotification.Event int events,
+    public void listNotifications(String cardId, @EuiccNotification.Event int events,
             ResultCallback<EuiccNotification[]> callback) {
         try {
-            getIEuiccCardController().listNotifications(mContext.getOpPackageName(), events,
+            getIEuiccCardController().listNotifications(mContext.getOpPackageName(), cardId, events,
                     new IListNotificationsCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccNotification[] notifications) {
@@ -598,14 +609,15 @@
     /**
      * Retrieves contents of all notification of the given {@code events}.
      *
+     * @param cardId The Id of the eUICC.
      * @param events bits of the event types ({@link EuiccNotification.Event}) to list.
      * @param callback the callback to get the result code and the list of notifications.
      */
-    public void retrieveNotificationList(@EuiccNotification.Event int events,
+    public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events,
             ResultCallback<EuiccNotification[]> callback) {
         try {
-            getIEuiccCardController().retrieveNotificationList(mContext.getOpPackageName(), events,
-                    new IRetrieveNotificationListCallback.Stub() {
+            getIEuiccCardController().retrieveNotificationList(mContext.getOpPackageName(), cardId,
+                    events, new IRetrieveNotificationListCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccNotification[] notifications) {
                             callback.onComplete(resultCode, notifications);
@@ -620,13 +632,15 @@
     /**
      * Retrieves the content of a notification of the given {@code seqNumber}.
      *
+     * @param cardId The Id of the eUICC.
      * @param seqNumber the sequence number of the notification.
      * @param callback the callback to get the result code and the notification.
      */
-    public void retrieveNotification(int seqNumber, ResultCallback<EuiccNotification> callback) {
+    public void retrieveNotification(String cardId, int seqNumber,
+            ResultCallback<EuiccNotification> callback) {
         try {
-            getIEuiccCardController().retrieveNotification(mContext.getOpPackageName(), seqNumber,
-                    new IRetrieveNotificationCallback.Stub() {
+            getIEuiccCardController().retrieveNotification(mContext.getOpPackageName(), cardId,
+                    seqNumber, new IRetrieveNotificationCallback.Stub() {
                         @Override
                         public void onComplete(int resultCode, EuiccNotification notification) {
                             callback.onComplete(resultCode, notification);
@@ -641,13 +655,16 @@
     /**
      * Removes a notification from eUICC.
      *
+     * @param cardId The Id of the eUICC.
      * @param seqNumber the sequence number of the notification.
      * @param callback the callback to get the result code.
      */
-    public void removeNotificationFromList(int seqNumber, ResultCallback<Void> callback) {
+    public void removeNotificationFromList(String cardId, int seqNumber,
+            ResultCallback<Void> callback) {
         try {
             getIEuiccCardController().removeNotificationFromList(
                     mContext.getOpPackageName(),
+                    cardId,
                     seqNumber,
                     new IRemoveNotificationFromListCallback.Stub() {
                         @Override
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index d146707..7f913ce 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -598,7 +599,11 @@
         }
     }
 
-    private static IEuiccController getIEuiccController() {
+    /**
+     * @hide
+     */
+    @TestApi
+    protected IEuiccController getIEuiccController() {
         return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index abc55c7..e33f44c 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -41,42 +41,49 @@
 
 /** @hide */
 interface IEuiccCardController {
-    oneway void getAllProfiles(String callingPackage, in IGetAllProfilesCallback callback);
-    oneway void getProfile(String callingPackage, String iccid, in IGetProfileCallback callback);
-    oneway void disableProfile(String callingPackage, String iccid, boolean refresh,
+    oneway void getAllProfiles(String callingPackage, String cardId,
+        in IGetAllProfilesCallback callback);
+    oneway void getProfile(String callingPackage, String cardId, String iccid,
+        in IGetProfileCallback callback);
+    oneway void disableProfile(String callingPackage, String cardId, String iccid, boolean refresh,
         in IDisableProfileCallback callback);
-    oneway void switchToProfile(String callingPackage, String iccid, boolean refresh,
+    oneway void switchToProfile(String callingPackage, String cardId, String iccid, boolean refresh,
         in ISwitchToProfileCallback callback);
-    String getEid();
-    oneway void setNickname(String callingPackage, String iccid, String nickname,
+    oneway void setNickname(String callingPackage, String cardId, String iccid, String nickname,
         in ISetNicknameCallback callback);
-    oneway void deleteProfile(String callingPackage, String iccid,
+    oneway void deleteProfile(String callingPackage, String cardId, String iccid,
         in IDeleteProfileCallback callback);
-    oneway void resetMemory(String callingPackage, int options, in IResetMemoryCallback callback);
-    oneway void getDefaultSmdpAddress(String callingPackage,
+    oneway void resetMemory(String callingPackage, String cardId, int options, in IResetMemoryCallback callback);
+    oneway void getDefaultSmdpAddress(String callingPackage, String cardId,
         in IGetDefaultSmdpAddressCallback callback);
-    oneway void getSmdsAddress(String callingPackage, in IGetSmdsAddressCallback callback);
-    oneway void setDefaultSmdpAddress(String callingPackage, String address,
+    oneway void getSmdsAddress(String callingPackage, String cardId,
+        in IGetSmdsAddressCallback callback);
+    oneway void setDefaultSmdpAddress(String callingPackage, String cardId, String address,
         in ISetDefaultSmdpAddressCallback callback);
-    oneway void getRulesAuthTable(String callingPackage, in IGetRulesAuthTableCallback callback);
-    oneway void getEuiccChallenge(String callingPackage, in IGetEuiccChallengeCallback callback);
-    oneway void getEuiccInfo1(String callingPackage, in IGetEuiccInfo1Callback callback);
-    oneway void getEuiccInfo2(String callingPackage, in IGetEuiccInfo2Callback callback);
-    oneway void authenticateServer(String callingPackage, String matchingId,
+    oneway void getRulesAuthTable(String callingPackage, String cardId,
+        in IGetRulesAuthTableCallback callback);
+    oneway void getEuiccChallenge(String callingPackage, String cardId,
+        in IGetEuiccChallengeCallback callback);
+    oneway void getEuiccInfo1(String callingPackage, String cardId,
+        in IGetEuiccInfo1Callback callback);
+    oneway void getEuiccInfo2(String callingPackage, String cardId,
+        in IGetEuiccInfo2Callback callback);
+    oneway void authenticateServer(String callingPackage, String cardId, String matchingId,
         in byte[] serverSigned1, in byte[] serverSignature1, in byte[] euiccCiPkIdToBeUsed,
         in byte[] serverCertificatein, in IAuthenticateServerCallback callback);
-    oneway void prepareDownload(String callingPackage, in byte[] hashCc, in byte[] smdpSigned2,
-        in byte[] smdpSignature2, in byte[] smdpCertificate, in IPrepareDownloadCallback callback);
-    oneway void loadBoundProfilePackage(String callingPackage, in byte[] boundProfilePackage,
-        in ILoadBoundProfilePackageCallback callback);
-    oneway void cancelSession(String callingPackage, in byte[] transactionId, int reason,
-        in ICancelSessionCallback callback);
-    oneway void listNotifications(String callingPackage, int events,
+    oneway void prepareDownload(String callingPackage, String cardId, in byte[] hashCc,
+        in byte[] smdpSigned2, in byte[] smdpSignature2, in byte[] smdpCertificate,
+        in IPrepareDownloadCallback callback);
+    oneway void loadBoundProfilePackage(String callingPackage, String cardId,
+        in byte[] boundProfilePackage, in ILoadBoundProfilePackageCallback callback);
+    oneway void cancelSession(String callingPackage, String cardId, in byte[] transactionId,
+        int reason, in ICancelSessionCallback callback);
+    oneway void listNotifications(String callingPackage, String cardId, int events,
         in IListNotificationsCallback callback);
-    oneway void retrieveNotificationList(String callingPackage, int events,
+    oneway void retrieveNotificationList(String callingPackage, String cardId, int events,
         in IRetrieveNotificationListCallback callback);
-    oneway void retrieveNotification(String callingPackage, int seqNumber,
+    oneway void retrieveNotification(String callingPackage, String cardId, int seqNumber,
         in IRetrieveNotificationCallback callback);
-    oneway void removeNotificationFromList(String callingPackage, int seqNumber,
+    oneway void removeNotificationFromList(String callingPackage, String cardId, int seqNumber,
             in IRemoveNotificationFromListCallback callback);
 }
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 41cde17..1ddc52c 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -1196,4 +1196,17 @@
     public CharSequence getHarmfulAppWarning(String packageName) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean hasSigningCertificate(
+            String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasSigningCertificate(
+            int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
+        throw new UnsupportedOperationException();
+    }
+
 }
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index cd2d098..2e1519b 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -33,12 +33,15 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -180,4 +183,84 @@
         assertEquals(20, NetworkCapabilities
                 .maxBandwidth(10, 20));
     }
+
+    @Test
+    public void testSetUids() {
+        final NetworkCapabilities netCap = new NetworkCapabilities();
+        final Set<UidRange> uids = new ArraySet<>();
+        uids.add(new UidRange(50, 100));
+        uids.add(new UidRange(3000, 4000));
+        netCap.setUids(uids);
+        assertTrue(netCap.appliesToUid(50));
+        assertTrue(netCap.appliesToUid(80));
+        assertTrue(netCap.appliesToUid(100));
+        assertTrue(netCap.appliesToUid(3000));
+        assertTrue(netCap.appliesToUid(3001));
+        assertFalse(netCap.appliesToUid(10));
+        assertFalse(netCap.appliesToUid(25));
+        assertFalse(netCap.appliesToUid(49));
+        assertFalse(netCap.appliesToUid(101));
+        assertFalse(netCap.appliesToUid(2000));
+        assertFalse(netCap.appliesToUid(100000));
+
+        assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
+        assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
+        assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
+        assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
+        assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
+        assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
+        assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
+        assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
+
+        NetworkCapabilities netCap2 = new NetworkCapabilities();
+        assertFalse(netCap2.satisfiedByUids(netCap));
+        assertFalse(netCap2.equalsUids(netCap));
+        netCap2.setUids(uids);
+        assertTrue(netCap2.satisfiedByUids(netCap));
+        assertTrue(netCap.equalsUids(netCap2));
+        assertTrue(netCap2.equalsUids(netCap));
+
+        uids.add(new UidRange(600, 700));
+        netCap2.setUids(uids);
+        assertFalse(netCap2.satisfiedByUids(netCap));
+        assertFalse(netCap.appliesToUid(650));
+        assertTrue(netCap2.appliesToUid(650));
+        netCap.combineCapabilities(netCap2);
+        assertTrue(netCap2.satisfiedByUids(netCap));
+        assertTrue(netCap.appliesToUid(650));
+        assertFalse(netCap.appliesToUid(500));
+
+        assertFalse(new NetworkCapabilities().satisfiedByUids(netCap));
+        netCap.combineCapabilities(new NetworkCapabilities());
+        assertTrue(netCap.appliesToUid(500));
+        assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
+        assertFalse(netCap2.appliesToUid(500));
+        assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
+        assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+    }
+
+    @Test
+    public void testParcelNetworkCapabilities() {
+        final Set<UidRange> uids = new ArraySet<>();
+        uids.add(new UidRange(50, 100));
+        uids.add(new UidRange(3000, 4000));
+        final NetworkCapabilities netCap = new NetworkCapabilities()
+            .addCapability(NET_CAPABILITY_INTERNET)
+            .setUids(uids)
+            .addCapability(NET_CAPABILITY_EIMS)
+            .addCapability(NET_CAPABILITY_NOT_METERED);
+        assertEqualsThroughMarshalling(netCap);
+    }
+
+    private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
+        Parcel p = Parcel.obtain();
+        netCap.writeToParcel(p, /* flags */ 0);
+        p.setDataPosition(0);
+        byte[] marshalledData = p.marshall();
+
+        p = Parcel.obtain();
+        p.unmarshall(marshalledData, 0, marshalledData.length);
+        p.setDataPosition(0);
+        assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap);
+    }
 }
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index 56b8e60..b14f550 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -67,7 +67,7 @@
             IoUtils.deleteContents(mTestProc);
         }
 
-        mFactory = new NetworkStatsFactory(mTestProc);
+        mFactory = new NetworkStatsFactory(mTestProc, false);
     }
 
     @After
@@ -116,6 +116,20 @@
     }
 
     @Test
+    public void testNetworkStatsSummary() throws Exception {
+        stageFile(R.raw.net_dev_typical, file("net/dev"));
+
+        final NetworkStats stats = mFactory.readNetworkStatsIfaceDev();
+        assertEquals(6, stats.size());
+        assertStatsEntry(stats, "lo", UID_ALL, SET_ALL, TAG_NONE, 8308L, 8308L);
+        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L, 489339L);
+        assertStatsEntry(stats, "ifb0", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
+        assertStatsEntry(stats, "ifb1", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
+        assertStatsEntry(stats, "sit0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
+        assertStatsEntry(stats, "ip6tnl0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
+    }
+
+    @Test
     public void testNetworkStatsSingle() throws Exception {
         stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
 
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 70cacb3..6e643a3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -44,6 +44,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
 
@@ -101,6 +102,7 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
+import android.net.UidRange;
 import android.net.metrics.IpConnectivityLog;
 import android.net.util.MultinetworkPolicyTracker;
 import android.os.ConditionVariable;
@@ -126,11 +128,13 @@
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.ConnectivityConstants;
 import com.android.server.connectivity.DefaultNetworkMetrics;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
 
@@ -360,7 +364,7 @@
 
         MockNetworkAgent(int transport, LinkProperties linkProperties) {
             final int type = transportToLegacyType(transport);
-            final String typeName = ConnectivityManager.getNetworkTypeName(type);
+            final String typeName = ConnectivityManager.getNetworkTypeName(transport);
             mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
             mNetworkCapabilities = new NetworkCapabilities();
             mNetworkCapabilities.addTransportType(transport);
@@ -377,6 +381,9 @@
                 case TRANSPORT_WIFI_AWARE:
                     mScore = 20;
                     break;
+                case TRANSPORT_VPN:
+                    mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
+                    break;
                 default:
                     throw new UnsupportedOperationException("unimplemented network type");
             }
@@ -438,6 +445,11 @@
             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
         }
 
+        public void setUids(Set<UidRange> uids) {
+            mNetworkCapabilities.setUids(uids);
+            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+        }
+
         public void setSignalStrength(int signalStrength) {
             mNetworkCapabilities.setSignalStrength(signalStrength);
             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
@@ -1463,6 +1475,11 @@
             return nc;
         }
 
+        void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
+            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+            assertTrue(fn.test((NetworkCapabilities) cbi.arg));
+        }
+
         void assertNoCallback() {
             waitForIdle();
             CallbackInfo c = mCallbacks.peek();
@@ -3625,4 +3642,76 @@
             return;
         }
     }
+
+    @Test
+    public void testVpnNetworkActive() {
+        final int uid = Process.myUid();
+
+        final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+        final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+        final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest genericRequest = new NetworkRequest.Builder().build();
+        final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI).build();
+        final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_VPN).build();
+        mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+        mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+        mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+
+        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        vpnNetworkCallback.assertNoCallback();
+
+        // TODO : check callbacks agree with the return value of mCm.getActiveNetwork().
+        // Right now this is not possible because establish() is not adequately instrumented
+        // in this test.
+
+        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        vpnNetworkAgent.setUids(ranges);
+        vpnNetworkAgent.connect(false);
+
+        genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+        wifiNetworkCallback.assertNoCallback();
+        vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+
+        genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+        vpnNetworkCallback.expectCapabilitiesLike(
+                nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent);
+
+        ranges.clear();
+        vpnNetworkAgent.setUids(ranges);
+
+        genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        wifiNetworkCallback.assertNoCallback();
+        vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+
+        ranges.add(new UidRange(uid, uid));
+        vpnNetworkAgent.setUids(ranges);
+
+        genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+        wifiNetworkCallback.assertNoCallback();
+        vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+
+        mWiFiNetworkAgent.disconnect();
+
+        genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        vpnNetworkCallback.assertNoCallback();
+
+        vpnNetworkAgent.disconnect();
+
+        genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        wifiNetworkCallback.assertNoCallback();
+        vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+
+        mCm.unregisterNetworkCallback(genericNetworkCallback);
+        mCm.unregisterNetworkCallback(wifiNetworkCallback);
+        mCm.unregisterNetworkCallback(vpnNetworkCallback);
+    }
 }
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 1618e07..801a396 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -136,7 +136,12 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
+                        eq(spiResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
         IpSecService.UserRecord userRecord =
@@ -168,7 +173,12 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
+                        eq(spiResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
@@ -221,6 +231,8 @@
                         anyString(),
                         anyLong(),
                         eq(TEST_SPI),
+                        anyInt(),
+                        anyInt(),
                         eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
                         eq(AUTH_KEY),
                         anyInt(),
@@ -254,6 +266,8 @@
                         anyString(),
                         anyLong(),
                         eq(TEST_SPI),
+                        anyInt(),
+                        anyInt(),
                         eq(""),
                         eq(new byte[] {}),
                         eq(0),
@@ -305,7 +319,12 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
+                        eq(createTransformResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
         IpSecService.UserRecord userRecord =
@@ -339,7 +358,12 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
+                        eq(createTransformResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index a375b60..2c94a60 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -635,4 +635,25 @@
         verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
         mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
     }
+
+    @Test
+    public void testReserveNetId() {
+        int start = mIpSecService.TUN_INTF_NETID_START;
+        for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
+            assertEquals(start + i, mIpSecService.reserveNetId());
+        }
+
+        // Check that resource exhaustion triggers an exception
+        try {
+            mIpSecService.reserveNetId();
+            fail("Did not throw error for all netIds reserved");
+        } catch (IllegalStateException expected) {
+        }
+
+        // Now release one and try again
+        int releasedNetId =
+                mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
+        mIpSecService.releaseNetId(releasedNetId);
+        assertEquals(releasedNetId, mIpSecService.reserveNetId());
+    }
 }
diff --git a/tests/net/res/raw/net_dev_typical b/tests/net/res/raw/net_dev_typical
new file mode 100644
index 0000000..290bf03
--- /dev/null
+++ b/tests/net/res/raw/net_dev_typical
@@ -0,0 +1,8 @@
+Inter-|   Receive                                                |  Transmit
+ face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
+    lo:    8308     116    0    0    0     0          0         0     8308     116    0    0    0     0       0          0
+rmnet0: 1507570    2205    0    0    0     0          0         0   489339    2237    0    0    0     0       0          0
+  ifb0:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
+  ifb1:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
+  sit0:       0       0    0    0    0     0          0         0        0       0  148    0    0     0       0          0
+ip6tnl0:       0       0    0    0    0     0          0         0        0       0  151  151    0     0       0          0
diff --git a/tests/notification/Android.mk b/tests/notification/Android.mk
index 0669553..255e6e7 100644
--- a/tests/notification/Android.mk
+++ b/tests/notification/Android.mk
@@ -7,7 +7,7 @@
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
 LOCAL_PACKAGE_NAME := NotificationTests
 
 LOCAL_SDK_VERSION := 21
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
index ee0e36c..81a0773 100644
--- a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
@@ -18,7 +18,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.commons.TryCatchBlockSorter;
@@ -101,7 +100,7 @@
             try {
                 a.analyze(owner, mn);
             } catch (AnalyzerException e) {
-                e.printStackTrace();
+                throw new RuntimeException("Locked region code injection: " + e.getMessage(), e);
             }
             InsnList instructions = mn.instructions;
 
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index e9e61a5..101b3e2 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -66,11 +66,11 @@
 
     List<OsuProvider> getMatchingOsuProviders(in ScanResult scanResult);
 
-    int addOrUpdateNetwork(in WifiConfiguration config);
+    int addOrUpdateNetwork(in WifiConfiguration config, String packageName);
 
-    boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
+    boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config, String packageName);
 
-    boolean removePasspointConfiguration(in String fqdn);
+    boolean removePasspointConfiguration(in String fqdn, String packageName);
 
     List<PasspointConfiguration> getPasspointConfigurations();
 
@@ -80,21 +80,21 @@
 
     void deauthenticateNetwork(long holdoff, boolean ess);
 
-    boolean removeNetwork(int netId);
+    boolean removeNetwork(int netId, String packageName);
 
-    boolean enableNetwork(int netId, boolean disableOthers);
+    boolean enableNetwork(int netId, boolean disableOthers, String packageName);
 
-    boolean disableNetwork(int netId);
+    boolean disableNetwork(int netId, String packageName);
 
-    void startScan(in ScanSettings requested, in WorkSource ws, in String packageName);
+    void startScan(in ScanSettings requested, in WorkSource ws, String packageName);
 
     List<ScanResult> getScanResults(String callingPackage);
 
-    void disconnect();
+    void disconnect(String packageName);
 
-    void reconnect();
+    void reconnect(String packageName);
 
-    void reassociate();
+    void reassociate(String packageName);
 
     WifiInfo getConnectionInfo(String callingPackage);
 
@@ -108,7 +108,7 @@
 
     boolean isDualBandSupported();
 
-    boolean saveConfiguration();
+    boolean saveConfiguration(String packageName);
 
     DhcpInfo getDhcpInfo();
 
@@ -134,7 +134,7 @@
 
     boolean stopSoftAp();
 
-    int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, in String packageName);
+    int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName);
 
     void stopLocalOnlyHotspot();
 
@@ -146,9 +146,9 @@
 
     WifiConfiguration getWifiApConfiguration();
 
-    void setWifiApConfiguration(in WifiConfiguration wifiConfig);
+    void setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
 
-    Messenger getWifiServiceMessenger();
+    Messenger getWifiServiceMessenger(String packageName);
 
     void enableTdls(String remoteIPAddress, boolean enable);
 
@@ -165,9 +165,9 @@
 
     void enableWifiConnectivityManager(boolean enabled);
 
-    void disableEphemeralNetwork(String SSID);
+    void disableEphemeralNetwork(String SSID, String packageName);
 
-    void factoryReset();
+    void factoryReset(String packageName);
 
     Network getCurrentNetwork();
 
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index eaad137..c46789c 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -294,18 +294,6 @@
     }
 
     /**
-     * num IP configuration failures
-     * @hide
-     */
-    public int numIpConfigFailures;
-
-    /**
-     * @hide
-     * Last time we blacklisted the ScanResult
-     */
-    public long blackListTimestamp;
-
-    /**
      * Status indicating the scan result does not correspond to a user's saved configuration
      * @hide
      * @removed
@@ -314,12 +302,6 @@
     public boolean untrusted;
 
     /**
-     * Number of time we connected to it
-     * @hide
-     */
-    public int numConnection;
-
-    /**
      * Number of time autojoin used it
      * @hide
      */
@@ -432,12 +414,6 @@
      */
     public List<String> anqpLines;
 
-    /**
-     *  @hide
-     * storing the raw bytes of full result IEs
-     **/
-    public byte[] bytes;
-
     /** information elements from beacon
      * @hide
      */
@@ -612,9 +588,7 @@
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
             untrusted = source.untrusted;
-            numConnection = source.numConnection;
             numUsage = source.numUsage;
-            numIpConfigFailures = source.numIpConfigFailures;
             venueName = source.venueName;
             operatorFriendlyName = source.operatorFriendlyName;
             flags = source.flags;
@@ -697,9 +671,7 @@
         dest.writeInt(centerFreq1);
         dest.writeLong(seen);
         dest.writeInt(untrusted ? 1 : 0);
-        dest.writeInt(numConnection);
         dest.writeInt(numUsage);
-        dest.writeInt(numIpConfigFailures);
         dest.writeString((venueName != null) ? venueName.toString() : "");
         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
         dest.writeLong(this.flags);
@@ -779,9 +751,7 @@
 
                 sr.seen = in.readLong();
                 sr.untrusted = in.readInt() != 0;
-                sr.numConnection = in.readInt();
                 sr.numUsage = in.readInt();
-                sr.numIpConfigFailures = in.readInt();
                 sr.venueName = in.readString();
                 sr.operatorFriendlyName = in.readString();
                 sr.flags = in.readLong();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e4b510d..50ae905 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1132,7 +1132,7 @@
      */
     private int addOrUpdateNetwork(WifiConfiguration config) {
         try {
-            return mService.addOrUpdateNetwork(config);
+            return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1153,7 +1153,7 @@
      */
     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
-            if (!mService.addOrUpdatePasspointConfiguration(config)) {
+            if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
                 throw new IllegalArgumentException();
             }
         } catch (RemoteException e) {
@@ -1170,7 +1170,7 @@
      */
     public void removePasspointConfiguration(String fqdn) {
         try {
-            if (!mService.removePasspointConfiguration(fqdn)) {
+            if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
                 throw new IllegalArgumentException();
             }
         } catch (RemoteException e) {
@@ -1256,7 +1256,7 @@
      */
     public boolean removeNetwork(int netId) {
         try {
-            return mService.removeNetwork(netId);
+            return mService.removeNetwork(netId, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1302,7 +1302,7 @@
 
         boolean success;
         try {
-            success = mService.enableNetwork(netId, attemptConnect);
+            success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1328,7 +1328,7 @@
      */
     public boolean disableNetwork(int netId) {
         try {
-            return mService.disableNetwork(netId);
+            return mService.disableNetwork(netId, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1341,7 +1341,7 @@
      */
     public boolean disconnect() {
         try {
-            mService.disconnect();
+            mService.disconnect(mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1356,7 +1356,7 @@
      */
     public boolean reconnect() {
         try {
-            mService.reconnect();
+            mService.reconnect(mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1371,7 +1371,7 @@
      */
     public boolean reassociate() {
         try {
-            mService.reassociate();
+            mService.reassociate(mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1701,7 +1701,7 @@
     @Deprecated
     public boolean saveConfiguration() {
         try {
-            return mService.saveConfiguration();
+            return mService.saveConfiguration(mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2136,7 +2136,7 @@
     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
         try {
-            mService.setWifiApConfiguration(wifiConfig);
+            mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -3052,7 +3052,7 @@
     public void disableEphemeralNetwork(String SSID) {
         if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
         try {
-            mService.disableEphemeralNetwork(SSID);
+            mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3093,7 +3093,7 @@
      */
     public Messenger getWifiServiceMessenger() {
         try {
-            return mService.getWifiServiceMessenger();
+            return mService.getWifiServiceMessenger(mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3619,7 +3619,7 @@
      */
     public void factoryReset() {
         try {
-            mService.factoryReset();
+            mService.factoryReset(mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }