Merge "Add WatchdogRollbackOccurred atom"
diff --git a/Android.bp b/Android.bp
index a5cc89c..d4a04cc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -726,7 +726,7 @@
         "ext",
     ],
 
-    jarjar_rules: ":framework-hidl-jarjar",
+    jarjar_rules: "jarjar_rules_hidl.txt",
 
     static_libs: [
         "apex_aidl_interface-java",
@@ -738,6 +738,15 @@
         "android.hardware.cas-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.health-V1.0-java-constants",
+        "android.hardware.radio-V1.0-java",
+        "android.hardware.radio-V1.1-java",
+        "android.hardware.radio-V1.2-java",
+        "android.hardware.radio-V1.3-java",
+        "android.hardware.radio-V1.4-java",
+        "android.hardware.radio.config-V1.0-java",
+        "android.hardware.radio.config-V1.1-java",
+        "android.hardware.radio.config-V1.2-java",
+        "android.hardware.radio.deprecated-V1.0-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
@@ -746,15 +755,12 @@
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
+        "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.vibrator-V1.0-java",
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.hardware.wifi-V1.0-java-constants",
-        "android.hardware.radio-V1.0-java",
-        "android.hardware.radio-V1.3-java",
-        "android.hardware.radio-V1.4-java",
-        "android.hardware.usb.gadget-V1.0-java",
         "networkstack-aidl-interfaces-java",
         "netd_aidl_interface-java",
         "devicepolicyprotosnano",
@@ -788,11 +794,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-hidl-jarjar",
-    srcs: ["jarjar_rules_hidl.txt"],
-}
-
 java_library {
     name: "framework",
     defaults: ["framework-defaults"],
diff --git a/api/current.txt b/api/current.txt
index bb6dbeb..124ad58 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5101,7 +5101,7 @@
   }
 
   public class KeyguardManager {
-    method public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
+    method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
     method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method @Deprecated public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
@@ -13947,8 +13947,6 @@
   @AnyThread public abstract class ColorSpace {
     method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[]);
     method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[], @NonNull android.graphics.ColorSpace.Adaptation);
-    method @NonNull @Size(3) public static float[] cctToIlluminantdXyz(@IntRange(from=1) int);
-    method @NonNull @Size(9) public static float[] chromaticAdaptation(@NonNull android.graphics.ColorSpace.Adaptation, @NonNull @Size(min=2, max=3) float[], @NonNull @Size(min=2, max=3) float[]);
     method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace);
     method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace.RenderIntent);
     method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace);
@@ -16498,6 +16496,7 @@
     ctor public BiometricPrompt.Builder(android.content.Context);
     method public android.hardware.biometrics.BiometricPrompt build();
     method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
     method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
@@ -44662,6 +44661,7 @@
 
   public final class SmsManager {
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
+    method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
     method public java.util.ArrayList<java.lang.String> divideMessage(String);
     method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
     method public android.os.Bundle getCarrierConfigValues();
@@ -48568,6 +48568,7 @@
     method public String getName();
     method @Deprecated public int getOrientation();
     method @Deprecated public int getPixelFormat();
+    method @Nullable public android.graphics.ColorSpace getPreferredWideGamutColorSpace();
     method public long getPresentationDeadlineNanos();
     method public void getRealMetrics(android.util.DisplayMetrics);
     method public void getRealSize(android.graphics.Point);
diff --git a/api/system-current.txt b/api/system-current.txt
index 30d42a23..31e6c6c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1303,13 +1303,13 @@
     field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
     field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
     field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
-    field public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
     field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
     field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
     field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
+    field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
     field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
     field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
@@ -1695,18 +1695,17 @@
 
   public final class RollbackInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
     method public int getRollbackId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
-    field public final android.content.rollback.PackageRollbackInfo targetPackage;
   }
 
   public final class RollbackManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void executeRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @Nullable public android.content.rollback.RollbackInfo getAvailableRollback(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
   }
 
@@ -5534,7 +5533,6 @@
     method @Deprecated public final void attachBaseContext(android.content.Context);
     method @Deprecated public final android.os.IBinder onBind(android.content.Intent);
     method @Deprecated public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
-    method @Deprecated public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
     field @Deprecated public static final String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
   }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8642715..ac99817 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -163,7 +163,7 @@
         // Consider removing this if it becomes a problem
         ServiceStateChanged service_state_changed = 99;
         ServiceLaunchReported service_launch_reported = 100;
-        PhenotypeFlagStateChanged phenotype_flag_state_changed = 101;
+        FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
         BinaryPushStateChanged binary_push_state_changed = 102;
         DevicePolicyEvent device_policy_event = 103;
         DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
@@ -2498,18 +2498,14 @@
 }
 
 /*
- * Logs when a flag flip state changes.
- * Logged in P/h.
+ * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips.
  */
-message PhenotypeFlagStateChanged {
-    // Mendel configuration name.
-    optional string mendel_config_name = 1;
-    // State
-    enum State {
-        STATE_UNKNOWN = 0;
-        COMMITTED = 1;
-    }
-    optional State state = 2;
+message FlagFlipUpdateOccurred {
+    // If the event is from a flag config package, specify the package name.
+    optional string flag_flip_package_name = 1;
+
+    // The order id of the package
+    optional int64 order_id = 2;
 }
 
 /*
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 181acce..f522d71 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -87,6 +88,12 @@
             "android.app.action.CONFIRM_FRP_CREDENTIAL";
 
     /**
+     * @hide
+     */
+    public static final String EXTRA_BIOMETRIC_PROMPT_BUNDLE =
+            "android.app.extra.BIOMETRIC_PROMPT_BUNDLE";
+
+    /**
      * A CharSequence dialog title to show to the user when used with a
      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
      * @hide
@@ -101,12 +108,6 @@
     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
 
     /**
-     * A boolean value to forward to {@link android.hardware.biometrics.BiometricPrompt}.
-     * @hide
-     */
-    public static final String EXTRA_USE_IMPLICIT = "android.app.extra.USE_IMPLICIT";
-
-    /**
      * A CharSequence description to show to the user on the alternate button when used with
      * {@link #ACTION_CONFIRM_FRP_CREDENTIAL}.
      * @hide
@@ -124,44 +125,23 @@
     public static final int RESULT_ALTERNATE = 1;
 
     /**
-     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
-     * for the current user of the device. The caller is expected to launch this activity using
-     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+     * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)}
+     *
+     * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
+     * if enrolled) for the current user of the device. The caller is expected to launch this
+     * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
      *
-     * @param title Title to be shown on the dialog.
-     * @param description Description to be shown on the dialog.
      * @return the intent for launching the activity or null if no password is required.
      **/
+    @Deprecated
     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
-    public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
-        return createConfirmDeviceCredentialIntent(title, description, false /* useImplicit */);
-    }
-
-    /**
-     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
-     * for the current user of the device. The caller is expected to launch this activity using
-     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
-     * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
-     *
-     * @param title Title to be shown on the dialog.
-     * @param description Description to be shown on the dialog.
-     * @param useImplicit If useImplicit is set to true, ConfirmDeviceCredentials will invoke
-     *      {@link android.hardware.biometrics.BiometricPrompt} with
-     *      {@link android.hardware.biometrics.BiometricPrompt.Builder#setRequireConfirmation(
-     *      boolean)} set to false.
-     * @return the intent for launching the activity or null if no password is required.
-     * @hide
-     */
-    public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description,
-            boolean useImplicit) {
-        if (!isDeviceSecure()) {
-            return null;
-        }
+    public Intent createConfirmDeviceCredentialIntent(CharSequence title,
+            CharSequence description) {
+        if (!isDeviceSecure()) return null;
         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
         intent.putExtra(EXTRA_TITLE, title);
         intent.putExtra(EXTRA_DESCRIPTION, description);
-        intent.putExtra(EXTRA_USE_IMPLICIT, useImplicit);
 
         // explicitly set the package for security
         intent.setPackage(getSettingsPackageForIntent(intent));
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6704a45..47a4a2d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -87,6 +87,7 @@
  * <p>For more information about using a ContentResolver with content providers, read the
  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
  * developer guide.</p>
+ * </div>
  */
 public abstract class ContentResolver implements ContentInterface {
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9e7aaf6..22f73db 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2375,8 +2375,7 @@
     public static final String ACTION_PACKAGE_ENABLE_ROLLBACK =
             "android.intent.action.PACKAGE_ENABLE_ROLLBACK";
     /**
-     * Broadcast Action: An existing version of an application package has been
-     * rolled back to a previous version.
+     * Broadcast Action: A rollback has been committed.
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -2385,8 +2384,8 @@
      */
     @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
-            "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
+    public static final String ACTION_ROLLBACK_COMMITTED =
+            "android.intent.action.ROLLBACK_COMMITTED";
     /**
      * @hide
      * Broadcast Action: Ask system services if there is any reason to
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 2faf3ad..4f4c34b 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -27,5 +27,4 @@
  */
 oneway interface IRuntimePermissionPresenter {
     void getAppPermissions(String packageName, in RemoteCallback callback);
-    void revokeRuntimePermission(String packageName, String permissionName);
 }
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 420bcb6..63d75a0 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -17,17 +17,13 @@
 package android.content.rollback;
 
 import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
 import android.content.rollback.RollbackInfo;
 import android.content.IntentSender;
 
 /** {@hide} */
 interface IRollbackManager {
 
-    RollbackInfo getAvailableRollback(String packageName);
-
-    StringParceledListSlice getPackagesWithAvailableRollbacks();
-
+    ParceledListSlice getAvailableRollbacks();
     ParceledListSlice getRecentlyExecutedRollbacks();
 
     void executeRollback(in RollbackInfo rollback, String callerPackageName,
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 0803a7c..8532b5a 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -20,6 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.List;
+
 /**
  * Information about a set of packages that can be, or already have been
  * rolled back together.
@@ -34,25 +36,20 @@
      */
     private final int mRollbackId;
 
-    /**
-     * The package that needs to be rolled back.
-     */
-    public final PackageRollbackInfo targetPackage;
+    private final List<PackageRollbackInfo> mPackages;
 
-    // TODO: Add a list of additional packages rolled back due to atomic
-    // install dependencies when rollback of atomic installs is supported.
     // TODO: Add a flag to indicate if reboot is required, when rollback of
     // staged installs is supported.
 
     /** @hide */
-    public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) {
+    public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages) {
         this.mRollbackId = rollbackId;
-        this.targetPackage = targetPackage;
+        this.mPackages = packages;
     }
 
     private RollbackInfo(Parcel in) {
         mRollbackId = in.readInt();
-        targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+        mPackages = in.createTypedArrayList(PackageRollbackInfo.CREATOR);
     }
 
     /**
@@ -62,6 +59,13 @@
         return mRollbackId;
     }
 
+    /**
+     * Returns the list of package that are rolled back.
+     */
+    public List<PackageRollbackInfo> getPackages() {
+        return mPackages;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -70,7 +74,7 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mRollbackId);
-        targetPackage.writeToParcel(out, flags);
+        out.writeTypedList(mPackages);
     }
 
     public static final Parcelable.Creator<RollbackInfo> CREATOR =
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c1c0bc1..2566ac5 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -17,7 +17,6 @@
 package android.content.rollback;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -50,55 +49,26 @@
     }
 
     /**
-     * Returns the rollback currently available to be executed for the given
-     * package.
-     * <p>
-     * The returned RollbackInfo describes what packages would be rolled back,
-     * including package version codes before and after rollback. The rollback
-     * can be initiated using {@link #executeRollback(RollbackInfo,IntentSender)}.
-     * <p>
-     * TODO: What if there is no package installed on device for packageName?
+     * Returns a list of all currently available rollbacks.
      *
-     * @param packageName name of the package to get the availble RollbackInfo for.
-     * @return the rollback available for the package, or null if no rollback
-     *         is available for the package.
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
-    public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
+    public List<RollbackInfo> getAvailableRollbacks() {
         try {
-            return mBinder.getAvailableRollback(packageName);
+            return mBinder.getAvailableRollbacks().getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Gets the names of packages that are available for rollback.
-     * Call {@link #getAvailableRollback(String)} to get more information
-     * about the rollback available for a particular package.
-     *
-     * @return the names of packages that are available for rollback.
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
-     */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
-    public @NonNull List<String> getPackagesWithAvailableRollbacks() {
-        try {
-            return mBinder.getPackagesWithAvailableRollbacks().getList();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-
-    /**
-     * Gets the list of all recently executed rollbacks.
+     * Gets the list of all recently committed rollbacks.
      * This is for the purposes of preventing re-install of a bad version of a
-     * package.
+     * package and monitoring the status of a staged rollback.
      * <p>
-     * Returns an empty list if there are no recently executed rollbacks.
+     * Returns an empty list if there are no recently committed rollbacks.
      * <p>
      * To avoid having to keep around complete rollback history forever on a
      * device, the returned list of rollbacks is only guaranteed to include
@@ -107,12 +77,12 @@
      * (without the possibility of rollback) to a higher version code than was
      * rolled back from.
      *
-     * @return the recently executed rollbacks
+     * @return the recently committed rollbacks
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
-    public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
+    public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
         try {
             return mBinder.getRecentlyExecutedRollbacks().getList();
         } catch (RemoteException e) {
@@ -121,25 +91,24 @@
     }
 
     /**
-     * Execute the given rollback, rolling back all versions of the packages
-     * to the last good versions previously installed on the device as
-     * specified in the given rollback object. The rollback will fail if any
-     * of the installed packages or available rollbacks are inconsistent with
-     * the versions specified in the given rollback object, which can happen
-     * if a package has been updated or a rollback expired since the rollback
-     * object was retrieved from {@link #getAvailableRollback(String)}.
+     * Commit the rollback with given id, rolling back all versions of the
+     * packages to the last good versions previously installed on the device
+     * as specified in the corresponding RollbackInfo object. The
+     * rollback will fail if any of the installed packages or available
+     * rollbacks are inconsistent with the versions specified in the given
+     * rollback object, which can happen if a package has been updated or a
+     * rollback expired since the rollback object was retrieved from
+     * {@link #getAvailableRollbacks()}.
      * <p>
      * TODO: Specify the returns status codes.
-     * TODO: What happens in case reboot is required for the rollback to take
-     * effect for staged installs?
      *
-     * @param rollback to execute
+     * @param rollback to commit
      * @param statusReceiver where to deliver the results
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
-    public void executeRollback(@NonNull RollbackInfo rollback,
+    public void commitRollback(@NonNull RollbackInfo rollback,
             @NonNull IntentSender statusReceiver) {
         try {
             mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver);
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 9d37d99..209afb8 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -252,12 +252,55 @@
     public static final int FACE_ACQUIRED_TOO_SIMILAR = 15;
 
     /**
+     * The magnitude of the pan angle of the user’s face with respect to the sensor’s
+     * capture plane is too high.
+     *
+     * The pan angle is defined as the angle swept out by the user’s face turning
+     * their neck left and right. The pan angle would be zero if the user faced the
+     * camera directly.
+     *
+     * The user should be informed to look more directly at the camera.
+     */
+    public static final int FACE_ACQUIRED_PAN_TOO_EXTREME = 16;
+
+    /**
+     * The magnitude of the tilt angle of the user’s face with respect to the sensor’s
+     * capture plane is too high.
+     *
+     * The tilt angle is defined as the angle swept out by the user’s face looking up
+     * and down. The pan angle would be zero if the user faced the camera directly.
+     *
+     * The user should be informed to look more directly at the camera.
+     */
+    public static final int FACE_ACQUIRED_TILT_TOO_EXTREME = 17;
+
+    /**
+     * The magnitude of the roll angle of the user’s face with respect to the sensor’s
+     * capture plane is too high.
+     *
+     * The roll angle is defined as the angle swept out by the user’s face tilting their head
+     * towards their shoulders to the left and right. The pan angle would be zero if the user
+     * faced the camera directly.
+     *
+     * The user should be informed to look more directly at the camera.
+     */
+    public static final int FACE_ACQUIRED_ROLL_TOO_EXTREME = 18;
+
+    /**
+     * The user’s face has been obscured by some object.
+     *
+     * The user should be informed to remove any objects from the line of sight from
+     * the sensor to the user’s face.
+     */
+    public static final int FACE_ACQUIRED_FACE_OBSCURED = 19;
+
+    /**
      * Hardware vendors may extend this list if there are conditions that do not fall under one of
      * the above categories. Vendors are responsible for providing error strings for these errors.
      *
      * @hide
      */
-    public static final int FACE_ACQUIRED_VENDOR = 16;
+    public static final int FACE_ACQUIRED_VENDOR = 20;
 
     /**
      * @hide
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 8aac1bf..5afe1a9 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -171,5 +171,39 @@
             Slog.w(TAG, "resetTimeout(): Service not connected");
         }
     }
+
+    /**
+     * TODO(b/123378871): Remove when moved.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void onConfirmDeviceCredentialSuccess() {
+        if (mService != null) {
+            try {
+                mService.onConfirmDeviceCredentialSuccess();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "onConfirmDeviceCredentialSuccess(): Service not connected");
+        }
+    }
+
+    /**
+     * TODO(b/123378871): Remove when moved.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void onConfirmDeviceCredentialError(int error, String message) {
+        if (mService != null) {
+            try {
+                mService.onConfirmDeviceCredentialError(error, message);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
+        }
+    }
 }
 
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c69b68e4..ec62aba 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -77,6 +77,10 @@
      * @hide
      */
     public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
+    /**
+     * @hide
+     */
+    public static final String KEY_ENABLE_FALLBACK = "enable_fallback";
 
     /**
      * Error/help message will show for this amount of time.
@@ -242,6 +246,18 @@
         }
 
         /**
+         * The user will first be prompted to authenticate with biometrics, but also given the
+         * option to authenticate with their device PIN, pattern, or password.
+         * @param enable When true, the prompt will fall back to ask for the user's device
+         *               credentials (PIN, pattern, or password).
+         * @return
+         */
+        public Builder setEnableFallback(boolean enable) {
+            mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
@@ -250,11 +266,15 @@
             final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
             final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
             final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
+            final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK);
 
             if (TextUtils.isEmpty(title) && !useDefaultTitle) {
                 throw new IllegalArgumentException("Title must be set and non-empty");
-            } else if (TextUtils.isEmpty(negative)) {
+            } else if (TextUtils.isEmpty(negative) && !enableFallback) {
                 throw new IllegalArgumentException("Negative text must be set and non-empty");
+            } else if (!TextUtils.isEmpty(negative) && enableFallback) {
+                throw new IllegalArgumentException("Can't have both negative button behavior"
+                        + " and fallback enabled");
             }
             return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
         }
@@ -514,6 +534,9 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
+        if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) {
+            throw new IllegalArgumentException("Fallback not supported with crypto");
+        }
         authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
     }
 
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index de828f2..e4336d1 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -51,4 +51,12 @@
 
     // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
     void resetTimeout(in byte [] token);
+
+    // TODO(b/123378871): Remove when moved.
+    // CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's
+    // setEnableFallback method, since there's no way for us to intercept onActivityResult.
+    // CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult.
+    void onConfirmDeviceCredentialSuccess();
+    // TODO(b/123378871): Remove when moved.
+    void onConfirmDeviceCredentialError(int error, String message);
 }
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7e45441..f3ebd7f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
+import android.graphics.ColorSpace;
 import android.graphics.Point;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.projection.IMediaProjection;
@@ -80,12 +81,20 @@
             new ArrayList<DisplayListenerDelegate>();
 
     private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
+    private final ColorSpace mWideColorSpace;
     private int[] mDisplayIdCache;
 
     private int mWifiDisplayScanNestCount;
 
     private DisplayManagerGlobal(IDisplayManager dm) {
         mDm = dm;
+        try {
+            mWideColorSpace =
+                    ColorSpace.get(
+                            ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -495,6 +504,17 @@
     }
 
     /**
+     * Gets the preferred wide gamut color space for all displays.
+     * The wide gamut color space is returned from composition pipeline
+     * based on hardware capability.
+     *
+     * @hide
+     */
+    public ColorSpace getPreferredWideGamutColorSpace() {
+        return mWideColorSpace;
+    }
+
+    /**
      * Sets the global brightness configuration for a given user.
      *
      * @hide
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index aae8afb..5ea8bd6 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -116,4 +116,9 @@
 
     // Get the minimum brightness curve.
     Curve getMinimumBrightnessCurve();
+
+    // Gets the id of the preferred wide gamut color space for all displays.
+    // The wide gamut color space is returned from composition pipeline
+    // based on hardware capability.
+    int getPreferredWideGamutColorSpaceId();
 }
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 8d568c8..33795f8 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -78,15 +78,6 @@
     public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(
             @NonNull String packageName);
 
-    /**
-     * Revokes the permission {@code permissionName} for app {@code packageName}
-     *
-     * @param packageName The package for which to revoke
-     * @param permissionName The permission to revoke
-     */
-    public abstract void onRevokeRuntimePermission(@NonNull String packageName,
-            @NonNull String permissionName);
-
     @Override
     public final IBinder onBind(Intent intent) {
         return new IRuntimePermissionPresenter.Stub() {
@@ -99,17 +90,6 @@
                         obtainMessage(RuntimePermissionPresenterService::getAppPermissions,
                                 RuntimePermissionPresenterService.this, packageName, callback));
             }
-
-            @Override
-            public void revokeRuntimePermission(String packageName, String permissionName) {
-                checkNotNull(packageName, "packageName");
-                checkNotNull(permissionName, "permissionName");
-
-                mHandler.sendMessage(
-                        obtainMessage(RuntimePermissionPresenterService::onRevokeRuntimePermission,
-                                RuntimePermissionPresenterService.this, packageName,
-                                permissionName));
-            }
         };
     }
 
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index f58efc9..e3a6bd7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.ColorSpace;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -953,6 +954,24 @@
     }
 
     /**
+     * Returns the preferred wide color space of the Display.
+     * The returned wide gamut color space is based on hardware capability and
+     * is preferred by the composition pipeline.
+     * Returns null if the display doesn't support wide color gamut.
+     * {@link Display#isWideColorGamut()}.
+     */
+    @Nullable
+    public ColorSpace getPreferredWideGamutColorSpace() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            if (mDisplayInfo.isWideColorGamut()) {
+                return mGlobal.getPreferredWideGamutColorSpace();
+            }
+            return null;
+        }
+    }
+
+    /**
      * Gets the supported color modes of this device.
      * @hide
      */
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 863b717..4032a6b8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -46,10 +46,9 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Process;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Surface.OutOfResourcesException;
 
@@ -60,6 +59,7 @@
 import libcore.util.NativeAllocationRegistry;
 
 import java.io.Closeable;
+import java.nio.ByteBuffer;
 
 /**
  * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -75,7 +75,7 @@
     private static final String TAG = "SurfaceControl";
 
     private static native long nativeCreate(SurfaceSession session, String name,
-            int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
+            int w, int h, int format, int flags, long parentObject, Parcel metadata)
             throws OutOfResourcesException;
     private static native long nativeReadFromParcel(Parcel in);
     private static native long nativeCopyFromSurfaceControl(long nativeObject);
@@ -182,6 +182,7 @@
     private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
             IBinder toToken);
     private static native boolean nativeGetProtectedContentSupport();
+    private static native void nativeSetMetadata(long transactionObj, int key, Parcel data);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -413,6 +414,24 @@
     }
 
     /**
+     * owner UID.
+     * @hide
+     */
+    public static final int METADATA_OWNER_UID = 1;
+
+    /**
+     * Window type as per {@link WindowManager.LayoutParams}.
+     * @hide
+     */
+    public static final int METADATA_WINDOW_TYPE = 2;
+
+    /**
+     * Task id to allow association between surfaces and task.
+     * @hide
+     */
+    public static final int METADATA_TASK_ID = 3;
+
+    /**
      * Builder class for {@link SurfaceControl} objects.
      */
     public static class Builder {
@@ -423,8 +442,7 @@
         private int mFormat = PixelFormat.OPAQUE;
         private String mName;
         private SurfaceControl mParent;
-        private int mWindowType = -1;
-        private int mOwnerUid = -1;
+        private SparseIntArray mMetadata;
 
         /**
          * Begin building a SurfaceControl with a given {@link SurfaceSession}.
@@ -455,8 +473,8 @@
                 throw new IllegalArgumentException(
                         "Only buffer layers can set a valid buffer size.");
             }
-            return new SurfaceControl(mSession, mName, mWidth, mHeight, mFormat,
-                    mFlags, mParent, mWindowType, mOwnerUid);
+            return new SurfaceControl(
+                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata);
         }
 
         /**
@@ -581,23 +599,17 @@
         }
 
         /**
-         * Set surface metadata.
+         * Sets a metadata int.
          *
-         * Currently these are window-types as per {@link WindowManager.LayoutParams} and
-         * owner UIDs. Child surfaces inherit their parents
-         * metadata so only the WindowManager needs to set this on root Surfaces.
-         *
-         * @param windowType A window-type
-         * @param ownerUid UID of the window owner.
+         * @param key metadata key
+         * @param data associated data
          * @hide
          */
-        public Builder setMetadata(int windowType, int ownerUid) {
-            if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
-                throw new UnsupportedOperationException(
-                        "It only makes sense to set Surface metadata from the WindowManager");
+        public Builder setMetadata(int key, int data) {
+            if (mMetadata == null) {
+                mMetadata = new SparseIntArray();
             }
-            mWindowType = windowType;
-            mOwnerUid = ownerUid;
+            mMetadata.put(key, data);
             return this;
         }
 
@@ -682,13 +694,12 @@
      * @param h The surface initial height.
      * @param flags The surface creation flags.  Should always include {@link #HIDDEN}
      * in the creation flags.
-     * @param windowType The type of the window as specified in WindowManager.java.
-     * @param ownerUid A unique per-app ID.
+     * @param metadata Initial metadata.
      *
      * @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
      */
     private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
-            SurfaceControl parent, int windowType, int ownerUid)
+            SurfaceControl parent, SparseIntArray metadata)
                     throws OutOfResourcesException, IllegalArgumentException {
         if (name == null) {
             throw new IllegalArgumentException("name must not be null");
@@ -706,8 +717,21 @@
         mName = name;
         mWidth = w;
         mHeight = h;
-        mNativeObject = nativeCreate(session, name, w, h, format, flags,
-            parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
+        Parcel metaParcel = Parcel.obtain();
+        try {
+            if (metadata != null && metadata.size() > 0) {
+                metaParcel.writeInt(metadata.size());
+                for (int i = 0; i < metadata.size(); ++i) {
+                    metaParcel.writeInt(metadata.keyAt(i));
+                    metaParcel.writeByteArray(
+                            ByteBuffer.allocate(4).putInt(metadata.valueAt(i)).array());
+                }
+            }
+            mNativeObject = nativeCreate(session, name, w, h, format, flags,
+                    parent != null ? parent.mNativeObject : 0, metaParcel);
+        } finally {
+            metaParcel.recycle();
+        }
         if (mNativeObject == 0) {
             throw new OutOfResourcesException(
                     "Couldn't allocate SurfaceControl native object");
@@ -2326,6 +2350,30 @@
         }
 
         /**
+         * Sets an arbitrary piece of metadata on the surface. This is a helper for int data.
+         * @hide
+         */
+        public Transaction setMetadata(int key, int data) {
+            Parcel parcel = Parcel.obtain();
+            parcel.writeInt(data);
+            try {
+                setMetadata(key, parcel);
+            } finally {
+                parcel.recycle();
+            }
+            return this;
+        }
+
+        /**
+         * Sets an arbitrary piece of metadata on the surface.
+         * @hide
+         */
+        public Transaction setMetadata(int key, Parcel data) {
+            nativeSetMetadata(mNativeObject, key, data);
+            return this;
+        }
+
+        /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
          *
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 69877c7..f1b259e 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -124,7 +124,7 @@
 
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
         jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
-        jint windowType, jint ownerUid) {
+        jobject metadataParcel) {
     ScopedUtfChars name(env, nameStr);
     sp<SurfaceComposerClient> client;
     if (sessionObj != NULL) {
@@ -134,8 +134,18 @@
     }
     SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
     sp<SurfaceControl> surface;
+    LayerMetadata metadata;
+    Parcel* parcel = parcelForJavaObject(env, metadataParcel);
+    if (parcel && !parcel->objectsCount()) {
+        status_t err = metadata.readFromParcel(parcel);
+        if (err != NO_ERROR) {
+          jniThrowException(env, "java/lang/IllegalArgumentException",
+                            "Metadata parcel has wrong format");
+        }
+    }
+
     status_t err = client->createSurfaceChecked(
-            String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
+            String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
     if (err == NAME_NOT_FOUND) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return 0;
@@ -377,6 +387,28 @@
     transaction->transferTouchFocus(fromToken, toToken);
 }
 
+static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jint id, jobject parcelObj) {
+    Parcel* parcel = parcelForJavaObject(env, parcelObj);
+    if (!parcel) {
+        jniThrowNullPointerException(env, "attribute data");
+        return;
+    }
+    if (parcel->objectsCount()) {
+        jniThrowException(env, "java/lang/RuntimeException",
+                "Tried to marshall a Parcel that contained Binder objects.");
+        return;
+    }
+
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+    std::vector<uint8_t> byteData(parcel->dataSize());
+    memcpy(byteData.data(), parcel->data(), parcel->dataSize());
+
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+    transaction->setMetadata(ctrl, id, std::move(byteData));
+}
+
 static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jfloatArray fColor) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -981,7 +1013,7 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
-    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
+    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J",
             (void*)nativeCreate },
     {"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
             (void*)nativeReadFromParcel },
@@ -1099,6 +1131,8 @@
             (void*)nativeSetInputWindowInfo },
     {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
             (void*)nativeTransferTouchFocus },
+    {"nativeSetMetadata", "(JILandroid/os/Parcel;)V",
+            (void*)nativeSetMetadata },
     {"nativeGetDisplayedContentSamplingAttributes",
             "(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;",
             (void*)nativeGetDisplayedContentSamplingAttributes },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 4e48663..4b37f13 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -423,13 +423,13 @@
 }
 
 void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
-  const int dev_null_fd = open("/dev/null", O_RDWR);
+  const int dev_null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
   if (dev_null_fd < 0) {
     fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
   }
 
-  if (dup2(dev_null_fd, fd) == -1) {
-    fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+  if (dup3(dev_null_fd, fd, O_CLOEXEC) == -1) {
+    fail_fn(android::base::StringPrintf("Failed dup3 on socket descriptor %d: %s",
                                         fd,
                                         strerror(errno)));
   }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a54bd7..893a607 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -43,7 +43,7 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
-    <protected-broadcast android:name="android.intent.action.PACKAGE_ROLLBACK_EXECUTED" />
+    <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 4755d45..c9e4694 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1821,6 +1821,8 @@
      * @param cct The correlated color temperature, in Kelvin
      * @return Corresponding XYZ values
      * @throws IllegalArgumentException If cct is invalid
+     *
+     * @hide
      */
     @NonNull
     @Size(3)
@@ -1851,6 +1853,8 @@
      * @param srcWhitePoint The white point to adapt from
      * @param dstWhitePoint The white point to adapt to
      * @return A 3x3 matrix as a non-null array of 9 floats
+     *
+     * @hide
      */
     @NonNull
     @Size(9)
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a45aa90..417a427 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -405,6 +405,11 @@
                 nativeFormat, consumerUsage);
         return;
     }
+
+    if (consumerUsage & GRALLOC_USAGE_PROTECTED) {
+        gbConsumer->setConsumerIsProtected(true);
+    }
+
     ctx->setBufferConsumer(bufferConsumer);
     bufferConsumer->setName(consumerName);
 
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 5fae9d5..3156732 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -47,32 +47,13 @@
 static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
     sp<SurfaceComposerClient> client = surfaceControl->getClient();
     sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-
-    Vector<ui::ColorMode> colorModes;
-    status_t err = client->getDisplayColorModes(display, &colorModes);
+    bool isWideColorDisplay = false;
+    status_t err = client->isWideColorDisplay(display, &isWideColorDisplay);
     if (err) {
         ALOGE("unable to get wide color support");
         return false;
     }
-
-    bool wideColorBoardConfig =
-        getBool<ISurfaceFlingerConfigs,
-                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
-
-    for (android::ui::ColorMode colorMode : colorModes) {
-        switch (colorMode) {
-            case ui::ColorMode::DISPLAY_P3:
-            case ui::ColorMode::ADOBE_RGB:
-            case ui::ColorMode::DCI_P3:
-                if (wideColorBoardConfig) {
-                    return true;
-                }
-                break;
-            default:
-                break;
-        }
-    }
-    return false;
+    return isWideColorDisplay;
 }
 
 static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index d09823e..a5a515f 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -34,11 +34,11 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.Preconditions;
 
@@ -48,6 +48,9 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
 
 /**
  * Find the best Service, and bind to it.
@@ -61,16 +64,20 @@
     public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
     public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
 
-    /**
-     * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
-     */
+
+    /** Function to run on binder interface. */
     public interface BinderRunner {
-        /**
-         * Runs on the retrieved binder.
-         *
-         * @param binder the binder retrieved from the {@link ServiceWatcher}.
-         */
-        void run(IBinder binder);
+        /** Called to run client code with the binder. */
+        void run(IBinder binder) throws RemoteException;
+    }
+
+    /**
+     * Function to run on binder interface.
+     * @param <T> Type to return.
+     */
+    public interface BlockingBinderRunner<T> {
+        /** Called to run client code with the binder. */
+        T run(IBinder binder) throws RemoteException;
     }
 
     public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
@@ -120,18 +127,14 @@
 
     private final Handler mHandler;
 
-    // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after
-    // the new service initialization work has completed
-    private final Object mBindLock = new Object();
-
     // read/write from handler thread
+    private IBinder mBestService;
     private int mCurrentUserId;
 
     // read from any thread, write from handler thread
     private volatile ComponentName mBestComponent;
     private volatile int mBestVersion;
     private volatile int mBestUserId;
-    private volatile IBinder mBestService;
 
     public ServiceWatcher(Context context, String logTag, String action,
             int overlaySwitchResId, int defaultServicePackageNameResId,
@@ -163,17 +166,9 @@
         mBestService = null;
     }
 
-    // called on handler thread
-    @GuardedBy("mBindLock")
-    protected void onBind() {
-        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
-    }
+    protected void onBind() {}
 
-    // called on handler thread
-    @GuardedBy("mBindLock")
-    protected void onUnbind() {
-        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
-    }
+    protected void onUnbind() {}
 
     /**
      * Start this watcher, including binding to the current best match and
@@ -248,25 +243,6 @@
         return bestComponent == null ? null : bestComponent.getPackageName();
     }
 
-    /**
-     * Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
-     * serially.
-     */
-    public final void runOnBinder(BinderRunner runner) {
-        synchronized (mBindLock) {
-            IBinder service = mBestService;
-            if (service != null) {
-                try {
-                    runner.run(service);
-                } catch (Exception e) {
-                    // remote exceptions cannot be allowed to crash system server
-                    Log.e(TAG, "exception while while running " + runner + " on " + service
-                            + " from " + this, e);
-                }
-            }
-        }
-    }
-
     private boolean isServiceMissing() {
         return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
                 PackageManager.MATCH_DIRECT_BOOT_AWARE
@@ -380,28 +356,66 @@
         mBestUserId = UserHandle.USER_NULL;
     }
 
+    /**
+     * Runs the given function asynchronously if currently connected. Suppresses any RemoteException
+     * thrown during execution.
+     */
+    public final void runOnBinder(BinderRunner runner) {
+        runOnHandler(() -> {
+            if (mBestService == null) {
+                return;
+            }
+
+            try {
+                runner.run(mBestService);
+            } catch (RuntimeException e) {
+                // the code being run is privileged, but may be outside the system server, and thus
+                // we cannot allow runtime exceptions to crash the system server
+                Log.e(TAG, "exception while while running " + runner + " on " + mBestService
+                        + " from " + this, e);
+            } catch (RemoteException e) {
+                // do nothing
+            }
+        });
+    }
+
+    /**
+     * Runs the given function synchronously if currently connected, and returns the default value
+     * if not currently connected or if any exception is thrown.
+     */
+    public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
+        try {
+            return runOnHandlerBlocking(() -> {
+                if (mBestService == null) {
+                    return defaultValue;
+                }
+
+                try {
+                    return runner.run(mBestService);
+                } catch (RemoteException e) {
+                    return defaultValue;
+                }
+            });
+        } catch (InterruptedException e) {
+            return defaultValue;
+        }
+    }
+
     @Override
     public final void onServiceConnected(ComponentName component, IBinder binder) {
-        mHandler.post(() -> {
+        runOnHandler(() -> {
             if (D) Log.d(mTag, component + " connected");
-
-            // hold the lock so that mBestService cannot be used by runOnBinder until complete
-            synchronized (mBindLock) {
-                mBestService = binder;
-                onBind();
-            }
+            mBestService = binder;
+            onBind();
         });
     }
 
     @Override
     public final void onServiceDisconnected(ComponentName component) {
-        mHandler.post(() -> {
+        runOnHandler(() -> {
             if (D) Log.d(mTag, component + " disconnected");
-
             mBestService = null;
-            synchronized (mBindLock) {
-                onUnbind();
-            }
+            onUnbind();
         });
     }
 
@@ -410,4 +424,32 @@
         ComponentName bestComponent = mBestComponent;
         return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
     }
+
+    private void runOnHandler(Runnable r) {
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            r.run();
+        } else {
+            mHandler.post(r);
+        }
+    }
+
+    private <T> T runOnHandlerBlocking(Callable<T> c) throws InterruptedException {
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            try {
+                return c.call();
+            } catch (Exception e) {
+                // Function cannot throw exception, this should never happen
+                throw new IllegalStateException(e);
+            }
+        } else {
+            FutureTask<T> task = new FutureTask<>(c);
+            mHandler.post(task);
+            try {
+                return task.get();
+            } catch (ExecutionException e) {
+                // Function cannot throw exception, this should never happen
+                throw new IllegalStateException(e);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 41fedc5..15d66e6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -29,10 +29,12 @@
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.IActivityTaskManager;
+import android.app.KeyguardManager;
 import android.app.TaskStackListener;
 import android.app.UserSwitchObserver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.hardware.biometrics.BiometricAuthenticator;
@@ -377,6 +379,13 @@
                 new BiometricTaskStackListener();
         private final Random mRandom = new Random();
 
+        // TODO(b/123378871): Remove when moved.
+        // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app)
+        // receiver. BiometricService internally launches CDCA which invokes BiometricService to
+        // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl
+        // method to poke BiometricService - the result will then be forwarded to this receiver.
+        private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
+
         // The current authentication session, null if idle/done. We need to track both the current
         // and pending sessions since errors may be sent to either.
         private AuthSession mCurrentAuthSession;
@@ -705,6 +714,22 @@
                 }
             }
 
+            // Launch CDC instead if necessary. CDC will return results through an AIDL call, since
+            // we can't get activity results. Store the receiver somewhere so we can forward the
+            // result back to the client.
+            // TODO(b/123378871): Remove when moved.
+            if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) {
+                mConfirmDeviceCredentialReceiver = receiver;
+                final KeyguardManager kgm = getContext().getSystemService(KeyguardManager.class);
+                // Use this so we don't need to duplicate logic..
+                final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */,
+                        null /* description */);
+                // Then give it the bundle to do magic behavior..
+                intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle);
+                getContext().startActivityAsUser(intent, UserHandle.CURRENT);
+                return;
+            }
+
             mHandler.post(() -> {
                 final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
                 final int modality = result.first;
@@ -745,6 +770,36 @@
             });
         }
 
+        @Override // Binder call
+        public void onConfirmDeviceCredentialSuccess() {
+            checkInternalPermission();
+            if (mConfirmDeviceCredentialReceiver == null) {
+                Slog.w(TAG, "onCDCASuccess null!");
+                return;
+            }
+            try {
+                mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException", e);
+            }
+            mConfirmDeviceCredentialReceiver = null;
+        }
+
+        @Override // Binder call
+        public void onConfirmDeviceCredentialError(int error, String message) {
+            checkInternalPermission();
+            if (mConfirmDeviceCredentialReceiver == null) {
+                Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+                return;
+            }
+            try {
+                mConfirmDeviceCredentialReceiver.onError(error, message);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException", e);
+            }
+            mConfirmDeviceCredentialReceiver = null;
+        }
+
         /**
          * authenticate() (above) which is called from BiometricPrompt determines which
          * modality/modalities to start authenticating with. authenticateInternal() should only be
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index cb3f91b..b89768a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -36,6 +36,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.ColorSpace;
 import android.graphics.Point;
 import android.hardware.SensorManager;
 import android.hardware.display.AmbientBrightnessDayStats;
@@ -93,9 +94,9 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
-import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -294,6 +295,7 @@
     // is rejected by the system.
     private final Curve mMinimumBrightnessCurve;
     private final Spline mMinimumBrightnessSpline;
+    private final ColorSpace mWideColorSpace;
 
     public DisplayManagerService(Context context) {
         this(context, new Injector());
@@ -322,6 +324,8 @@
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
         mCurrentUserId = UserHandle.USER_SYSTEM;
+        ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
+        mWideColorSpace = colorSpaces[1];
     }
 
     public void setupSchedulerPolicies() {
@@ -1073,6 +1077,10 @@
         return mMinimumBrightnessCurve;
     }
 
+    int getPreferredWideGamutColorSpaceIdInternal() {
+        return mWideColorSpace.getId();
+    }
+
     private void setBrightnessConfigurationForUserInternal(
             @Nullable BrightnessConfiguration c, @UserIdInt int userId,
             @Nullable String packageName) {
@@ -2128,6 +2136,16 @@
             }
         }
 
+        @Override // Binder call
+        public int getPreferredWideGamutColorSpaceId() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getPreferredWideGamutColorSpaceIdInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         void setBrightness(int brightness) {
             Settings.System.putIntForUser(mContext.getContentResolver(),
                     Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index cfc85da..326984c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -34,6 +34,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Pair;
 import android.util.Printer;
@@ -756,6 +757,14 @@
          */
         private final ArrayMap<String, String> mCopyOnWriteDataStore = new ArrayMap<>();
 
+        private static final ArraySet<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+        static {
+            Settings.Secure.getCloneToManagedProfileSettings(CLONE_TO_MANAGED_PROFILE);
+        }
+
+        private static final UserManagerInternal sUserManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+
         private boolean mCopyOnWrite = false;
         @NonNull
         private String mEnabledInputMethodsStrCache = "";
@@ -833,7 +842,9 @@
             if (mCopyOnWrite) {
                 mCopyOnWriteDataStore.put(key, str);
             } else {
-                Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+                final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+                        ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+                Settings.Secure.putStringForUser(mResolver, key, str, userId);
             }
         }
 
@@ -852,7 +863,9 @@
             if (mCopyOnWrite) {
                 mCopyOnWriteDataStore.put(key, String.valueOf(value));
             } else {
-                Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+                final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+                        ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+                Settings.Secure.putIntForUser(mResolver, key, value, userId);
             }
         }
 
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index f1de371..e6f0ed9 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -20,8 +20,6 @@
 import android.location.Address;
 import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
-import android.os.RemoteException;
-import android.util.Log;
 
 import com.android.internal.os.BackgroundThread;
 import com.android.server.ServiceWatcher;
@@ -68,35 +66,22 @@
 
     public String getFromLocation(double latitude, double longitude, int maxResults,
             GeocoderParams params, List<Address> addrs) {
-        final String[] result = new String[]{"Service not Available"};
-        mServiceWatcher.runOnBinder(binder -> {
+        return mServiceWatcher.runOnBinderBlocking(binder -> {
             IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-            try {
-                result[0] = provider.getFromLocation(
-                        latitude, longitude, maxResults, params, addrs);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
-        });
-        return result[0];
+            return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
+        }, "Service not Available");
     }
 
     public String getFromLocationName(String locationName,
             double lowerLeftLatitude, double lowerLeftLongitude,
             double upperRightLatitude, double upperRightLongitude, int maxResults,
             GeocoderParams params, List<Address> addrs) {
-        final String[] result = new String[]{"Service not Available"};
-        mServiceWatcher.runOnBinder(binder -> {
+        return mServiceWatcher.runOnBinderBlocking(binder -> {
             IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
-            try {
-                result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
-                        lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
-                        maxResults, params, addrs);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
-        });
-        return result[0];
+            return provider.getFromLocationName(locationName, lowerLeftLatitude,
+                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+                    maxResults, params, addrs);
+        }, "Service not Available");
     }
 
 }
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index a6da8c5..6b5b1be 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -127,20 +127,16 @@
         return mServiceWatcher.start();
     }
 
-    private void initializeService(IBinder binder) {
+    private void initializeService(IBinder binder) throws RemoteException {
         ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
         if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
 
-        try {
-            service.setLocationProviderManager(mManager);
+        service.setLocationProviderManager(mManager);
 
-            synchronized (mRequestLock) {
-                if (mRequest != null) {
-                    service.setRequest(mRequest, mWorkSource);
-                }
+        synchronized (mRequestLock) {
+            if (mRequest != null) {
+                service.setRequest(mRequest, mWorkSource);
             }
-        } catch (RemoteException e) {
-            Log.w(TAG, e);
         }
     }
 
@@ -157,63 +153,44 @@
         }
         mServiceWatcher.runOnBinder(binder -> {
             ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-            try {
-                service.setRequest(request, source);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
+            service.setRequest(request, source);
         });
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(" service=" + mServiceWatcher);
-        mServiceWatcher.runOnBinder(binder -> {
+        mServiceWatcher.runOnBinderBlocking(binder -> {
             try {
                 TransferPipe.dumpAsync(binder, fd, args);
             } catch (IOException | RemoteException e) {
-                pw.println(" failed to dump location provider: " + e);
+                pw.println(" failed to dump location provider");
             }
-        });
+            return null;
+        }, null);
     }
 
     @Override
     public int getStatus(Bundle extras) {
-        int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
-        mServiceWatcher.runOnBinder(binder -> {
+        return mServiceWatcher.runOnBinderBlocking(binder -> {
             ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-            try {
-                status[0] = service.getStatus(extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
-        });
-        return status[0];
+            return service.getStatus(extras);
+        }, LocationProvider.TEMPORARILY_UNAVAILABLE);
     }
 
     @Override
     public long getStatusUpdateTime() {
-        long[] updateTime = new long[] {0L};
-        mServiceWatcher.runOnBinder(binder -> {
+        return mServiceWatcher.runOnBinderBlocking(binder -> {
             ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-            try {
-                updateTime[0] = service.getStatusUpdateTime();
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
-        });
-        return updateTime[0];
+            return service.getStatusUpdateTime();
+        }, 0L);
     }
 
     @Override
     public void sendExtraCommand(String command, Bundle extras) {
         mServiceWatcher.runOnBinder(binder -> {
             ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
-            try {
-                service.sendExtraCommand(command, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-            }
+            service.sendExtraCommand(command, extras);
         });
     }
 }
diff --git a/services/core/java/com/android/server/location/OWNERS b/services/core/java/com/android/server/location/OWNERS
index 92b4d5f..c2c95e6 100644
--- a/services/core/java/com/android/server/location/OWNERS
+++ b/services/core/java/com/android/server/location/OWNERS
@@ -1,6 +1,8 @@
+aadmal@google.com
 arthuri@google.com
 bduddie@google.com
 gomo@google.com
 sooniln@google.com
 weiwa@google.com
 wyattriley@google.com
+yuhany@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a164686..de3f50a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1087,7 +1087,8 @@
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
-                    || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
+                    || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
+                    || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                         UserHandle.USER_ALL);
                 String pkgList[] = null;
@@ -1108,6 +1109,23 @@
                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
                     cancelNotifications = false;
                     unhideNotifications = true;
+                } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
+                    final int distractionRestrictions =
+                            intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
+                                    PackageManager.RESTRICTION_NONE);
+                    if ((distractionRestrictions
+                            & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
+                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                        uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+                        cancelNotifications = false;
+                        hideNotifications = true;
+                    } else {
+                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                        uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+                        cancelNotifications = false;
+                        unhideNotifications = true;
+                    }
+
                 } else if (queryRestart) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
@@ -1651,6 +1669,7 @@
         IntentFilter suspendedPkgFilter = new IntentFilter();
         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+        suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
                 suspendedPkgFilter, null, null);
 
@@ -7743,6 +7762,20 @@
         mPackageIntentReceiver.onReceive(getContext(), intent);
     }
 
+    @VisibleForTesting
+    protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
+        // only use for testing: mimic receive broadcast that package is (un)distracting
+        // but does not actually register that info with packagemanager
+        final Bundle extras = new Bundle();
+        extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
+        extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
+
+        final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
+        intent.putExtras(extras);
+
+        mPackageIntentReceiver.onReceive(getContext(), intent);
+    }
+
     /**
      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
      * binder without sending large amounts of data over a oneway transaction.
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 3d88f20..2aaa1ed 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -176,6 +176,14 @@
                     // only use for testing
                     mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
                 }
+                case "distract_package": {
+                    // only use for testing
+                    // Flag values are in
+                    // {@link android.content.pm.PackageManager.DistractionRestriction}.
+                    mDirectService.simulatePackageDistractionBroadcast(
+                            Integer.parseInt(getNextArgRequired()),
+                            getNextArgRequired().split(","));
+                }
                 break;
                 case "post":
                 case "notify":
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 8b4c410..6487bd7 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,7 +28,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.IRollbackManager;
 import android.content.rollback.PackageRollbackInfo;
@@ -56,12 +55,10 @@
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import java.util.Set;
 
 /**
  * Implementation of service that manages APK level rollbacks.
@@ -200,48 +197,20 @@
     }
 
     @Override
-    public RollbackInfo getAvailableRollback(String packageName) {
+    public ParceledListSlice getAvailableRollbacks() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getAvailableRollback");
+                "getAvailableRollbacks");
 
-        RollbackData data = getRollbackForPackage(packageName);
-        if (data == null) {
-            return null;
-        }
-
-        // Note: The rollback for the package ought to be for the currently
-        // installed version, otherwise the rollback data is out of date. In
-        // that rare case, we'll check when we execute the rollback whether
-        // it's out of date or not, so no need to check package versions here.
-
-        for (PackageRollbackInfo info : data.packages) {
-            if (info.getPackageName().equals(packageName)) {
-                // TODO: Once the RollbackInfo API supports info about
-                // dependant packages, add that info here.
-                return new RollbackInfo(data.rollbackId, info);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public StringParceledListSlice getPackagesWithAvailableRollbacks() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getPackagesWithAvailableRollbacks");
-
-        final Set<String> packageNames = new HashSet<>();
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
+            List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
                 RollbackData data = mAvailableRollbacks.get(i);
-                for (PackageRollbackInfo info : data.packages) {
-                    packageNames.add(info.getPackageName());
-                }
+                rollbacks.add(new RollbackInfo(data.rollbackId, data.packages));
             }
+            return new ParceledListSlice<>(rollbacks);
         }
-        return new StringParceledListSlice(new ArrayList<>(packageNames));
     }
 
     @Override
@@ -279,18 +248,11 @@
      */
     private void executeRollbackInternal(RollbackInfo rollback,
             String callerPackageName, IntentSender statusReceiver) {
-        String targetPackageName = rollback.targetPackage.getPackageName();
-        Log.i(TAG, "Initiating rollback of " + targetPackageName);
+        Log.i(TAG, "Initiating rollback");
 
-        // Get the latest RollbackData for the target package.
-        final RollbackData data = getRollbackForPackage(targetPackageName);
+        RollbackData data = getRollbackForId(rollback.getRollbackId());
         if (data == null) {
-            sendFailure(statusReceiver, "No rollback available for package.");
-            return;
-        }
-
-        if (data.rollbackId != rollback.getRollbackId()) {
-            sendFailure(statusReceiver, "Rollback for package is out of date.");
+            sendFailure(statusReceiver, "Rollback unavailable");
             return;
         }
 
@@ -335,14 +297,8 @@
         PackageManager pm = context.getPackageManager();
         try {
             PackageInstaller packageInstaller = pm.getPackageInstaller();
-            String installerPackageName = pm.getInstallerPackageName(targetPackageName);
-            if (installerPackageName == null) {
-                sendFailure(statusReceiver, "Cannot find installer package");
-                return;
-            }
             PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
                     PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-            parentParams.setInstallerPackageName(installerPackageName);
             parentParams.setAllowDowngrade(true);
             parentParams.setMultiPackage();
             int parentSessionId = packageInstaller.createSession(parentParams);
@@ -351,6 +307,11 @@
             for (PackageRollbackInfo info : data.packages) {
                 PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                         PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+                String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
+                if (installerPackageName == null) {
+                    sendFailure(statusReceiver, "Cannot find installer package");
+                    return;
+                }
                 params.setInstallerPackageName(installerPackageName);
                 params.setAllowDowngrade(true);
                 int sessionId = packageInstaller.createSession(params);
@@ -392,7 +353,7 @@
                             addRecentlyExecutedRollback(rollback);
                             sendSuccess(statusReceiver);
 
-                            Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+                            Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
 
                             // TODO: This call emits the warning "Calling a method in the
                             // system process without a qualified user". Fix that.
@@ -406,7 +367,7 @@
             data.inProgress = true;
             parentSession.commit(receiver.getIntentSender());
         } catch (IOException e) {
-            Log.e(TAG, "Unable to roll back " + targetPackageName, e);
+            Log.e(TAG, "Rollback failed", e);
             sendFailure(statusReceiver, "IOException: " + e.toString());
             return;
         }
@@ -537,9 +498,12 @@
             boolean changed = false;
             while (iter.hasNext()) {
                 RollbackInfo rollback = iter.next();
-                if (packageName.equals(rollback.targetPackage.getPackageName())) {
-                    iter.remove();
-                    changed = true;
+                for (PackageRollbackInfo info : rollback.getPackages()) {
+                    if (packageName.equals(info.getPackageName())) {
+                        iter.remove();
+                        changed = true;
+                        break;
+                    }
                 }
             }
 
@@ -935,6 +899,25 @@
         return null;
     }
 
+    /*
+     * Returns the RollbackData, if any, for an available rollback with the
+     * given rollbackId.
+     */
+    private RollbackData getRollbackForId(int rollbackId) {
+        synchronized (mLock) {
+            // TODO: Have ensureRollbackDataLoadedLocked return the list of
+            // available rollbacks, to hopefully avoid forgetting to call it?
+            ensureRollbackDataLoadedLocked();
+            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                RollbackData data = mAvailableRollbacks.get(i);
+                if (data.rollbackId == rollbackId) {
+                    return data;
+                }
+            }
+        }
+        return null;
+    }
+
     @GuardedBy("mLock")
     private int allocateRollbackIdLocked() throws IOException {
         int n = 0;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1f2f1cc..3954a11 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInstaller;
+import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.Handler;
@@ -51,11 +52,14 @@
     @Override
     public boolean onHealthCheckFailed(String packageName) {
         RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
-        RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
-        if (rollback != null) {
-            // TODO(zezeozue): Only rollback if rollback version == failed package version
-            mHandler.post(() -> executeRollback(rollbackManager, rollback));
-            return true;
+        for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
+            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+                if (packageName.equals(packageRollback.getPackageName())) {
+                    // TODO(zezeozue): Only rollback if rollback version == failed package version
+                    mHandler.post(() -> executeRollback(rollbackManager, rollback));
+                    return true;
+                }
+            }
         }
         // Don't handle the notification, no rollbacks available
         return false;
@@ -84,7 +88,7 @@
                 }
             });
         });
-        manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
+        manager.commitRollback(rollback, rollbackReceiver.getIntentSender());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 7738be9..3b24b3e 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -114,13 +114,9 @@
                 for (int i = 0; i < array.length(); ++i) {
                     JSONObject element = array.getJSONObject(i);
                     int rollbackId = element.getInt("rollbackId");
-                    String packageName = element.getString("packageName");
-                    long higherVersionCode = element.getLong("higherVersionCode");
-                    long lowerVersionCode = element.getLong("lowerVersionCode");
-                    PackageRollbackInfo target = new PackageRollbackInfo(
-                            new VersionedPackage(packageName, higherVersionCode),
-                            new VersionedPackage(packageName, lowerVersionCode));
-                    RollbackInfo rollback = new RollbackInfo(rollbackId, target);
+                    List<PackageRollbackInfo> packages = packageRollbackInfosFromJson(
+                            element.getJSONArray("packages"));
+                    RollbackInfo rollback = new RollbackInfo(rollbackId, packages);
                     recentlyExecutedRollbacks.add(rollback);
                 }
             } catch (IOException | JSONException e) {
@@ -155,18 +151,8 @@
     void saveAvailableRollback(RollbackData data) throws IOException {
         try {
             JSONObject dataJson = new JSONObject();
-            JSONArray packagesJson = new JSONArray();
-            for (PackageRollbackInfo info : data.packages) {
-                JSONObject infoJson = new JSONObject();
-                infoJson.put("packageName", info.getPackageName());
-                infoJson.put("higherVersionCode",
-                        info.getVersionRolledBackFrom().getLongVersionCode());
-                infoJson.put("lowerVersionCode",
-                        info.getVersionRolledBackTo().getVersionCode());
-                packagesJson.put(infoJson);
-            }
             dataJson.put("rollbackId", data.rollbackId);
-            dataJson.put("packages", packagesJson);
+            dataJson.put("packages", toJson(data.packages));
             dataJson.put("timestamp", data.timestamp.toString());
 
             PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
@@ -200,11 +186,7 @@
                 RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
                 JSONObject element = new JSONObject();
                 element.put("rollbackId", rollback.getRollbackId());
-                element.put("packageName", rollback.targetPackage.getPackageName());
-                element.put("higherVersionCode",
-                        rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
-                element.put("lowerVersionCode",
-                        rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
+                element.put("packages", toJson(rollback.getPackages()));
                 array.put(element);
             }
 
@@ -229,18 +211,7 @@
 
             int rollbackId = dataJson.getInt("rollbackId");
             RollbackData data = new RollbackData(rollbackId, backupDir);
-
-            JSONArray packagesJson = dataJson.getJSONArray("packages");
-            for (int i = 0; i < packagesJson.length(); ++i) {
-                JSONObject infoJson = packagesJson.getJSONObject(i);
-                String packageName = infoJson.getString("packageName");
-                long higherVersionCode = infoJson.getLong("higherVersionCode");
-                long lowerVersionCode = infoJson.getLong("lowerVersionCode");
-                data.packages.add(new PackageRollbackInfo(
-                        new VersionedPackage(packageName, higherVersionCode),
-                        new VersionedPackage(packageName, lowerVersionCode)));
-            }
-
+            data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
             data.timestamp = Instant.parse(dataJson.getString("timestamp"));
             return data;
         } catch (JSONException | DateTimeParseException e) {
@@ -248,6 +219,40 @@
         }
     }
 
+    private JSONObject toJson(PackageRollbackInfo info) throws JSONException {
+        JSONObject json = new JSONObject();
+        json.put("packageName", info.getPackageName());
+        json.put("higherVersionCode", info.getVersionRolledBackFrom().getLongVersionCode());
+        json.put("lowerVersionCode", info.getVersionRolledBackTo().getLongVersionCode());
+        return json;
+    }
+
+    private PackageRollbackInfo packageRollbackInfoFromJson(JSONObject json) throws JSONException {
+        String packageName = json.getString("packageName");
+        long higherVersionCode = json.getLong("higherVersionCode");
+        long lowerVersionCode = json.getLong("lowerVersionCode");
+        return new PackageRollbackInfo(
+                new VersionedPackage(packageName, higherVersionCode),
+                new VersionedPackage(packageName, lowerVersionCode));
+    }
+
+    private JSONArray toJson(List<PackageRollbackInfo> infos) throws JSONException {
+        JSONArray json = new JSONArray();
+        for (PackageRollbackInfo info : infos) {
+            json.put(toJson(info));
+        }
+        return json;
+    }
+
+    private List<PackageRollbackInfo> packageRollbackInfosFromJson(JSONArray json)
+            throws JSONException {
+        List<PackageRollbackInfo> infos = new ArrayList<>();
+        for (int i = 0; i < json.length(); ++i) {
+            infos.add(packageRollbackInfoFromJson(json.getJSONObject(i)));
+        }
+        return infos;
+    }
+
     /**
      * Deletes a file completely.
      * If the file is a directory, its contents are deleted as well.
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 29645f6..ed029cd 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.view.SurfaceControl.METADATA_OWNER_UID;
+import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
+
 import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT;
 import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR;
 import static com.android.server.wm.AppWindowThumbnailProto.WIDTH;
@@ -82,7 +85,8 @@
                 .setName("thumbnail anim: " + appToken.toString())
                 .setBufferSize(mWidth, mHeight)
                 .setFormat(PixelFormat.TRANSLUCENT)
-                .setMetadata(appToken.windowType,
+                .setMetadata(METADATA_WINDOW_TYPE, appToken.windowType)
+                .setMetadata(METADATA_OWNER_UID,
                         window != null ? window.mOwnerUid : Binder.getCallingUid())
                 .build();
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a7dd55b..476bd6e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.EMPTY;
+import static android.view.SurfaceControl.METADATA_TASK_ID;
 
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
@@ -643,6 +644,11 @@
         return getAppAnimationLayer(ANIMATION_LAYER_HOME);
     }
 
+    @Override
+    SurfaceControl.Builder makeSurface() {
+        return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
+    }
+
     boolean isTaskAnimating() {
         final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
         if (recentsAnim != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c2a8e7e..dea3597 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -18,6 +18,8 @@
 
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
+import static android.view.SurfaceControl.METADATA_OWNER_UID;
+import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -35,7 +37,6 @@
 import android.os.Trace;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowContentFrameStats;
@@ -103,7 +104,8 @@
                 .setBufferSize(w, h)
                 .setFormat(format)
                 .setFlags(flags)
-                .setMetadata(windowType, ownerUid);
+                .setMetadata(METADATA_WINDOW_TYPE, windowType)
+                .setMetadata(METADATA_OWNER_UID, ownerUid);
         mSurfaceControl = b.build();
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
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 6222923..9c6ab0a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3410,6 +3410,77 @@
     }
 
     @Test
+    public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
+        // Post 2 notifications from 2 packages
+        NotificationRecord pkgA = new NotificationRecord(mContext,
+                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+        mService.addNotification(pkgA);
+        NotificationRecord pkgB = new NotificationRecord(mContext,
+                generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+        mService.addNotification(pkgB);
+
+        // on broadcast, hide one of the packages
+        mService.simulatePackageDistractionBroadcast(
+                PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"});
+        ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
+        assertEquals(1, captorHide.getValue().size());
+        assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+
+        // on broadcast, unhide the package
+        mService.simulatePackageDistractionBroadcast(
+                PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"});
+        ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
+        assertEquals(1, captorUnhide.getValue().size());
+        assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+    }
+
+    @Test
+    public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
+        // Post 2 notifications from 2 packages
+        NotificationRecord pkgA = new NotificationRecord(mContext,
+                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+        mService.addNotification(pkgA);
+        NotificationRecord pkgB = new NotificationRecord(mContext,
+                generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+        mService.addNotification(pkgB);
+
+        // on broadcast, hide one of the packages
+        mService.simulatePackageDistractionBroadcast(
+                PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"});
+        ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(2)).notifyHiddenLocked(captorHide.capture());
+        assertEquals(2, captorHide.getValue().size());
+        assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+        assertEquals("b", captorHide.getValue().get(1).sbn.getPackageName());
+
+        // on broadcast, unhide the package
+        mService.simulatePackageDistractionBroadcast(
+                PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"});
+        ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(2)).notifyUnhiddenLocked(captorUnhide.capture());
+        assertEquals(2, captorUnhide.getValue().size());
+        assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+        assertEquals("b", captorUnhide.getValue().get(1).sbn.getPackageName());
+    }
+
+    @Test
+    public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
+        // post notification from this package
+        final NotificationRecord notif1 = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        mService.addNotification(notif1);
+
+        // on broadcast, nothing is hidden since no notifications are of package "test_package"
+        mService.simulatePackageDistractionBroadcast(
+                PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"});
+        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+        verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
+        assertEquals(0, captor.getValue().size());
+    }
+
+    @Test
     public void testCanUseManagedServicesLowRamNoWatchNullPkg() {
         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
         when(mActivityManager.isLowRamDevice()).thenReturn(true);
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index d777bf1..aaca18a 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -16,6 +16,8 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
@@ -2145,6 +2147,79 @@
     }
 
     /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * The prefixes is a list of prefix {@code String} separated by this delimiter.
+     * @hide
+     */
+    public static final String REGEX_PREFIX_DELIMITER = ",";
+    /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * The success status to be added into the intent to be sent to the calling package.
+     * @hide
+     */
+    public static final int RESULT_STATUS_SUCCESS = 0;
+    /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * The timeout status to be added into the intent to be sent to the calling package.
+     * @hide
+     */
+    public static final int RESULT_STATUS_TIMEOUT = 1;
+    /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * Intent extra key of the retrieved SMS message as a {@code String}.
+     * @hide
+     */
+    public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
+    /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * Intent extra key of SMS retriever status, which indicates whether the request for the
+     * coming SMS message is SUCCESS or TIMEOUT
+     * @hide
+     */
+    public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
+    /**
+     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
+     * @hide
+     */
+    public static final String EXTRA_SIM_SUBSCRIPTION_ID =
+            "android.telephony.extra.SIM_SUBSCRIPTION_ID";
+
+    /**
+     * Create a single use app specific incoming SMS request for the calling package.
+     *
+     * This method returns a token that if included in a subsequent incoming SMS message, and the
+     * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be
+     * sent with the SMS data to the calling package.
+     *
+     * The token is only good for one use within a reasonable amount of time. After an SMS has been
+     * received containing the token all subsequent SMS messages with the token will be routed as
+     * normal.
+     *
+     * An app can only have one request at a time, if the app already has a request pending it will
+     * be replaced with a new request.
+     *
+     * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The
+     *  matching SMS message should have at least one of the prefixes in the beginning of the
+     *  message.
+     * @param intent this intent is sent when the matching SMS message is received.
+     * @return Token to include in an SMS message.
+     */
+    @Nullable
+    public String createAppSpecificSmsTokenWithPackageInfo(
+            @Nullable String prefixes, @NonNull PendingIntent intent) {
+        try {
+            ISms iccSms = getISmsServiceOrThrow();
+            return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
+                ActivityThread.currentPackageName(), prefixes, intent);
+
+        } catch (RemoteException ex) {
+            ex.rethrowFromSystemServer();
+            return null;
+        }
+    }
+
+    /**
      * Filters a bundle to only contain MMS config variables.
      *
      * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index a4eb424..58ebb15 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -560,4 +560,19 @@
      * @param intent PendingIntent to be sent when an SMS is received containing the token.
      */
     String createAppSpecificSmsToken(int subId, String callingPkg, in PendingIntent intent);
+
+    /**
+     * Create an app-only incoming SMS request for the calling package.
+     *
+     * If an incoming text contains the token returned by this method the provided
+     * <code>PendingIntent</code> will be sent containing the SMS data.
+     *
+     * @param subId the SIM id.
+     * @param callingPkg the package name of the calling app.
+     * @param prefixes the caller provided prefixes
+     * @param intent PendingIntent to be sent when a SMS is received containing the token and one
+     *   of the prefixes
+     */
+    String createAppSpecificSmsTokenWithPackageInfo(
+            int subId, String callingPkg, String prefixes, in PendingIntent intent);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 1cdf44d..f2f2960 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -188,4 +188,10 @@
     public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public String createAppSpecificSmsTokenWithPackageInfo(
+            int subId, String callingPkg, String prefixes, PendingIntent intent) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
index 979d13a..ee02a72 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -35,7 +35,6 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := DexLoggerNativeTestLibrary
-LOCAL_MULTILIB := first
 LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE)
@@ -44,8 +43,6 @@
 
 include $(BUILD_SHARED_LIBRARY)
 
-dexloggertest_so := $(LOCAL_BUILT_MODULE)
-
 # And a standalone native executable that we can exec.
 
 include $(CLEAR_VARS)
@@ -73,11 +70,15 @@
     android-support-test \
     truth-prebuilt \
 
+# Include both versions of the .so if we have 2 arch
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := \
+    DexLoggerNativeTestLibrary \
+
 # This gets us the javalib.jar built by DexLoggerTestLibrary above as well as the various
 # native binaries.
 LOCAL_JAVA_RESOURCE_FILES := \
     $(dexloggertest_jar) \
-    $(dexloggertest_so) \
-    $(dexloggertest_executable)
+    $(dexloggertest_executable) \
 
 include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
index d68769b..e92cc56 100644
--- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
@@ -21,6 +21,7 @@
 
 import android.app.UiAutomation;
 import android.content.Context;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
@@ -147,7 +148,7 @@
         String expectedNameHash =
                 "996223BAD4B4FE75C57A3DEC61DB9C0B38E0A7AD479FC95F33494F4BC55A0F0E";
         String expectedContentHash =
-                copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+                copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
 
         System.load(privateCopyFile.toString());
 
@@ -170,7 +171,7 @@
         String expectedNameHash =
                 "8C39990C560B4F36F83E208E279F678746FE23A790E4C50F92686584EA2041CA";
         String expectedContentHash =
-                copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+                copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
 
         System.load(privateCopyFile.toString());
 
@@ -307,6 +308,12 @@
         return new File(sContext.getDir("dcl", Context.MODE_PRIVATE), name);
     }
 
+    private String libraryPath(final String libraryName) {
+        // This may be deprecated. but it tells us the ABI of this process which is exactly what we
+        // want.
+        return "/lib/" + Build.CPU_ABI + "/" + libraryName;
+    }
+
     private static String copyAndHashResource(String resourcePath, File copyTo) throws Exception {
         MessageDigest hasher = MessageDigest.getInstance("SHA-256");
 
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index 030641b..e10f866 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -29,7 +29,7 @@
 
 /**
  * A broadcast receiver that can be used to get
- * ACTION_PACKAGE_ROLLBACK_EXECUTED broadcasts.
+ * ACTION_ROLLBACK_COMMITTED broadcasts.
  */
 class RollbackBroadcastReceiver extends BroadcastReceiver {
 
@@ -43,7 +43,7 @@
      */
     RollbackBroadcastReceiver() {
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+        filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
         InstrumentationRegistry.getContext().registerReceiver(this, filter);
     }
 
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 13ac4f0..7ab716f 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -31,11 +31,8 @@
 import android.util.Log;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import org.junit.Ignore;
@@ -43,6 +40,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -86,8 +84,8 @@
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.MANAGE_ROLLBACKS);
 
-            // Register a broadcast receiver for notification when the rollback is
-            // done executing.
+            // Register a broadcast receiver for notification when the
+            // rollback has been committed.
             RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -99,12 +97,11 @@
             // uninstalled and when rollback manager deletes the rollback. Fix it
             // so that's not the case!
             for (int i = 0; i < 5; ++i) {
-                for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-                    if (TEST_APP_A.equals(info.targetPackage.getPackageName())) {
-                        Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
-                        Thread.sleep(1000);
-                        break;
-                    }
+                RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                        rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+                if (rollback != null) {
+                    Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+                    Thread.sleep(1000);
                 }
             }
 
@@ -113,13 +110,11 @@
             // between when the app is uninstalled and when the previously
             // available rollback, if any, is removed.
             Thread.sleep(1000);
-            assertNull(rm.getAvailableRollback(TEST_APP_A));
-            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
 
-            // There should be no recently executed rollbacks for this package.
-            for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-                assertNotEquals(TEST_APP_A, info.targetPackage.getPackageName());
-            }
+            // There should be no recently committed rollbacks for this package.
+            assertNull(getUniqueRollbackInfoForPackage(
+                        rm.getRecentlyCommittedRollbacks(), TEST_APP_A));
 
             // Install v1 of the app (without rollbacks enabled).
             RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -134,10 +129,9 @@
             // between when the app is installed and when the rollback
             // is made available.
             Thread.sleep(1000);
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollback);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
 
             // We should not have received any rollback requests yet.
             // TODO: Possibly flaky if, by chance, some other app on device
@@ -156,15 +150,9 @@
             assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
 
             // Verify the recent rollback has been recorded.
-            rollback = null;
-            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
-                    assertNull(rollback);
-                    rollback = r;
-                }
-            }
-            assertNotNull(rollback);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+            rollback = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
 
             broadcastReceiver.unregister();
             context.unregisterReceiver(enableRollbackReceiver);
@@ -202,28 +190,25 @@
             // is made available.
             Thread.sleep(1000);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
-            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+            rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
-            rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+            rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Rollback of B should not rollback A
             RollbackTestUtils.rollback(rollbackB);
@@ -264,28 +249,23 @@
             // is made available.
             Thread.sleep(1000);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoForAandB(rollbackA);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
-            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoForAandB(rollbackB);
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+            rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoForAandB(rollbackA);
 
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
-            rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+            rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoForAandB(rollbackB);
 
             // Rollback of B should rollback A as well
             RollbackTestUtils.rollback(rollbackB);
@@ -297,10 +277,10 @@
     }
 
     /**
-     * Test that recently executed rollback data is properly persisted.
+     * Test that recently committed rollback data is properly persisted.
      */
     @Test
-    public void testRecentlyExecutedRollbackPersistence() throws Exception {
+    public void testRecentlyCommittedRollbackPersistence() throws Exception {
         try {
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
@@ -319,37 +299,27 @@
             // between when the app is installed and when the rollback
             // is made available.
             Thread.sleep(1000);
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
 
             // Roll back the app.
             RollbackTestUtils.rollback(rollback);
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // Verify the recent rollback has been recorded.
-            rollback = null;
-            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
-                    assertNull(rollback);
-                    rollback = r;
-                }
-            }
+            rollback = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
             assertNotNull(rollback);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // Verify the recent rollback is still recorded.
-            rollback = null;
-            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
-                    assertNull(rollback);
-                    rollback = r;
-                }
-            }
+            rollback = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
             assertNotNull(rollback);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
         } finally {
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -378,17 +348,16 @@
             // between when the app is installed and when the rollback
             // is made available.
             Thread.sleep(1000);
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollback);
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
 
             // Expire the rollback.
             rm.expireRollbackForPackage(TEST_APP_A);
 
             // The rollback should no longer be available.
-            assertNull(rm.getAvailableRollback(TEST_APP_A));
-            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            assertNull(getUniqueRollbackInfoForPackage(
+                        rm.getAvailableRollbacks(), TEST_APP_A));
         } finally {
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -459,7 +428,8 @@
             processUserData(TEST_APP_A);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
             RollbackTestUtils.rollback(rollback);
             processUserData(TEST_APP_A);
         } finally {
@@ -469,12 +439,12 @@
 
     /**
      * Test restrictions on rollback broadcast sender.
-     * A random app should not be able to send a PACKAGE_ROLLBACK_EXECUTED broadcast.
+     * A random app should not be able to send a ROLLBACK_COMMITTED broadcast.
      */
     @Test
     public void testRollbackBroadcastRestrictions() throws Exception {
         RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
-        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+        Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
         try {
             InstrumentationRegistry.getContext().sendBroadcast(broadcast);
             fail("Succeeded in sending restricted broadcast from app context.");
@@ -516,18 +486,18 @@
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
             // Both test apps should now be available for rollback, and the
-            // targetPackage returned for rollback should be correct.
+            // RollbackInfo returned for the rollbacks should be correct.
             // TODO: See if there is a way to remove this race condition
             // between when the app is installed and when the rollback
             // is made available.
             Thread.sleep(1000);
-            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
 
-            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Executing rollback should roll back the correct package.
             RollbackTestUtils.rollback(rollbackA);
@@ -558,21 +528,14 @@
         RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
         try {
-            rm.getAvailableRollback(TEST_APP_A);
+            rm.getAvailableRollbacks();
             fail("expected SecurityException");
         } catch (SecurityException e) {
             // Expected.
         }
 
         try {
-            rm.getPackagesWithAvailableRollbacks();
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-
-        try {
-            rm.getRecentlyExecutedRollbacks();
+            rm.getRecentlyCommittedRollbacks();
             fail("expected SecurityException");
         } catch (SecurityException e) {
             // Expected.
@@ -581,7 +544,7 @@
         try {
             // TODO: What if the implementation checks arguments for non-null
             // first? Then this test isn't valid.
-            rm.executeRollback(null, null);
+            rm.commitRollback(null, null);
             fail("expected SecurityException");
         } catch (SecurityException e) {
             // Expected.
@@ -629,12 +592,9 @@
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
             // TEST_APP_A should now be available for rollback.
-            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
-            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollback);
-
-            // TODO: Test the dependent apps for rollback are correct once we
-            // support that in the RollbackInfo API.
+            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoForAandB(rollback);
 
             // Rollback the app. It should cause both test apps to be rolled
             // back.
@@ -642,14 +602,16 @@
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
-            // We should not see a recent rollback listed for TEST_APP_B
-            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-                assertNotEquals(TEST_APP_B, r.targetPackage.getPackageName());
-            }
+            // We should see recent rollbacks listed for both A and B.
+            Thread.sleep(1000);
+            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
 
-            // TODO: Test the listed dependent apps for the recently executed
-            // rollback are correct once we support that in the RollbackInfo
-            // API.
+            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TEST_APP_B);
+            assertRollbackInfoForAandB(rollbackB);
+
+            assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
         } finally {
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -697,13 +659,13 @@
             // between when the app is installed and when the rollback
             // is made available.
             Thread.sleep(1000);
-            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
-            assertNotNull(rollbackA);
-            assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_A);
+            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
 
-            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
-            assertNotNull(rollbackB);
-            assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TEST_APP_B);
+            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
             for (int i = 0; i < 5; i++) {
@@ -724,4 +686,47 @@
             RollbackTestUtils.dropShellPermissionIdentity();
         }
     }
+
+    // Helper function to test the value of a RollbackInfo with single package
+    private void assertRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            RollbackInfo info) {
+        assertNotNull(info);
+        assertEquals(1, info.getPackages().size());
+        assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
+                info.getPackages().get(0));
+    }
+
+    // Helper function to test that the given rollback info is a rollback for
+    // the atomic set {A2, B2} -> {A1, B1}.
+    private void assertRollbackInfoForAandB(RollbackInfo rollback) {
+        assertNotNull(rollback);
+        assertEquals(2, rollback.getPackages().size());
+        if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) {
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0));
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1));
+        } else {
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0));
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1));
+        }
+    }
+
+    // Helper function to return the RollbackInfo with a given package in the
+    // list of rollbacks. Throws an assertion failure if there is more than
+    // one such rollback info. Returns null if there are no such rollback
+    // infos.
+    private RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
+            String packageName) {
+        RollbackInfo found = null;
+        for (RollbackInfo rollback : rollbacks) {
+            for (PackageRollbackInfo info : rollback.getPackages()) {
+                if (packageName.equals(info.getPackageName())) {
+                    assertNull(found);
+                    found = rollback;
+                    break;
+                }
+            }
+        }
+        return found;
+    }
 }
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index edb1355..f481897 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -90,12 +90,12 @@
     }
 
     /**
-     * Execute the given rollback.
+     * Commit the given rollback.
      * @throws AssertionError if the rollback fails.
      */
     static void rollback(RollbackInfo rollback) throws InterruptedException {
         RollbackManager rm = getRollbackManager();
-        rm.executeRollback(rollback, LocalIntentSender.getIntentSender());
+        rm.commitRollback(rollback, LocalIntentSender.getIntentSender());
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
diff --git a/tools/bit/aapt.cpp b/tools/bit/aapt.cpp
index 961b47c..cee0cd5 100644
--- a/tools/bit/aapt.cpp
+++ b/tools/bit/aapt.cpp
@@ -159,10 +159,11 @@
 inspect_apk(Apk* apk, const string& filename)
 {
     // Load the manifest xml
-    Command cmd("aapt");
+    Command cmd("aapt2");
     cmd.AddArg("dump");
     cmd.AddArg("xmltree");
     cmd.AddArg(filename);
+    cmd.AddArg("--file");
     cmd.AddArg("AndroidManifest.xml");
 
     int err;
@@ -217,11 +218,11 @@
             if (current != NULL) {
                 Attribute attr;
                 string str = match[2];
-                size_t colon = str.find(':');
+                size_t colon = str.rfind(':');
                 if (colon == string::npos) {
                     attr.name = str;
                 } else {
-                    attr.ns = scope->namespaces[string(str, 0, colon)];
+                    attr.ns.assign(str, 0, colon);
                     attr.name.assign(str, colon+1, string::npos);
                 }
                 attr.value = match[3];
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index a71cea1..860094ae 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -623,12 +623,13 @@
     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
     const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
     const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
-
+    const string buildOut = get_out_dir();
     chdir_or_exit(buildTop.c_str());
 
-    const string buildDevice = get_build_var("TARGET_DEVICE", false);
-    const string buildId = get_build_var("BUILD_ID", false);
-    const string buildOut = get_out_dir();
+    BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+    const string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
+    const string buildId = buildVars.GetBuildVar("BUILD_ID", false);
 
     // Get the modules for the targets
     map<string,Module> modules;
@@ -661,6 +662,7 @@
     string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
     bool syncSystem = false;
     bool alwaysSyncSystem = false;
+    vector<string> systemFiles;
     vector<InstallApk> installApks;
     for (size_t i=0; i<targets.size(); i++) {
         Target* target = targets[i];
@@ -670,6 +672,7 @@
                 // System partition
                 if (starts_with(file, systemPath)) {
                     syncSystem = true;
+                    systemFiles.push_back(file);
                     if (!target->build) {
                         // If a system partition target didn't get built then
                         // it won't change we will always need to do adb sync
@@ -692,6 +695,19 @@
         get_directory_contents(systemPath, &systemFilesBefore);
     }
 
+    if (systemFiles.size() > 0){
+        print_info("System files:");
+        for (size_t i=0; i<systemFiles.size(); i++) {
+            printf("  %s\n", systemFiles[i].c_str());
+        }
+    }
+    if (installApks.size() > 0){
+        print_info("APKs to install:");
+        for (size_t i=0; i<installApks.size(); i++) {
+            printf("  %s\n", installApks[i].file.filename.c_str());
+        }
+    }
+
     //
     // Build
     //
@@ -798,7 +814,8 @@
             for (size_t j=0; j<target->module.installed.size(); j++) {
                 string filename = target->module.installed[j];
 
-                if (!ends_with(filename, ".apk")) {
+                // Apk in the data partition
+                if (!starts_with(filename, dataPath) || !ends_with(filename, ".apk")) {
                     continue;
                 }
 
@@ -1004,13 +1021,16 @@
 void
 run_tab_completion(const string& word)
 {
-    const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
+    const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
     const string buildProduct = get_required_env("TARGET_PRODUCT", false);
+    const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
+    const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
     const string buildOut = get_out_dir();
-
     chdir_or_exit(buildTop.c_str());
 
-    string buildDevice = sniff_device_name(buildOut, buildProduct);
+    BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+    string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
 
     map<string,Module> modules;
     read_modules(buildOut, buildDevice, &modules, true);
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index 5a9ab22..6270913 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -21,6 +21,7 @@
 #include "util.h"
 
 #include <json/reader.h>
+#include <json/writer.h>
 #include <json/value.h>
 
 #include <fstream>
@@ -34,22 +35,118 @@
 
 using namespace std;
 
-map<string,string> g_buildVars;
+static bool
+map_contains(const map<string,string>& m, const string& k, const string& v) {
+    map<string,string>::const_iterator it = m.find(k);
+    if (it == m.end()) {
+        return false;
+    }
+    return it->second == v;
+}
+
+static string
+make_cache_filename(const string& outDir)
+{
+    string filename(outDir);
+    return filename + "/.bit_cache";
+}
+
+BuildVars::BuildVars(const string& outDir, const string& buildProduct,
+        const string& buildVariant, const string& buildType)
+    :m_filename(),
+     m_cache()
+{
+    m_cache["TARGET_PRODUCT"] = buildProduct;
+    m_cache["TARGET_BUILD_VARIANT"] = buildVariant;
+    m_cache["TARGET_BUILD_TYPE"] = buildType;
+
+    // If we have any problems reading the file, that's ok, just do
+    // uncached calls to make / soong.
+
+    if (outDir == "") {
+        return;
+    }
+
+
+    m_filename = make_cache_filename(outDir);
+
+    std::ifstream stream(m_filename, std::ifstream::binary);
+
+    if (stream.fail()) {
+        return;
+    }
+
+    Json::Value json;
+    Json::Reader reader;
+    if (!reader.parse(stream, json)) {
+        return;
+    }
+
+    if (!json.isObject()) {
+        return;
+    }
+
+    map<string,string> cache;
+
+    vector<string> names = json.getMemberNames();
+    const int N = names.size();
+    for (int i=0; i<N; i++) {
+        const string& name = names[i];
+        const Json::Value& value = json[name];
+        if (!value.isString()) {
+            continue;
+        }
+        cache[name] = value.asString();
+    }
+
+    // If all of the base variables match, then we can use this cache.  Otherwise, use our
+    // base one.  The next time someone reads a value, the new one, with our base varaibles
+    // will be saved.
+    if (map_contains(cache, "TARGET_PRODUCT", buildProduct)
+            && map_contains(cache, "TARGET_BUILD_VARIANT", buildVariant)
+            && map_contains(cache, "TARGET_BUILD_TYPE", buildType)) {
+        m_cache = cache;
+    }
+}
+
+BuildVars::~BuildVars()
+{
+}
+
+void
+BuildVars::save()
+{
+    if (m_filename == "") {
+        return;
+    }
+
+    Json::StyledStreamWriter writer("  ");
+
+    Json::Value json(Json::objectValue);
+
+    for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) {
+        json[it->first] = it->second;
+    }
+
+    std::ofstream stream(m_filename, std::ofstream::binary);
+    writer.write(stream, json);
+}
 
 string
-get_build_var(const string& name, bool quiet)
+BuildVars::GetBuildVar(const string& name, bool quiet)
 {
     int err;
 
-    map<string,string>::iterator it = g_buildVars.find(name);
-    if (it == g_buildVars.end()) {
+    map<string,string>::iterator it = m_cache.find(name);
+    if (it == m_cache.end()) {
         Command cmd("build/soong/soong_ui.bash");
         cmd.AddArg("--dumpvar-mode");
         cmd.AddArg(name);
 
         string output = trim(get_command_output(cmd, &err, quiet));
         if (err == 0) {
-            g_buildVars[name] = output;
+            m_cache[name] = output;
+            save();
             return output;
         } else {
             return string();
@@ -59,38 +156,6 @@
     }
 }
 
-string
-sniff_device_name(const string& buildOut, const string& product)
-{
-    string match("ro.build.product=" + product);
-
-    string base(buildOut + "/target/product");
-    DIR* dir = opendir(base.c_str());
-    if (dir == NULL) {
-        return string();
-    }
-
-    dirent* entry;
-    while ((entry = readdir(dir)) != NULL) {
-        if (entry->d_name[0] == '.') {
-            continue;
-        }
-        if (entry->d_type == DT_DIR) {
-            string filename(base + "/" + entry->d_name + "/system/build.prop");
-            vector<string> lines;
-            split_lines(&lines, read_file(filename));
-            for (size_t i=0; i<lines.size(); i++) {
-                if (lines[i] == match) {
-                    return entry->d_name;
-                }
-            }
-        }
-    }
-
-    closedir(dir);
-    return string();
-}
-
 void
 json_error(const string& filename, const char* error, bool quiet)
 {
diff --git a/tools/bit/make.h b/tools/bit/make.h
index 1c9504d..db0b69f 100644
--- a/tools/bit/make.h
+++ b/tools/bit/make.h
@@ -31,16 +31,26 @@
     vector<string> installed;
 };
 
-string get_build_var(const string& name, bool quiet);
-
 /**
- * Poke around in the out directory and try to find a device name that matches
- * our product. This is faster than running get_build_var and good enough for
- * tab completion.
- *
- * Returns the empty string if we can't find one.
+ * Class to encapsulate getting build variables. Caches the
+ * results if possible.
  */
-string sniff_device_name(const string& buildOut, const string& product);
+class BuildVars
+{
+public:
+    BuildVars(const string& outDir, const string& buildProduct,
+            const string& buildVariant, const string& buildType);
+    ~BuildVars();
+
+    string GetBuildVar(const string& name, bool quiet);
+
+private:
+    void save();
+
+    string m_filename;
+
+    map<string,string> m_cache;
+};
 
 void read_modules(const string& buildOut, const string& buildDevice,
         map<string,Module>* modules, bool quiet);
diff --git a/tools/bit/print.cpp b/tools/bit/print.cpp
index 790e0b4..35feda1 100644
--- a/tools/bit/print.cpp
+++ b/tools/bit/print.cpp
@@ -116,6 +116,20 @@
 }
 
 void
+print_info(const char* format, ...)
+{
+    fputs(g_escapeBold, stdout);
+
+    va_list args;
+    va_start(args, format);
+    vfprintf(stdout, format, args);
+    va_end(args);
+
+    fputs(g_escapeEndColor, stdout);
+    fputc('\n', stdout);
+}
+
+void
 print_one_line(const char* format, ...)
 {
     if (g_stdoutIsTty) {
diff --git a/tools/bit/print.h b/tools/bit/print.h
index b6c3e9a..db6cf5f 100644
--- a/tools/bit/print.h
+++ b/tools/bit/print.h
@@ -33,6 +33,7 @@
 void print_command(const Command& command);
 void print_error(const char* format, ...);
 void print_warning(const char* format, ...);
+void print_info(const char* format, ...);
 void print_one_line(const char* format, ...);
 void check_error(int err);