Merge "Attempt to de-flake tests."
diff --git a/Android.bp b/Android.bp
index 1ee7405..6288940 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,7 +69,6 @@
         "core/java/android/app/ITaskStackListener.aidl",
         "core/java/android/app/IBackupAgent.aidl",
         "core/java/android/app/IEphemeralResolver.aidl",
-        "core/java/android/app/IInputForwarder.aidl",
         "core/java/android/app/IInstantAppResolver.aidl",
         "core/java/android/app/IInstrumentationWatcher.aidl",
         "core/java/android/app/INotificationManager.aidl",
diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING
index 8a676e9..2cdf54b 100644
--- a/api/TEST_MAPPING
+++ b/api/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "CtsCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "GtsUnofficialApisUsageTestCases"
     }
   ]
 }
diff --git a/api/current.txt b/api/current.txt
index fe52f3a..1c60efa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9348,25 +9348,7 @@
     field public static final android.os.Parcelable.Creator<android.content.ComponentName> CREATOR;
   }
 
-  public interface ContentInterface {
-    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
-    method @Nullable public android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle) throws android.os.RemoteException;
-    method @Nullable public android.net.Uri canonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
-    method public int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
-    method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String) throws android.os.RemoteException;
-    method @Nullable public String getType(@NonNull android.net.Uri) throws android.os.RemoteException;
-    method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues) throws android.os.RemoteException;
-    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method @Nullable public android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
-    method @Nullable public android.net.Uri uncanonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
-    method public int update(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
-  }
-
-  public abstract class ContentProvider implements android.content.ComponentCallbacks2 android.content.ContentInterface {
+  public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
     ctor public ContentProvider();
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
@@ -9419,7 +9401,7 @@
     method public void writeDataToPipe(@NonNull android.os.ParcelFileDescriptor, @NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable T);
   }
 
-  public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
@@ -9502,8 +9484,8 @@
     method public void setKeepUpdated(boolean);
   }
 
-  public abstract class ContentResolver implements android.content.ContentInterface {
-    ctor public ContentResolver(android.content.Context);
+  public abstract class ContentResolver {
+    ctor public ContentResolver(@Nullable android.content.Context);
     method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull android.net.Uri);
     method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull String);
     method @Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull android.net.Uri);
@@ -9568,6 +9550,8 @@
     method public final void unregisterContentObserver(@NonNull android.database.ContentObserver);
     method public final int update(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
     method public static void validateSyncExtrasBundle(android.os.Bundle);
+    method public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider);
+    method public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient);
     field public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
     field public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
     field public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
@@ -38171,38 +38155,26 @@
     method public static android.net.Uri buildRootsUri(String);
     method public static android.net.Uri buildSearchDocumentsUri(String, String, String);
     method public static android.net.Uri buildTreeDocumentUri(String, String);
-    method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, String, String) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
-    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
-    method @Deprecated public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
-    method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public static android.net.Uri copyDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public static android.net.Uri createDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull String, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public static android.content.IntentSender createWebLinkIntent(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+    method public static boolean deleteDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method public static void ejectRoot(@NonNull android.content.ContentResolver, @NonNull android.net.Uri);
+    method @Nullable public static android.provider.DocumentsContract.Path findDocumentPath(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
     method public static String getDocumentId(android.net.Uri);
-    method @Nullable public static android.os.Bundle getDocumentMetadata(@NonNull android.content.ContentInterface, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public static android.os.Bundle getDocumentMetadata(@NonNull android.content.ContentResolver, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public static android.graphics.Bitmap getDocumentThumbnail(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.graphics.Point, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public static String getRootId(android.net.Uri);
     method public static String getSearchDocumentsQuery(android.net.Uri);
     method public static String getTreeDocumentId(android.net.Uri);
-    method public static boolean isChildDocument(@NonNull android.content.ContentInterface, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+    method public static boolean isChildDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
     method public static boolean isDocumentUri(android.content.Context, @Nullable android.net.Uri);
     method public static boolean isRootUri(@NonNull android.content.Context, @Nullable android.net.Uri);
     method public static boolean isRootsUri(@NonNull android.content.Context, @Nullable android.net.Uri);
     method public static boolean isTreeUri(android.net.Uri);
-    method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method @Deprecated public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, String) throws java.io.FileNotFoundException;
-    method @Deprecated public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+    method @Nullable public static android.net.Uri moveDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method public static boolean removeDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public static android.net.Uri renameDocument(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
     field public static final String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
     field public static final String EXTRA_ERROR = "error";
     field public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
diff --git a/api/system-current.txt b/api/system-current.txt
index 8296eee..128ee99 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -304,7 +304,7 @@
   }
 
   public class AppOpsManager {
-    method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static String[] getOpStrs();
     method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]);
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
@@ -394,6 +394,17 @@
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
+  public static final class AppOpsManager.HistoricalOpsRequest {
+  }
+
+  public static final class AppOpsManager.HistoricalOpsRequest.Builder {
+    ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
+  }
+
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
@@ -1284,11 +1295,11 @@
 
 package android.content {
 
-  public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
 
-  public abstract class ContentResolver implements android.content.ContentInterface {
+  public abstract class ContentResolver {
     method public android.os.Bundle getCache(android.net.Uri);
     method public android.graphics.drawable.Drawable getTypeDrawable(String);
     method public void putCache(android.net.Uri, android.os.Bundle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 16098c1..01678b1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -101,8 +101,8 @@
   public class AppOpsManager {
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
-    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
-    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(int, @Nullable String, @Nullable String[], long, long, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public static String[] getOpStrs();
     method public boolean isOperationActive(int, int, String);
@@ -206,6 +206,17 @@
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
+  public static final class AppOpsManager.HistoricalOpsRequest {
+  }
+
+  public static final class AppOpsManager.HistoricalOpsRequest.Builder {
+    ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
+  }
+
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
@@ -472,11 +483,11 @@
 
 package android.content {
 
-  public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
 
-  public abstract class ContentResolver implements android.content.ContentInterface {
+  public abstract class ContentResolver {
     method public static String[] getSyncAdapterPackagesForAuthorityAsUser(String, int);
   }
 
diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blacklist.txt
index dca3b52..b328f2a 100644
--- a/config/hiddenapi-force-blacklist.txt
+++ b/config/hiddenapi-force-blacklist.txt
@@ -1,4 +1,6 @@
 Ldalvik/system/VMRuntime;->setHiddenApiExemptions([Ljava/lang/String;)V
+Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V
+Ldalvik/system/VMRuntime;->setTargetSdkVersionNative(I)V
 Ljava/lang/invoke/MethodHandles$Lookup;->IMPL_LOOKUP:Ljava/lang/invoke/MethodHandles$Lookup;
 Ljava/lang/invoke/VarHandle;->acquireFence()V
 Ljava/lang/invoke/VarHandle;->compareAndExchange([Ljava/lang/Object;)Ljava/lang/Object;
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-greylist-max-o.txt
index 4b6cc0e..d9c1cd0 100644
--- a/config/hiddenapi-greylist-max-o.txt
+++ b/config/hiddenapi-greylist-max-o.txt
@@ -109777,7 +109777,6 @@
 Ldalvik/system/VMRuntime;->setNonSdkApiUsageConsumer(Ljava/util/function/Consumer;)V
 Ldalvik/system/VMRuntime;->setProcessPackageName(Ljava/lang/String;)V
 Ldalvik/system/VMRuntime;->setSystemDaemonThreadPriority()V
-Ldalvik/system/VMRuntime;->setTargetSdkVersionNative(I)V
 Ldalvik/system/VMRuntime;->startHeapTaskProcessor()V
 Ldalvik/system/VMRuntime;->startJitCompilation()V
 Ldalvik/system/VMRuntime;->stopHeapTaskProcessor()V
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index dc2ed4c..a836e8e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -170,7 +170,6 @@
 Landroid/app/IAssistDataReceiver$Stub;-><init>()V
 Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V
 Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
-Landroid/app/IInputForwarder;->forwardEvent(Landroid/view/InputEvent;)Z
 Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
 Landroid/app/IInstrumentationWatcher;->instrumentationStatus(Landroid/content/ComponentName;ILandroid/os/Bundle;)V
 Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 69c450c..7d828d8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -259,10 +259,11 @@
 
     public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
             long duration, String tag);
-    public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
-            String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
-            Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
-            boolean sticky, int userId, boolean allowBackgroundActivityStarts);
+    public abstract int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+            int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
+            int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
+            Bundle bOptions, boolean serialized, boolean sticky, int userId,
+            boolean allowBackgroundActivityStarts);
     public abstract ComponentName startServiceInPackage(int uid, Intent service,
             String resolvedType, boolean fgRequired, String callingPackage, int userId,
             boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index ce71998..bcbeb22 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -291,6 +291,9 @@
 
     /** Send current location and size to the WM to set tap exclude region for this view. */
     private void updateLocation() {
+        if (!isAttachedToWindow()) {
+            return;
+        }
         try {
             getLocationInWindow(mLocationInWindow);
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
@@ -429,6 +432,9 @@
 
     /** Report to server that tap exclude region on hosting display should be cleared. */
     private void cleanTapExcludeRegion() {
+        if (!isAttachedToWindow()) {
+            return;
+        }
         // Update tap exclude region with an empty rect to clean the state on server.
         try {
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 13eec58..040ad06 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -46,6 +46,8 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+
+import com.android.internal.annotations.Immutable;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsNotedCallback;
@@ -2210,6 +2212,115 @@
     }
 
     /**
+     * Request for getting historical app op usage. The request acts
+     * as a filtering criteria when querying historical op usage.
+     *
+     * @hide
+     */
+    @Immutable
+    @TestApi
+    @SystemApi
+    public static final class HistoricalOpsRequest {
+        private final int mUid;
+        private final @Nullable String mPackageName;
+        private final @Nullable List<String> mOpNames;
+        private final long mBeginTimeMillis;
+        private final long mEndTimeMillis;
+
+        private HistoricalOpsRequest(int uid, @Nullable String packageName,
+                @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis) {
+            mUid = uid;
+            mPackageName = packageName;
+            mOpNames = opNames;
+            mBeginTimeMillis = beginTimeMillis;
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /**
+         * Builder for creating a {@link HistoricalOpsRequest}.
+         *
+         * @hide
+         */
+        @TestApi
+        @SystemApi
+        public static final class Builder {
+            private int mUid = Process.INVALID_UID;
+            private @Nullable String mPackageName;
+            private @Nullable List<String> mOpNames;
+            private final long mBeginTimeMillis;
+            private final long mEndTimeMillis;
+
+            /**
+             * Creates a new builder.
+             *
+             * @param beginTimeMillis The beginning of the interval in milliseconds since
+             *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
+             *     negative.
+             * @param endTimeMillis The end of the interval in milliseconds since
+             *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
+             *     {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
+             *     history including ops that happen while this call is in flight.
+             */
+            public Builder(long beginTimeMillis, long endTimeMillis) {
+                Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
+                        "beginTimeMillis must be non negative and lesser than endTimeMillis");
+                mBeginTimeMillis = beginTimeMillis;
+                mEndTimeMillis = endTimeMillis;
+            }
+
+            /**
+             * Sets the UID to query for.
+             *
+             * @param uid The uid. Pass {@link android.os.Process#INVALID_UID} for any uid.
+             * @return This builder.
+             */
+            public @NonNull Builder setUid(int uid) {
+                Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+                        "uid must be " + Process.INVALID_UID + " or non negative");
+                mUid = uid;
+                return this;
+            }
+
+            /**
+             * Sets the package to query for.
+             *
+             * @param packageName The package name. <code>Null</code> for any package.
+             * @return This builder.
+             */
+            public @NonNull Builder setPackageName(@Nullable String packageName) {
+                mPackageName = packageName;
+                return this;
+            }
+
+            /**
+             * Sets the op names to query for.
+             *
+             * @param opNames The op names. <code>Null</code> for any op.
+             * @return This builder.
+             */
+            public @NonNull Builder setOpNames(@Nullable List<String> opNames) {
+                if (opNames != null) {
+                    final int opCount = opNames.size();
+                    for (int i = 0; i < opCount; i++) {
+                        Preconditions.checkArgument(AppOpsManager.strOpToOp(
+                                opNames.get(i)) != AppOpsManager.OP_NONE);
+                    }
+                }
+                mOpNames = opNames;
+                return this;
+            }
+
+            /**
+             * @return a new {@link HistoricalOpsRequest}.
+             */
+            public @NonNull HistoricalOpsRequest build() {
+                return new HistoricalOpsRequest(mUid, mPackageName, mOpNames,
+                        mBeginTimeMillis, mEndTimeMillis);
+            }
+        }
+    }
+
+    /**
      * This class represents historical app op state of all UIDs for a given time interval.
      *
      * @hide
@@ -3671,26 +3782,7 @@
     /**
      * Retrieve historical app op stats for a period.
      *
-     * <p>Historical data can be obtained
-     * for a specific package by specifying the <code>packageName</code> argument,
-     * for a specific UID if specifying the <code>uid</code> argument, for a
-     * specific package in a UID by specifying the <code>packageName</code>
-     * and the <code>uid</code> arguments, for all packages by passing
-     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
-     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
-     *  Similarly, you can specify the <code>opNames</code> argument to get
-     *  data only for these ops or <code>null</code> for all ops.
-     *
-     * @param uid The UID to query for.
-     * @param packageName The package to query for.
-     * @param beginTimeMillis The beginning of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
-     *     negative.
-     * @param endTimeMillis The end of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
-     *     {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
-     *     history including ops that happen while this call is in flight.
-     * @param opNames The ops to query for. Pass {@code null} for all ops.
+     * @param request A request object describing the data being queried for.
      * @param executor Executor on which to run the callback. If <code>null</code>
      *     the callback is executed on the default executor running on the main thread.
      * @param callback Callback on which to deliver the result.
@@ -3702,13 +3794,13 @@
     @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public void getHistoricalOps(int uid, @Nullable String packageName,
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+    public void getHistoricalOps(@NonNull HistoricalOpsRequest request,
             @NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            mService.getHistoricalOps(uid, packageName, opNames, beginTimeMillis, endTimeMillis,
+            mService.getHistoricalOps(request.mUid, request.mPackageName, request.mOpNames,
+                    request.mBeginTimeMillis, request.mEndTimeMillis,
                     new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
@@ -3725,29 +3817,12 @@
 
     /**
      * Retrieve historical app op stats for a period.
-     *
-     * <p>Historical data can be obtained
-     * for a specific package by specifying the <code>packageName</code> argument,
-     * for a specific UID if specifying the <code>uid</code> argument, for a
-     * specific package in a UID by specifying the <code>packageName</code>
-     * and the <code>uid</code> arguments, for all packages by passing
-     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
-     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
-     *  Similarly, you can specify the <code>opNames</code> argument to get
-     *  data only for these ops or <code>null</code> for all ops.
      *  <p>
      *  This method queries only the on disk state and the returned ops are raw,
      *  which is their times are relative to the history start as opposed to the
      *  epoch start.
      *
-     * @param uid The UID to query for.
-     * @param packageName The package to query for.
-     * @param beginTimeMillis The beginning of the interval in milliseconds since
-     *      history start. History time grows as one goes into the past.
-     * @param endTimeMillis The end of the interval in milliseconds since
-     *      history start. History time grows as one goes into the past. Must be after
-     *     {@code beginTimeMillis}.
-     * @param opNames The ops to query for. Pass {@code null} for all ops.
+     * @param request A request object describing the data being queried for.
      * @param executor Executor on which to run the callback. If <code>null</code>
      *     the callback is executed on the default executor running on the main thread.
      * @param callback Callback on which to deliver the result.
@@ -3758,15 +3833,15 @@
      */
     @TestApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+    public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
             @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            mService.getHistoricalOpsFromDiskRaw(uid, packageName, opNames, beginTimeMillis,
-                    endTimeMillis, new RemoteCallback((result) -> {
-               final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+            mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
+                    request.mOpNames, request.mBeginTimeMillis, request.mEndTimeMillis,
+                    new RemoteCallback((result) -> {
+                final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     executor.execute(() -> callback.accept(ops));
diff --git a/core/java/android/app/IInputForwarder.aidl b/core/java/android/app/IInputForwarder.aidl
deleted file mode 100644
index d6be63e..0000000
--- a/core/java/android/app/IInputForwarder.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import android.view.InputEvent;
-
-/**
- * Forwards input events into owned activity container, used in {@link android.app.ActivityView}.
- * To forward input to other apps {@link android.Manifest.permission.INJECT_EVENTS} permission is
- * required.
- * @hide
- */
-interface IInputForwarder {
-    boolean forwardEvent(in InputEvent event);
-}
\ No newline at end of file
diff --git a/core/java/android/app/admin/TEST_MAPPING b/core/java/android/app/admin/TEST_MAPPING
new file mode 100644
index 0000000..8f88c22
--- /dev/null
+++ b/core/java/android/app/admin/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "frameworks/base/services/devicepolicy"
+    }
+  ]
+}
diff --git a/core/java/android/content/ContentInterface.java b/core/java/android/content/ContentInterface.java
index 3d732eb..d41d8d9 100644
--- a/core/java/android/content/ContentInterface.java
+++ b/core/java/android/content/ContentInterface.java
@@ -36,6 +36,8 @@
  * These methods have been extracted into a general interface so that APIs can
  * be flexible in accepting either a {@link ContentProvider}, a
  * {@link ContentResolver}, or a {@link ContentProviderClient}.
+ *
+ * @hide
  */
 public interface ContentInterface {
     public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f138d39..e06322df 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -134,7 +134,7 @@
     private boolean mNoPerms;
     private boolean mSingleUser;
 
-    private final ThreadLocal<String> mCallingPackage = new ThreadLocal<>();
+    private ThreadLocal<String> mCallingPackage;
 
     private Transport mTransport = new Transport();
 
@@ -2034,6 +2034,7 @@
 
     private void attachInfo(Context context, ProviderInfo info, boolean testing) {
         mNoPerms = testing;
+        mCallingPackage = new ThreadLocal<>();
 
         /*
          * Only allow it to be set once, so after the content service gives
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7672ccf..bbfa5cc 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -609,10 +609,60 @@
     private static final int SLOW_THRESHOLD_MILLIS = 500;
     private final Random mRandom = new Random();  // guarded by itself
 
-    public ContentResolver(Context context) {
+    public ContentResolver(@Nullable Context context) {
+        this(context, null);
+    }
+
+    /** {@hide} */
+    public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
         mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+        mWrapped = wrapped;
+    }
+
+    /** {@hide} */
+    public static ContentResolver wrap(@NonNull ContentInterface wrapped) {
+        Preconditions.checkNotNull(wrapped);
+
+        return new ContentResolver(null, wrapped) {
+            @Override
+            public void unstableProviderDied(IContentProvider icp) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public boolean releaseUnstableProvider(IContentProvider icp) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public boolean releaseProvider(IContentProvider icp) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            protected IContentProvider acquireUnstableProvider(Context c, String name) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            protected IContentProvider acquireProvider(Context c, String name) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    /**
+     * Create a {@link ContentResolver} instance that redirects all its methods
+     * to the given {@link ContentProvider}.
+     */
+    public static ContentResolver wrap(@NonNull ContentProvider wrapped) {
+        return wrap((ContentInterface) wrapped);
+    }
+
+    /**
+     * Create a {@link ContentResolver} instance that redirects all its methods
+     * to the given {@link ContentProviderClient}.
+     */
+    public static ContentResolver wrap(@NonNull ContentProviderClient wrapped) {
+        return wrap((ContentInterface) wrapped);
     }
 
     /** @hide */
@@ -660,6 +710,12 @@
     public final @Nullable String getType(@NonNull Uri url) {
         Preconditions.checkNotNull(url, "url");
 
+        try {
+            if (mWrapped != null) return mWrapped.getType(url);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         // XXX would like to have an acquireExistingUnstableProvider for this.
         IContentProvider provider = acquireExistingProvider(url);
         if (provider != null) {
@@ -715,6 +771,12 @@
         Preconditions.checkNotNull(url, "url");
         Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
 
+        try {
+            if (mWrapped != null) return mWrapped.getStreamTypes(url, mimeTypeFilter);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             return null;
@@ -843,6 +905,15 @@
             @Nullable String[] projection, @Nullable Bundle queryArgs,
             @Nullable CancellationSignal cancellationSignal) {
         Preconditions.checkNotNull(uri, "uri");
+
+        try {
+            if (mWrapped != null) {
+                return mWrapped.query(uri, projection, queryArgs, cancellationSignal);
+            }
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider unstableProvider = acquireUnstableProvider(uri);
         if (unstableProvider == null) {
             return null;
@@ -942,6 +1013,13 @@
     @Override
     public final @Nullable Uri canonicalize(@NonNull Uri url) {
         Preconditions.checkNotNull(url, "url");
+
+        try {
+            if (mWrapped != null) return mWrapped.canonicalize(url);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             return null;
@@ -979,6 +1057,13 @@
     @Override
     public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
         Preconditions.checkNotNull(url, "url");
+
+        try {
+            if (mWrapped != null) return mWrapped.uncanonicalize(url);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             return null;
@@ -1015,6 +1100,13 @@
     public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
             @Nullable CancellationSignal cancellationSignal) {
         Preconditions.checkNotNull(url, "url");
+
+        try {
+            if (mWrapped != null) return mWrapped.refresh(url, args, cancellationSignal);
+        } catch (RemoteException e) {
+            return false;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             return false;
@@ -1126,6 +1218,12 @@
     @Override
     public final @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
             @Nullable CancellationSignal signal) throws FileNotFoundException {
+        try {
+            if (mWrapped != null) return mWrapped.openFile(uri, mode, signal);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         return openFileDescriptor(uri, mode, signal);
     }
 
@@ -1237,6 +1335,12 @@
     @Override
     public final @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
             @Nullable CancellationSignal signal) throws FileNotFoundException {
+        try {
+            if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, signal);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         return openAssetFileDescriptor(uri, mode, signal);
     }
 
@@ -1448,6 +1552,14 @@
     public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
             @NonNull String mimeTypeFilter, @Nullable Bundle opts,
             @Nullable CancellationSignal signal) throws FileNotFoundException {
+        try {
+            if (mWrapped != null) {
+                return mWrapped.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
+            }
+        } catch (RemoteException e) {
+            return null;
+        }
+
         return openTypedAssetFileDescriptor(uri, mimeTypeFilter, opts, signal);
     }
 
@@ -1664,6 +1776,13 @@
     public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
                 @Nullable ContentValues values) {
         Preconditions.checkNotNull(url, "url");
+
+        try {
+            if (mWrapped != null) return mWrapped.insert(url, values);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown URL " + url);
@@ -1705,6 +1824,13 @@
                     throws RemoteException, OperationApplicationException {
         Preconditions.checkNotNull(authority, "authority");
         Preconditions.checkNotNull(operations, "operations");
+
+        try {
+            if (mWrapped != null) return mWrapped.applyBatch(authority, operations);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         ContentProviderClient provider = acquireContentProviderClient(authority);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown authority " + authority);
@@ -1731,6 +1857,13 @@
                 @NonNull ContentValues[] values) {
         Preconditions.checkNotNull(url, "url");
         Preconditions.checkNotNull(values, "values");
+
+        try {
+            if (mWrapped != null) return mWrapped.bulkInsert(url, values);
+        } catch (RemoteException e) {
+            return 0;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown URL " + url);
@@ -1764,6 +1897,13 @@
     public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
             @Nullable String[] selectionArgs) {
         Preconditions.checkNotNull(url, "url");
+
+        try {
+            if (mWrapped != null) return mWrapped.delete(url, where, selectionArgs);
+        } catch (RemoteException e) {
+            return 0;
+        }
+
         IContentProvider provider = acquireProvider(url);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown URL " + url);
@@ -1801,6 +1941,13 @@
             @Nullable ContentValues values, @Nullable String where,
             @Nullable String[] selectionArgs) {
         Preconditions.checkNotNull(uri, "uri");
+
+        try {
+            if (mWrapped != null) return mWrapped.update(uri, values, where, selectionArgs);
+        } catch (RemoteException e) {
+            return 0;
+        }
+
         IContentProvider provider = acquireProvider(uri);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown URI " + uri);
@@ -1844,6 +1991,13 @@
             @Nullable String arg, @Nullable Bundle extras) {
         Preconditions.checkNotNull(authority, "authority");
         Preconditions.checkNotNull(method, "method");
+
+        try {
+            if (mWrapped != null) return mWrapped.call(authority, method, arg, extras);
+        } catch (RemoteException e) {
+            return null;
+        }
+
         IContentProvider provider = acquireProvider(authority);
         if (provider == null) {
             throw new IllegalArgumentException("Unknown authority " + authority);
@@ -3193,6 +3347,7 @@
     @UnsupportedAppUsage
     final String mPackageName;
     final int mTargetSdkVersion;
+    final ContentInterface mWrapped;
 
     private static final String TAG = "ContentResolver";
 
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index f413d7c..0c07a67 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -65,7 +65,8 @@
     @SystemApi
     public static final int CAPABILITY_NONE = 0x0;
     /**
-     * The device can properly apply transforms over protected content.
+     * The device can use GPU composition on protected content (layers whose buffers are protected
+     * in the trusted memory zone).
      *
      * @hide
      */
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 44b653c..8a0a9c7 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -563,7 +563,8 @@
      * 0 produces a grayscale image, 1 is normal.
      *
      * @hide
-     * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)}.
+     * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)} instead. The level passed
+     * as a parameter here will be rounded to the nearest hundredth.
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 97868fa..64448fd 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,7 +16,6 @@
 
 package android.hardware.input;
 
-import android.app.IInputForwarder;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
@@ -82,7 +81,4 @@
     void setCustomPointerIcon(in PointerIcon icon);
 
     void requestPointerCapture(IBinder windowToken, boolean enabled);
-
-    /** Create input forwarder to deliver touch events to owned display. */
-    IInputForwarder createInputForwarder(int displayId);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index bfb7c58..fec5c34 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -21,7 +21,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
-import android.app.IInputForwarder;
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.os.Binder;
@@ -934,26 +933,6 @@
         }
     }
 
-
-    /**
-     * Create an {@link IInputForwarder} targeted to provided display.
-     * {@link android.Manifest.permission.INJECT_EVENTS} permission is required to call this method.
-     *
-     * @param displayId Id of the target display where input events should be forwarded.
-     *                  Display must exist and must be owned by the caller.
-     * @return The forwarder instance.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public IInputForwarder createInputForwarder(int displayId) {
-        try {
-            return mIm.createInputForwarder(displayId);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
     private void populateInputDevicesLocked() {
         if (mInputDevicesChangedListener == null) {
             final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 5708342..d282967 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1281,8 +1281,9 @@
      * @see DocumentsProvider#openDocumentThumbnail(String, Point,
      *      android.os.CancellationSignal)
      */
-    public static Bitmap getDocumentThumbnail(ContentInterface content, Uri documentUri, Point size,
-            CancellationSignal signal) throws FileNotFoundException {
+    public static @Nullable Bitmap getDocumentThumbnail(@NonNull ContentResolver content,
+            @NonNull Uri documentUri, @NonNull Point size, @Nullable CancellationSignal signal)
+            throws FileNotFoundException {
         try {
             return ContentResolver.loadThumbnail(content, documentUri, Point.convert(size), signal,
                     ImageDecoder.ALLOCATOR_SOFTWARE);
@@ -1295,12 +1296,6 @@
         }
     }
 
-    @Deprecated
-    public static Bitmap getDocumentThumbnail(ContentResolver content, Uri documentUri, Point size,
-            CancellationSignal signal) throws FileNotFoundException {
-        return getDocumentThumbnail((ContentInterface) content, documentUri, size, signal);
-    }
-
     /**
      * Create a new document with given MIME type and display name.
      *
@@ -1309,8 +1304,9 @@
      * @param displayName name of new document
      * @return newly created document, or {@code null} if failed
      */
-    public static Uri createDocument(ContentInterface content, Uri parentDocumentUri,
-            String mimeType, String displayName) throws FileNotFoundException {
+    public static @Nullable Uri createDocument(@NonNull ContentResolver content,
+            @NonNull Uri parentDocumentUri, @NonNull String mimeType, @NonNull String displayName)
+            throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
@@ -1327,12 +1323,6 @@
         }
     }
 
-    @Deprecated
-    public static Uri createDocument(ContentResolver content, Uri parentDocumentUri,
-            String mimeType, String displayName) throws FileNotFoundException {
-        return createDocument((ContentInterface) content, parentDocumentUri, mimeType, displayName);
-    }
-
     /**
      * Test if a document is descendant (child, grandchild, etc) from the given
      * parent.
@@ -1342,7 +1332,7 @@
      * @return if given document is a descendant of the given parent.
      * @see Root#FLAG_SUPPORTS_IS_CHILD
      */
-    public static boolean isChildDocument(@NonNull ContentInterface content,
+    public static boolean isChildDocument(@NonNull ContentResolver content,
             @NonNull Uri parentDocumentUri, @NonNull Uri childDocumentUri)
             throws FileNotFoundException {
         Preconditions.checkNotNull(content, "content can not be null");
@@ -1369,12 +1359,6 @@
         }
     }
 
-    @Deprecated
-    public static boolean isChildDocument(ContentResolver content, Uri parentDocumentUri,
-            Uri childDocumentUri) throws FileNotFoundException {
-        return isChildDocument((ContentInterface) content, parentDocumentUri, childDocumentUri);
-    }
-
     /**
      * Change the display name of an existing document.
      * <p>
@@ -1388,8 +1372,8 @@
      * @return the existing or new document after the rename, or {@code null} if
      *         failed.
      */
-    public static Uri renameDocument(ContentInterface content, Uri documentUri,
-            String displayName) throws FileNotFoundException {
+    public static @Nullable Uri renameDocument(@NonNull ContentResolver content,
+            @NonNull Uri documentUri, @NonNull String displayName) throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
@@ -1406,19 +1390,13 @@
         }
     }
 
-    @Deprecated
-    public static Uri renameDocument(ContentResolver content, Uri documentUri,
-            String displayName) throws FileNotFoundException {
-        return renameDocument((ContentInterface) content, documentUri, displayName);
-    }
-
     /**
      * Delete the given document.
      *
      * @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
      * @return if the document was deleted successfully.
      */
-    public static boolean deleteDocument(ContentInterface content, Uri documentUri)
+    public static boolean deleteDocument(@NonNull ContentResolver content, @NonNull Uri documentUri)
             throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
@@ -1434,12 +1412,6 @@
         }
     }
 
-    @Deprecated
-    public static boolean deleteDocument(ContentResolver content, Uri documentUri)
-            throws FileNotFoundException {
-        return deleteDocument((ContentInterface) content, documentUri);
-    }
-
     /**
      * Copies the given document.
      *
@@ -1448,8 +1420,9 @@
      *         document's copy.
      * @return the copied document, or {@code null} if failed.
      */
-    public static Uri copyDocument(ContentInterface content, Uri sourceDocumentUri,
-            Uri targetParentDocumentUri) throws FileNotFoundException {
+    public static @Nullable Uri copyDocument(@NonNull ContentResolver content,
+            @NonNull Uri sourceDocumentUri, @NonNull Uri targetParentDocumentUri)
+            throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
@@ -1465,12 +1438,6 @@
         }
     }
 
-    @Deprecated
-    public static Uri copyDocument(ContentResolver content, Uri sourceDocumentUri,
-            Uri targetParentDocumentUri) throws FileNotFoundException {
-        return copyDocument((ContentInterface) content, sourceDocumentUri, targetParentDocumentUri);
-    }
-
     /**
      * Moves the given document under a new parent.
      *
@@ -1480,8 +1447,9 @@
      *         document.
      * @return the moved document, or {@code null} if failed.
      */
-    public static Uri moveDocument(ContentInterface content, Uri sourceDocumentUri,
-            Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
+    public static @Nullable Uri moveDocument(@NonNull ContentResolver content,
+            @NonNull Uri sourceDocumentUri, @NonNull Uri sourceParentDocumentUri,
+            @NonNull Uri targetParentDocumentUri) throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
@@ -1498,13 +1466,6 @@
         }
     }
 
-    @Deprecated
-    public static Uri moveDocument(ContentResolver content, Uri sourceDocumentUri,
-            Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
-        return moveDocument((ContentInterface) content, sourceDocumentUri, sourceParentDocumentUri,
-                targetParentDocumentUri);
-    }
-
     /**
      * Removes the given document from a parent directory.
      *
@@ -1515,8 +1476,8 @@
      * @param parentDocumentUri parent document of the document to remove.
      * @return true if the document was removed successfully.
      */
-    public static boolean removeDocument(ContentInterface content, Uri documentUri,
-            Uri parentDocumentUri) throws FileNotFoundException {
+    public static boolean removeDocument(@NonNull ContentResolver content, @NonNull Uri documentUri,
+            @NonNull Uri parentDocumentUri) throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
@@ -1532,34 +1493,23 @@
         }
     }
 
-    @Deprecated
-    public static boolean removeDocument(ContentResolver content, Uri documentUri,
-            Uri parentDocumentUri) throws FileNotFoundException {
-        return removeDocument((ContentInterface) content, documentUri, parentDocumentUri);
-    }
-
     /**
      * Ejects the given root. It throws {@link IllegalStateException} when ejection failed.
      *
      * @param rootUri root with {@link Root#FLAG_SUPPORTS_EJECT} to be ejected
      */
-    public static void ejectRoot(ContentInterface content, Uri rootUri) {
+    public static void ejectRoot(@NonNull ContentResolver content, @NonNull Uri rootUri) {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
 
             content.call(rootUri.getAuthority(),
                     METHOD_EJECT_ROOT, null, in);
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to eject", e);
         }
     }
 
-    @Deprecated
-    public static void ejectRoot(ContentResolver content, Uri rootUri) {
-        ejectRoot((ContentInterface) content, rootUri);
-    }
-
     /**
      * Returns metadata associated with the document. The type of metadata returned
      * is specific to the document type. For example the data returned for an image
@@ -1590,7 +1540,7 @@
      * @param documentUri a Document URI
      * @return a Bundle of Bundles.
      */
-    public static @Nullable Bundle getDocumentMetadata(@NonNull ContentInterface content,
+    public static @Nullable Bundle getDocumentMetadata(@NonNull ContentResolver content,
             @NonNull Uri documentUri) throws FileNotFoundException {
         Preconditions.checkNotNull(content, "content can not be null");
         Preconditions.checkNotNull(documentUri, "documentUri can not be null");
@@ -1607,12 +1557,6 @@
         }
     }
 
-    @Deprecated
-    public static Bundle getDocumentMetadata(ContentResolver content, Uri documentUri)
-            throws FileNotFoundException {
-        return getDocumentMetadata((ContentInterface) content, documentUri);
-    }
-
     /**
      * Finds the canonical path from the top of the document tree.
      *
@@ -1626,8 +1570,8 @@
      * @return the path of the document, or {@code null} if failed.
      * @see DocumentsProvider#findDocumentPath(String, String)
      */
-    public static Path findDocumentPath(ContentInterface content, Uri treeUri)
-            throws FileNotFoundException {
+    public static @Nullable Path findDocumentPath(@NonNull ContentResolver content,
+            @NonNull Uri treeUri) throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, treeUri);
@@ -1642,12 +1586,6 @@
         }
     }
 
-    @Deprecated
-    public static Path findDocumentPath(ContentResolver content, Uri treeUri)
-            throws FileNotFoundException {
-        return findDocumentPath((ContentInterface) content, treeUri);
-    }
-
     /**
      * Creates an intent for obtaining a web link for the specified document.
      *
@@ -1699,8 +1637,8 @@
      * @see DocumentsProvider#createWebLinkIntent(String, Bundle)
      * @see Intent#EXTRA_EMAIL
      */
-    public static IntentSender createWebLinkIntent(ContentInterface content, Uri uri,
-            Bundle options) throws FileNotFoundException {
+    public static @Nullable IntentSender createWebLinkIntent(@NonNull ContentResolver content,
+            @NonNull Uri uri, @Nullable Bundle options) throws FileNotFoundException {
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, uri);
@@ -1721,12 +1659,6 @@
         }
     }
 
-    @Deprecated
-    public static IntentSender createWebLinkIntent(ContentResolver content, Uri uri,
-            Bundle options) throws FileNotFoundException {
-        return createWebLinkIntent((ContentInterface) content, uri, options);
-    }
-
     /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c4ab91f..8a90cad 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -44,9 +44,9 @@
     int checkPackage(int uid, String packageName);
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
-    void getHistoricalOps(int uid, String packageName, in String[] ops, long beginTimeMillis,
+    void getHistoricalOps(int uid, String packageName, in List<String> ops, long beginTimeMillis,
             long endTimeMillis, in RemoteCallback callback);
-    void getHistoricalOpsFromDiskRaw(int uid, String packageName, in String[] ops,
+    void getHistoricalOpsFromDiskRaw(int uid, String packageName, in List<String> ops,
             long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
     void offsetHistory(long duration);
     void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a8ad810..c46f867 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -137,6 +137,7 @@
         mDismissStartTarget = mTargets.get(0);
         mDismissEndTarget = mTargets.get(mTargets.size() - 1);
         mMiddleTarget = mTargets.get(mTargets.size() / 2);
+        mMiddleTarget.isMiddleTarget = true;
     }
 
     /**
@@ -438,6 +439,8 @@
 
         public final int flag;
 
+        public boolean isMiddleTarget;
+
         /**
          * Multiplier used to calculate distance to snap position. The lower this value, the harder
          * it's to snap on this target
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
index 1b691d6..c23ca83 100644
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ b/core/res/res/layout/notification_material_media_seekbar.xml
@@ -30,6 +30,7 @@
         android:maxHeight="3dp"
         android:paddingTop="24dp"
         android:paddingBottom="24dp"
+        android:clickable="true"
         android:layout_marginBottom="-24dp"
         android:layout_marginTop="-12dp"
         android:splitTrack="false"
diff --git a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
index 02a9adf..bff6b5f 100644
--- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
@@ -60,7 +60,8 @@
                 DocumentsContract.buildDocumentUri(TestDocumentsProvider.AUTHORITY, DOCUMENT_ID);
         try (ContentProviderClient client =
                      mResolver.acquireUnstableContentProviderClient(docUri)) {
-            final Path actual = DocumentsContract.findDocumentPath(client, docUri);
+            final Path actual = DocumentsContract.findDocumentPath(
+                    ContentResolver.wrap(client), docUri);
             assertEquals(expected, actual);
         }
     }
diff --git a/media/OWNERS b/media/OWNERS
index 03b751c..eb26367 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -11,3 +11,6 @@
 marcone@google.com
 sungsoo@google.com
 wjia@google.com
+
+# For maintaining sync with AndroidX code
+per-file ExifInterface.java = jinpark@google.com, sungsoo@google.com
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e0d178f..29ae1b2 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -137,6 +137,7 @@
     static_libs: [
         "SystemUI-core",
     ],
+    resource_dirs: [],
 
     platform_apis: true,
     product_specific: true,
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7a7d1f6..bb34a87 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -461,6 +461,9 @@
         if (mSnapAlgorithm == null) {
             mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
                     mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets, mDockSide);
+            if (mSnapTargetBeforeMinimized != null && mSnapTargetBeforeMinimized.isMiddleTarget) {
+                mSnapTargetBeforeMinimized = mSnapAlgorithm.getMiddleTarget();
+            }
         }
         if (mMinimizedSnapAlgorithm == null) {
             mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 8160e04..6714b0a 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -660,7 +660,7 @@
             ++mCount;
         } catch (Exception e) {
             Slog.e(TAG, "Error when attempting restore: " + e.toString());
-            keyValueAgentErrorCleanup();
+            keyValueAgentErrorCleanup(false);
             executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
         }
     }
@@ -686,6 +686,7 @@
         boolean staging = !packageName.equals("android");
         ParcelFileDescriptor stage;
         File downloadFile = (staging) ? mStageName : mBackupDataName;
+        boolean startedAgentRestore = false;
 
         try {
             IBackupTransport transport =
@@ -766,13 +767,15 @@
             long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
                     mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
+            startedAgentRestore = true;
             mAgent.doRestore(mBackupData, appVersionCode, mNewState,
                     mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
         } catch (Exception e) {
             Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
                     packageName, e.toString());
-            keyValueAgentErrorCleanup();    // clears any pending timeout messages as well
+            // Clears any pending timeout messages as well.
+            keyValueAgentErrorCleanup(startedAgentRestore);
 
             // After a restore failure we go back to running the queue.  If there
             // are no more packages to be restored that will be handled by the
@@ -832,7 +835,7 @@
             Slog.e(TAG, "Unable to finalize restore of " + packageName);
             EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
                     packageName, e.toString());
-            keyValueAgentErrorCleanup();
+            keyValueAgentErrorCleanup(true);
             executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
         }
     }
@@ -1110,11 +1113,18 @@
         mListener.onFinished(callerLogString);
     }
 
-    void keyValueAgentErrorCleanup() {
-        // If the agent fails restore, it might have put the app's data
-        // into an incoherent state.  For consistency we wipe its data
-        // again in this case before continuing with normal teardown
-        backupManagerService.clearApplicationDataAfterRestoreFailure(mCurrentPackage.packageName);
+    /**
+     * @param clearAppData - set to {@code true} if the backup agent had already been invoked when
+     *     restore faied. So the app data may be in corrupted state and has to be cleared.
+     */
+    void keyValueAgentErrorCleanup(boolean clearAppData) {
+        if (clearAppData) {
+            // If the agent fails restore, it might have put the app's data
+            // into an incoherent state.  For consistency we wipe its data
+            // again in this case before continuing with normal teardown
+            backupManagerService.clearApplicationDataAfterRestoreFailure(
+                    mCurrentPackage.packageName);
+        }
         keyValueAgentCleanup();
     }
 
@@ -1251,7 +1261,7 @@
                 // Some kind of horrible semantic error; we're in an unexpected state.
                 // Back off hard and wind up.
                 Slog.e(TAG, "Unexpected restore callback into state " + mState);
-                keyValueAgentErrorCleanup();
+                keyValueAgentErrorCleanup(true);
                 nextState = UnifiedRestoreState.FINAL;
                 break;
             }
@@ -1271,7 +1281,7 @@
         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
                 mCurrentPackage.packageName, "restore timeout");
         // Handle like an agent that threw on invocation: wipe it and go on to the next
-        keyValueAgentErrorCleanup();
+        keyValueAgentErrorCleanup(true);
         executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2f20572..3c0430f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2704,8 +2704,8 @@
     public void batterySendBroadcast(Intent intent) {
         synchronized (this) {
             broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                    OP_NONE, null, false, false,
-                    -1, SYSTEM_UID, UserHandle.USER_ALL);
+                    OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+                    Binder.getCallingPid(), UserHandle.USER_ALL);
         }
     }
 
@@ -3823,12 +3823,13 @@
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
                     if (isInstantApp) {
                         intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
-                        broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
-                                null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
-                                resolvedUserId, false);
+                        broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+                                null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, false,
+                                false, resolvedUserId, false);
                     } else {
-                        broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
-                                null, null, null, null, false, false, resolvedUserId, false);
+                        broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+                                null, 0, null, null, null, null, false, false, resolvedUserId,
+                                false);
                     }
 
                     if (observer != null) {
@@ -4263,7 +4264,8 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null, OP_NONE,
-                null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
+                null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                Binder.getCallingPid(), UserHandle.getUserId(uid));
     }
 
     private void cleanupDisabledPackageComponentsLocked(
@@ -8709,6 +8711,8 @@
 
             mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
 
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
             long ident = Binder.clearCallingIdentity();
             try {
                 Intent intent = new Intent(Intent.ACTION_USER_STARTED);
@@ -8717,7 +8721,7 @@
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null, null, OP_NONE,
-                        null, false, false, MY_PID, SYSTEM_UID,
+                        null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
                         currentUserId);
                 intent = new Intent(Intent.ACTION_USER_STARTING);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -8731,7 +8735,8 @@
                             }
                         }, 0, null, null,
                         new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
-                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+                        UserHandle.USER_ALL);
             } catch (Throwable t) {
                 Slog.wtf(TAG, "Failed sending first user broadcasts", t);
             } finally {
@@ -14369,10 +14374,12 @@
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
             Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
-            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+            boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+            int realCallingPid, int userId) {
         return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
             resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
-            sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
+            sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
+            false /* allowBackgroundActivityStarts */);
     }
 
     @GuardedBy("this")
@@ -14380,8 +14387,8 @@
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
             Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
-            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
-            boolean allowBackgroundActivityStarts) {
+            boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+            int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
         intent = new Intent(intent);
 
         final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14430,7 +14437,7 @@
                 // PendingIntent), because that who is actually supplied the arguments.
                 if (checkComponentPermission(
                         android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
-                        Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
+                        realCallingPid, realCallingUid, -1, true)
                         != PackageManager.PERMISSION_GRANTED) {
                     String msg = "Permission Denial: " + intent.getAction()
                             + " broadcast from " + callerPackage + " (pid=" + callingPid
@@ -15118,15 +15125,15 @@
                     callerApp != null ? callerApp.info.packageName : null,
                     intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                     requiredPermissions, appOp, bOptions, serialized, sticky,
-                    callingPid, callingUid, userId);
+                    callingPid, callingUid, callingUid, callingPid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
 
-    int broadcastIntentInPackage(String packageName, int uid,
-            Intent intent, String resolvedType, IIntentReceiver resultTo,
+    int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+            int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle resultExtras,
             String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
             int userId, boolean allowBackgroundActivityStarts) {
@@ -15139,7 +15146,8 @@
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                     resultTo, resultCode, resultData, resultExtras,
                     requiredPermissions, OP_NONE, bOptions, serialized,
-                    sticky, -1, uid, userId, allowBackgroundActivityStarts);
+                    sticky, -1, uid, realCallingUid, realCallingPid, userId,
+                    allowBackgroundActivityStarts);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -17721,15 +17729,16 @@
         }
 
         @Override
-        public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
-                String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
-                Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
-                boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
+        public int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+                int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
+                int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
+                Bundle bOptions, boolean serialized, boolean sticky, int userId,
+                boolean allowBackgroundActivityStarts) {
             synchronized (ActivityManagerService.this) {
                 return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
-                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
-                        requiredPermission, bOptions, serialized, sticky, userId,
-                        allowBackgroundActivityStarts);
+                        realCallingUid, realCallingPid, intent, resolvedType, resultTo, resultCode,
+                        resultData, resultExtras, requiredPermission, bOptions, serialized, sticky,
+                        userId, allowBackgroundActivityStarts);
             }
         }
 
@@ -17830,8 +17839,8 @@
                         | Intent.FLAG_RECEIVER_FOREGROUND
                         | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
                 broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                        OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                        UserHandle.USER_ALL);
+                        OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                        Binder.getCallingPid(), UserHandle.USER_ALL);
                 if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
                     intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -17841,8 +17850,8 @@
                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                     }
                     broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                            OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                            UserHandle.USER_ALL);
+                            OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                            Binder.getCallingPid(), UserHandle.USER_ALL);
                 }
 
                 // Send a broadcast to PackageInstallers if the configuration change is interesting
@@ -17857,7 +17866,7 @@
                             new String[] { android.Manifest.permission.INSTALL_PACKAGES };
                     broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
                             permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                            UserHandle.USER_ALL);
+                            Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
                 }
             }
         }
@@ -17881,7 +17890,8 @@
                 }
 
                 broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                        OP_NONE, null, false, false, -1, SYSTEM_UID, UserHandle.USER_ALL);
+                        OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+                        Binder.getCallingPid(), UserHandle.USER_ALL);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index af56352..a08c829 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -423,9 +423,9 @@
                         // If a completion callback has been requested, require
                         // that the broadcast be delivered synchronously
                         int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
-                                uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
-                                requiredPermission, options, (finishedReceiver != null),
-                                false, userId,
+                                uid, callingUid, callingPid, finalIntent, resolvedType,
+                                finishedReceiver, code, null, null, requiredPermission, options,
+                                (finishedReceiver != null), false, userId,
                                 mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
                                 || allowTrampoline);
                         if (sent == ActivityManager.BROADCAST_SUCCESS) {
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 3ea1147..376999d 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -27,6 +27,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -108,7 +109,7 @@
         mIntent.setComponent(componentName);
         mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
                 AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
-                Process.SYSTEM_UID, mUserId);
+                Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7f6648a..ac20f6c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -371,7 +371,8 @@
                     | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
                     new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+                    Binder.getCallingUid(), Binder.getCallingPid(), userId);
         }
 
         // We need to delay unlocking managed profiles until the parent user
@@ -471,7 +472,7 @@
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
         mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
                 null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                userId);
+                Binder.getCallingUid(), Binder.getCallingPid(), userId);
 
         if (getUserInfo(userId).isManagedProfile()) {
             UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
@@ -484,8 +485,8 @@
                                 | Intent.FLAG_RECEIVER_FOREGROUND);
                 mInjector.broadcastIntent(profileUnlockedIntent,
                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, SYSTEM_UID,
-                        parent.id);
+                        null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                        Binder.getCallingPid(), parent.id);
             }
         }
 
@@ -543,7 +544,8 @@
                                 mInjector.getUserManager().makeInitialized(userInfo.id);
                             }
                         }, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, SYSTEM_UID, userId);
+                        null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                        Binder.getCallingPid(), userId);
             }
         }
 
@@ -573,7 +575,8 @@
                     }
                 }, 0, null, null,
                 new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+                AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+                Binder.getCallingUid(), Binder.getCallingPid(), userId);
     }
 
     int restartUser(final int userId, final boolean foreground) {
@@ -696,7 +699,8 @@
                 mInjector.broadcastIntent(stoppingIntent,
                         null, stoppingReceiver, 0, null, null,
                         new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                        Binder.getCallingPid(), UserHandle.USER_ALL);
             });
         }
     }
@@ -735,7 +739,8 @@
         mInjector.broadcastIntent(shutdownIntent,
                 null, shutdownReceiver, 0, null, null, null,
                 AppOpsManager.OP_NONE,
-                null, true, false, MY_PID, SYSTEM_UID, userId);
+                null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                Binder.getCallingPid(), userId);
     }
 
     void finishUserStopped(UserState uss) {
@@ -834,7 +839,8 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
         mInjector.broadcastIntent(intent,
                 null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+                null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                Binder.getCallingPid(), UserHandle.USER_ALL);
     }
 
     /**
@@ -950,6 +956,8 @@
 
         Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
 
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
         final long ident = Binder.clearCallingIdentity();
         try {
             final int oldUserId = getCurrentUserId();
@@ -1088,7 +1096,7 @@
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 mInjector.broadcastIntent(intent,
                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, SYSTEM_UID, userId);
+                        null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
             }
 
             if (foreground) {
@@ -1111,7 +1119,8 @@
                             }
                         }, 0, null, null,
                         new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+                        UserHandle.USER_ALL);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1427,6 +1436,8 @@
     }
 
     void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
         long ident = Binder.clearCallingIdentity();
         try {
             Intent intent;
@@ -1442,7 +1453,8 @@
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
                     mInjector.broadcastIntent(intent,
                             null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+                            null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+                            profileUserId);
                 }
             }
             if (newUserId >= 0) {
@@ -1457,7 +1469,8 @@
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
                     mInjector.broadcastIntent(intent,
                             null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+                            null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+                            profileUserId);
                 }
                 intent = new Intent(Intent.ACTION_USER_SWITCHED);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -1466,8 +1479,8 @@
                 mInjector.broadcastIntent(intent,
                         null, null, 0, null, null,
                         new String[] {android.Manifest.permission.MANAGE_USERS},
-                        AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                        UserHandle.USER_ALL);
+                        AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, callingUid,
+                        callingPid, UserHandle.USER_ALL);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2107,12 +2120,14 @@
         protected int broadcastIntent(Intent intent, String resolvedType,
                 IIntentReceiver resultTo, int resultCode, String resultData,
                 Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
-                boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+                boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+                int realCallingPid, int userId) {
             // TODO b/64165549 Verify that mLock is not held before calling AMS methods
             synchronized (mService) {
                 return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
                         resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
-                        ordered, sticky, callingPid, callingUid, userId);
+                        ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
+                        userId);
             }
         }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0e33090..70c28a8 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -38,6 +38,7 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalOpsRequest;
 import android.app.AppOpsManagerInternal;
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
 import android.content.BroadcastReceiver;
@@ -1024,25 +1025,29 @@
 
     @Override
     public void getHistoricalOps(int uid, @NonNull String packageName,
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
             @NonNull RemoteCallback callback) {
-        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
-                "uid must be " + Process.INVALID_UID + " or non negative");
-        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
-                "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        // Use the builder to validate arguments.
+        final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+                beginTimeMillis, endTimeMillis)
+                .setUid(uid)
+                .setPackageName(packageName)
+                .setOpNames(opNames)
+                .build();
         Preconditions.checkNotNull(callback, "callback cannot be null");
-        checkValidOpsOrNull(opNames);
 
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
 
+        final String[] opNamesArray = (opNames != null)
+                ? opNames.toArray(new String[opNames.size()]) : null;
         if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
             // TODO (bug:122218838): Remove once the feature fully enabled.
-            getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+            getHistoricalPackagesOpsCompat(uid, packageName, opNamesArray, beginTimeMillis,
                     endTimeMillis, callback);
         } else {
             // Must not hold the appops lock
-            mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+            mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
                     beginTimeMillis, endTimeMillis, callback);
         }
     }
@@ -1101,20 +1106,25 @@
 
     @Override
     public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
             @NonNull RemoteCallback callback) {
-        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
-                "uid must be " + Process.INVALID_UID + " or non negative");
-        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
-                "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        // Use the builder to validate arguments.
+        final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+                beginTimeMillis, endTimeMillis)
+                .setUid(uid)
+                .setPackageName(packageName)
+                .setOpNames(opNames)
+                .build();
         Preconditions.checkNotNull(callback, "callback cannot be null");
-        checkValidOpsOrNull(opNames);
 
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
 
+        final String[] opNamesArray = (opNames != null)
+                ? opNames.toArray(new String[opNames.size()]) : null;
+
         // Must not hold the appops lock
-        mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+        mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
                 beginTimeMillis, endTimeMillis, callback);
     }
 
@@ -4266,16 +4276,6 @@
         return packageNames;
     }
 
-    private static void checkValidOpsOrNull(String[] opNames) {
-        if (opNames != null) {
-            for (String opName : opNames) {
-                if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
-                    throw new IllegalArgumentException("Unknown op: " + opName);
-                }
-            }
-        }
-    }
-
     private final class ClientRestrictionState implements DeathRecipient {
         private final IBinder token;
         SparseArray<boolean[]> perUserRestrictions;
diff --git a/services/core/java/com/android/server/input/InputForwarder.java b/services/core/java/com/android/server/input/InputForwarder.java
deleted file mode 100644
index 00af839..0000000
--- a/services/core/java/com/android/server/input/InputForwarder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.input;
-
-import android.app.IInputForwarder;
-import android.hardware.input.InputManagerInternal;
-import android.view.InputEvent;
-
-import com.android.server.LocalServices;
-
-import static android.hardware.input.InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
-
-/**
- * Basic implementation of {@link IInputForwarder}.
- */
-class InputForwarder extends IInputForwarder.Stub {
-
-    private final InputManagerInternal mInputManagerInternal;
-    private final int mDisplayId;
-
-    InputForwarder(int displayId) {
-        mDisplayId = displayId;
-        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
-    }
-
-    @Override
-    public boolean forwardEvent(InputEvent event) {
-        event.setDisplayId(mDisplayId);
-        return mInputManagerInternal.injectInputEvent(event, INJECT_INPUT_EVENT_MODE_ASYNC);
-    }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 28393a2..87c7441 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,7 +17,6 @@
 package com.android.server.input;
 
 import android.annotation.NonNull;
-import android.app.IInputForwarder;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -1685,29 +1684,6 @@
         nativeMonitor(mPtr);
     }
 
-    // Binder call
-    @Override
-    public IInputForwarder createInputForwarder(int displayId) throws RemoteException {
-        if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
-                "createInputForwarder()")) {
-            throw new SecurityException("Requires INJECT_EVENTS permission");
-        }
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-        final Display display = displayManager.getDisplay(displayId);
-        if (display == null) {
-            throw new IllegalArgumentException(
-                    "Can't create input forwarder for non-existent displayId: " + displayId);
-        }
-        final int callingUid = Binder.getCallingUid();
-        final int displayOwnerUid = display.getOwnerUid();
-        if (callingUid != displayOwnerUid) {
-            throw new SecurityException(
-                    "Only owner of the display can forward input events to it.");
-        }
-
-        return new InputForwarder(displayId);
-    }
-
     // Native callback.
     private void notifyConfigurationChanged(long whenNanos) {
         mWindowManagerCallbacks.notifyConfigurationChanged();
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dac4b6f..e12d1dc 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -167,6 +167,27 @@
     }
 
     /**
+     * Marks a staged session as successful.
+     *
+     * <p>Only activated session can be marked as successful.
+     *
+     * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
+     *                  successful.
+     */
+    void markStagedSessionSuccessful(int sessionId) {
+        try {
+            mApexService.markStagedSessionSuccessful(sessionId);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            throw new RuntimeException(re);
+        } catch (Exception e) {
+            // It is fine to just log an exception in this case. APEXd will be able to recover in
+            // case markStagedSessionSuccessful fails.
+            Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
+        }
+    }
+
+    /**
      * Dumps various state information to the provided {@link PrintWriter} object.
      *
      * @param pw the {@link PrintWriter} object to send information to.
@@ -196,7 +217,7 @@
             ipw.increaseIndent();
             final ApexSessionInfo[] sessions = mApexService.getSessions();
             for (ApexSessionInfo si : sessions) {
-                ipw.println("Session ID: " + Integer.toString(si.sessionId));
+                ipw.println("Session ID: " + si.sessionId);
                 ipw.increaseIndent();
                 if (si.isUnknown) {
                     ipw.println("State: UNKNOWN");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6c212d6..d1ebc94 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -247,7 +247,8 @@
     }
 
     private void resumeSession(@NonNull PackageInstallerSession session) {
-        if (sessionContainsApex(session)) {
+        boolean hasApex = sessionContainsApex(session);
+        if (hasApex) {
             // Check with apexservice whether the apex packages have been activated.
             ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
             if (apexSessionInfo == null) {
@@ -271,7 +272,7 @@
                 mBgHandler.post(() -> preRebootVerification(session));
                 return;
             }
-            if (!apexSessionInfo.isActivated) {
+            if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
                 // In all the remaining cases apexd will try to apply the session again at next
                 // boot. Nothing to do here for now.
                 Slog.w(TAG, "Staged session " + session.sessionId + " scheduled to be applied "
@@ -287,7 +288,11 @@
                         + "more information.");
             return;
         }
+
         session.setStagedSessionApplied();
+        if (hasApex) {
+            mApexManager.markStagedSessionSuccessful(session.sessionId);
+        }
     }
 
     private String findFirstAPKInDir(File stageDir) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index ceaf829..05d3c17 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -842,6 +843,7 @@
             String packageName = newPackage.packageName;
             for (PackageRollbackInfo info : rd.packages) {
                 if (info.getPackageName().equals(packageName)) {
+                    info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
                     AppDataRollbackHelper.SnapshotAppDataResult rs =
                             mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
                     info.getPendingBackups().addAll(rs.pendingBackups);
@@ -874,7 +876,7 @@
      * the child sessions, not the parent session.
      */
     private boolean enableRollbackForSession(PackageInstaller.SessionInfo session,
-            int[] installedUsers, boolean snapshotUserData) {
+            @NonNull int[] installedUsers, boolean snapshotUserData) {
         // TODO: Don't attempt to enable rollback for split installs.
         final int installFlags = session.installFlags;
         if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
@@ -1016,7 +1018,7 @@
             }
 
             if (!session.isMultiPackage()) {
-                if (!enableRollbackForSession(session, null, false)) {
+                if (!enableRollbackForSession(session, new int[0], false)) {
                     Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
                     result.offer(false);
                     return;
@@ -1030,7 +1032,7 @@
                         result.offer(false);
                         return;
                     }
-                    if (!enableRollbackForSession(childSession, null, false)) {
+                    if (!enableRollbackForSession(childSession, new int[0], false)) {
                         Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
                         result.offer(false);
                         return;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f33c518..087de69 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -87,8 +87,6 @@
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Process.SYSTEM_UID;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
 
 import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -2828,28 +2826,6 @@
             outAppBounds.setEmpty();
         }
 
-        // TODO(b/112288258): Remove below calculation because the position information in bounds
-        // will be replaced by the offset of surface.
-        final Rect appBounds = parentConfig.windowConfiguration.getAppBounds();
-        if (appBounds != null) {
-            final Rect outBounds = inOutConfig.windowConfiguration.getBounds();
-            final int activityWidth = outBounds.width();
-            final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
-            if (navBarPosition == NAV_BAR_LEFT) {
-                // Position the activity frame on the opposite side of the nav bar.
-                outBounds.left = appBounds.right - activityWidth;
-                outBounds.right = appBounds.right;
-            } else if (navBarPosition == NAV_BAR_RIGHT) {
-                // Position the activity frame on the opposite side of the nav bar.
-                outBounds.left = 0;
-                outBounds.right = activityWidth + appBounds.left;
-            } else if (appBounds.width() > activityWidth) {
-                // Horizontally center the frame.
-                outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2;
-                outBounds.right = outBounds.left + activityWidth;
-            }
-        }
-
         task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 0a3c2fb..c685b05 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2332,6 +2332,20 @@
             if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
                 throw new IllegalStateException("Task resolved to incompatible display");
             }
+
+            final ActivityDisplay preferredDisplay =
+                    mRootActivityContainer.getActivityDisplay(preferredDisplayId);
+
+            final boolean singleTaskInstance = preferredDisplay != null
+                    && preferredDisplay.isSingleTaskInstance();
+
+            if (singleTaskInstance) {
+                // Suppress the warning toast if the preferredDisplay was set to singleTask.
+                // The singleTaskInstance displays will only contain one task and any attempt to
+                // launch new task will re-route to the default display.
+                return;
+            }
+
             if (preferredDisplayId != actualDisplayId) {
                 Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
                 // Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 97062a6..5c528c7 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -568,7 +568,7 @@
 
         final long token = proto.start(fieldId);
         mRequestedOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION,
-                logLevel != WindowTraceLogLevel.CRITICAL);
+                logLevel == WindowTraceLogLevel.CRITICAL);
         if (logLevel == WindowTraceLogLevel.ALL) {
             mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION, false /* critical */);
             mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION,
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ea65dd9..1d76a71 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -396,6 +396,10 @@
         if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
                 || mAdjustedForDivider != adjustedForDivider) {
             if (animate && !mAnimatingForMinimizedDockedStack) {
+                // Notify SystemUI to set the target docked stack size according current docked
+                // state without animation when calling startImeAdjustAnimation.
+                notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
+                        isHomeStackResizable());
                 startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
             } else {
                 // Animation might be delayed, so only notify if we don't run an animation.
@@ -889,7 +893,10 @@
         }
         if (mAnimatingForMinimizedDockedStack) {
             return animateForMinimizedDockedStack(now);
-        } else if (mAnimatingForIme) {
+        } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
+            // To prevent task stack resize animation may flicking when playing app transition
+            // animation & IME window enter animation in parallel, make sure app transition is done
+            // and then start to animate for IME.
             return animateForIme(now);
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 59d7560..9d3112f 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -2134,7 +2134,7 @@
             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
                 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
                 inOutConfig.screenHeightDp = insideParentBounds
-                        ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp)
+                        ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
                         : overrideScreenHeightDp;
             }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7b742fd..b915199 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1163,6 +1163,14 @@
     }
 
     private boolean adjustForIME(final WindowState imeWin) {
+        // To prevent task stack resize animation may flicking when playing app transition
+        // animation & IME window enter animation in parallel, we need to make sure app
+        // transition is done and then adjust task size for IME, skip the new adjusted frame when
+        // app transition is still running.
+        if (getDisplayContent().mAppTransition.isRunning()) {
+            return false;
+        }
+
         final int dockedSide = getDockSide();
         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
         if (imeWin == null || !dockedTopOrBottom) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3430987..21a557e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2164,9 +2164,6 @@
                 // A modal window uses the whole compatibility bounds.
                 flags |= FLAG_NOT_TOUCH_MODAL;
                 mTmpRect.set(mAppToken.getResolvedOverrideBounds());
-                // TODO(b/112288258): Remove the forced offset when the override bounds always
-                // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}).
-                mTmpRect.offsetTo(0, 0);
             } else {
                 // Non-modal uses the application based frame.
                 mTmpRect.set(mWindowFrames.mCompatFrame);
diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING
new file mode 100644
index 0000000..ab85a68
--- /dev/null
+++ b/services/devicepolicy/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "CtsDevicePolicyManagerTestCases"
+    }
+  ]
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index bd03a8d..04abeca1 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -403,7 +403,8 @@
         protected int broadcastIntent(Intent intent, String resolvedType,
                 IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
                 String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
-                boolean sticky, int callingPid, int callingUid, int userId) {
+                boolean sticky, int callingPid, int callingUid, int realCallingUid,
+                int realCallingPid, int userId) {
             Log.i(TAG, "broadcastIntentLocked " + intent);
             mSentIntents.add(intent);
             return 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8c36905..a1db3e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -27,9 +27,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -158,35 +155,6 @@
         assertTrue(mActivity.isState(STOPPED));
     }
 
-    @Test
-    public void testPositionLimitedAspectRatioNavBarBottom() {
-        verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
-                new Rect(0, 0, 1000, 1500));
-    }
-
-    @Test
-    public void testPositionLimitedAspectRatioNavBarLeft() {
-        verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f,
-                new Rect(500, 0, 2000, 1000));
-    }
-
-    @Test
-    public void testPositionLimitedAspectRatioNavBarRight() {
-        verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f,
-                new Rect(0, 0, 1500, 1000));
-    }
-
-    private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
-            float aspectRatio, Rect expectedActivityBounds) {
-        // Verify with nav bar on the right.
-        when(mService.mWindowManager.getNavBarPosition(mActivity.getDisplayId()))
-                .thenReturn(navBarPosition);
-        mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
-        mActivity.info.maxAspectRatio = aspectRatio;
-        ensureActivityConfiguration();
-        assertEquals(expectedActivityBounds, mActivity.getBounds());
-    }
-
     private void ensureActivityConfiguration() {
         mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index bcf9dd2..388f98f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -24,6 +24,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -307,6 +308,41 @@
         assertEquals(fullScreenBounds, task.getBounds());
     }
 
+    @Test
+    public void testComputeConfigResourceOverrides() {
+        final TaskRecord task = new TaskBuilder(mSupervisor).build();
+        final Configuration inOutConfig = new Configuration();
+        final Configuration parentConfig = new Configuration();
+        final int longSide = 1200;
+        final int shortSide = 600;
+        parentConfig.densityDpi = 400;
+        parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
+        parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+
+        // Portrait bounds.
+        inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
+        // By default, the parent bounds should limit the existing input bounds.
+        task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+        assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+        assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+        assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
+
+        inOutConfig.setToDefaults();
+        // Landscape bounds.
+        inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
+        // Without limiting to be inside the parent bounds, the out screen size should keep relative
+        // to the input bounds.
+        task.computeConfigResourceOverrides(inOutConfig, parentConfig,
+                false /* insideParentBounds */);
+
+        assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+                inOutConfig.screenHeightDp);
+        assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+                inOutConfig.screenWidthDp);
+        assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
+    }
+
     /** Ensures that the alias intent won't have target component resolved. */
     @Test
     public void testTaskIntentActivityAlias() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 3eb9085..b0e20b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -35,6 +35,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -54,7 +55,6 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
 
 import android.graphics.Insets;
 import android.graphics.Matrix;
@@ -87,6 +87,7 @@
  */
 @SmallTest
 @Presubmit
+@FlakyTest(bugId = 124127512)
 public class WindowStateTests extends WindowTestsBase {
     private static int sPreviousNewInsetsMode;
 
@@ -389,6 +390,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 74078662)
     public void testLayoutSeqResetOnReparent() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         app.mLayoutSeq = 1;
@@ -445,6 +447,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 74078662)
     public void testDisplayCutoutIsCalculatedRelativeToFrame() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         WindowFrames wf = app.getWindowFrames();
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 40d4eff..0967ad3 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -71,7 +71,7 @@
 
 # RollbackTest
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, RollbackTest/src)
 LOCAL_PACKAGE_NAME := RollbackTest
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
@@ -84,10 +84,21 @@
   $(ROLLBACK_TEST_APP_BV1) \
   $(ROLLBACK_TEST_APP_BV2) \
   $(ROLLBACK_TEST_APEX_V2)
+LOCAL_MANIFEST_FILE := RollbackTest/AndroidManifest.xml
 LOCAL_SDK_VERSION := system_current
 LOCAL_TEST_CONFIG := RollbackTest.xml
 include $(BUILD_PACKAGE)
 
+# StagedRollbackTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, StagedRollbackTest/src)
+LOCAL_MODULE := StagedRollbackTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_JAVA_LIBRARIES := tradefed
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_TEST_CONFIG := StagedRollbackTest.xml
+include $(BUILD_HOST_JAVA_LIBRARY)
+
 # Clean up local variables
 ROLLBACK_TEST_APP_AV1 :=
 ROLLBACK_TEST_APP_AV2 :=
diff --git a/tests/RollbackTest/README.txt b/tests/RollbackTest/README.txt
new file mode 100644
index 0000000..c0b718a
--- /dev/null
+++ b/tests/RollbackTest/README.txt
@@ -0,0 +1,23 @@
+This directory contains a test for the rollback manager service.
+
+Directory structure
+===================
+RollbackTest
+  - device driven test for rollbacks not involving staged rollbacks.
+
+StagedRollbackTest
+  - device driven test for staged rollbacks.
+
+TestApp
+  - source for dummy apks used in testing.
+
+TestApex
+  - source for dummy apex modules used in testing.
+
+Running the tests
+=================
+
+You can manually run the tests as follows:
+
+  atest RollbackTest
+  atest StagedRollbackTest
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index adbad56..ac39f85 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -21,5 +21,9 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.tests.rollback" />
         <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+
+        <!-- Exclude the StagedRollbackTest tests, which needs to be specially
+             driven from the StagedRollbackTest host test -->
+        <option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" />
     </test>
 </configuration>
diff --git a/tests/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
similarity index 100%
rename from tests/RollbackTest/AndroidManifest.xml
rename to tests/RollbackTest/RollbackTest/AndroidManifest.xml
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
similarity index 100%
rename from tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
similarity index 100%
rename from tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
similarity index 92%
rename from tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
rename to tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index f07ae9f..f3edf09 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,6 +16,10 @@
 
 package com.android.tests.rollback;
 
+import static com.android.tests.rollback.RollbackTestUtils.assertPackageRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+
 import android.Manifest;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -24,7 +28,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.Handler;
@@ -42,7 +45,6 @@
 import org.junit.runners.JUnit4;
 
 import java.util.Collections;
-import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.SynchronousQueue;
@@ -617,17 +619,6 @@
         }
     }
 
-    // Helper function to test the value of a PackageRollbackInfo
-    private void assertPackageRollbackInfoEquals(String packageName,
-            long versionRolledBackFrom, long versionRolledBackTo,
-            PackageRollbackInfo info) {
-        assertEquals(packageName, info.getPackageName());
-        assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
-        assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
-        assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
-        assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
-    }
-
     /**
      * Test bad update automatic rollback.
      */
@@ -713,23 +704,6 @@
         }
     }
 
-    // Helper function to test the value of a RollbackInfo with single package
-    private void assertRollbackInfoEquals(String packageName,
-            long versionRolledBackFrom, long versionRolledBackTo,
-            RollbackInfo info, VersionedPackage... causePackages) {
-        assertNotNull(info);
-        assertEquals(1, info.getPackages().size());
-        assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
-                info.getPackages().get(0));
-        assertEquals(causePackages.length, info.getCausePackages().size());
-        for (int i = 0; i < causePackages.length; ++i) {
-            assertEquals(causePackages[i].getPackageName(),
-                    info.getCausePackages().get(i).getPackageName());
-            assertEquals(causePackages[i].getLongVersionCode(),
-                    info.getCausePackages().get(i).getLongVersionCode());
-        }
-    }
-
     // 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) {
@@ -743,23 +717,4 @@
             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/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
new file mode 100644
index 0000000..280ee1d
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Utilities to facilitate testing rollbacks.
+ */
+class RollbackTestUtils {
+
+    private static final String TAG = "RollbackTest";
+
+    static RollbackManager getRollbackManager() {
+        Context context = InstrumentationRegistry.getContext();
+        RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
+        if (rm == null) {
+            throw new AssertionError("Failed to get RollbackManager");
+        }
+        return rm;
+    }
+
+    /**
+     * Returns the version of the given package installed on device.
+     * Returns -1 if the package is not currently installed.
+     */
+    static long getInstalledVersion(String packageName) {
+        Context context = InstrumentationRegistry.getContext();
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInfo info = pm.getPackageInfo(packageName, 0);
+            return info.getLongVersionCode();
+        } catch (PackageManager.NameNotFoundException e) {
+            return -1;
+        }
+    }
+
+    private static void assertStatusSuccess(Intent result) {
+        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                PackageInstaller.STATUS_FAILURE);
+        if (status == -1) {
+            throw new AssertionError("PENDING USER ACTION");
+        } else if (status > 0) {
+            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+        }
+    }
+
+    /**
+     * Uninstalls the given package.
+     * Does nothing if the package is not installed.
+     * @throws AssertionError if package can't be uninstalled.
+     */
+    static void uninstall(String packageName) throws InterruptedException, IOException {
+        // No need to uninstall if the package isn't installed.
+        if (getInstalledVersion(packageName) == -1) {
+            return;
+        }
+
+        Context context = InstrumentationRegistry.getContext();
+        PackageManager packageManager = context.getPackageManager();
+        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
+        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
+        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+    }
+
+    /**
+     * Commit the given rollback.
+     * @throws AssertionError if the rollback fails.
+     */
+    static void rollback(int rollbackId, VersionedPackage... causePackages)
+            throws InterruptedException {
+        RollbackManager rm = getRollbackManager();
+        rm.commitRollback(rollbackId, Arrays.asList(causePackages),
+                LocalIntentSender.getIntentSender());
+        Intent result = LocalIntentSender.getIntentSenderResult();
+        int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+                RollbackManager.STATUS_FAILURE);
+        if (status != RollbackManager.STATUS_SUCCESS) {
+            String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
+            throw new AssertionError(message);
+        }
+    }
+
+    /**
+     * Installs the apk with the given name.
+     *
+     * @param resourceName name of class loader resource for the apk to
+     *        install.
+     * @param enableRollback if rollback should be enabled.
+     * @throws AssertionError if the installation fails.
+     */
+    static void install(String resourceName, boolean enableRollback)
+            throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        PackageInstaller.Session session = null;
+        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        if (enableRollback) {
+            params.setEnableRollback();
+        }
+        int sessionId = packageInstaller.createSession(params);
+        session = packageInstaller.openSession(sessionId);
+
+        ClassLoader loader = RollbackTest.class.getClassLoader();
+        try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+             InputStream is = loader.getResourceAsStream(resourceName);) {
+            byte[] buffer = new byte[4096];
+            int n;
+            while ((n = is.read(buffer)) >= 0) {
+                packageInSession.write(buffer, 0, n);
+            }
+        }
+
+        // Commit the session (this will start the installation workflow).
+        session.commit(LocalIntentSender.getIntentSender());
+        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+    }
+
+    /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
+    static void launchPackage(String packageName)
+            throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setPackage(packageName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        context.startActivity(intent);
+    }
+
+    /**
+     * Installs the apks with the given resource names as an atomic set.
+     * <p>
+     * In case of staged installs, this function will return succesfully after
+     * the staged install has been committed and is ready for the device to
+     * reboot.
+     *
+     * @param staged if the rollback should be staged.
+     * @param enableRollback if rollback should be enabled.
+     * @param resourceNames names of the class loader resource for the apks to
+     *        install.
+     * @throws AssertionError if the installation fails.
+     */
+    private static void install(boolean staged, boolean enableRollback,
+            String... resourceNames) throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+
+        PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        multiPackageParams.setMultiPackage();
+        if (staged) {
+            multiPackageParams.setStaged();
+        }
+        if (enableRollback) {
+            // TODO: Do we set this on the parent params, the child params, or
+            // both?
+            multiPackageParams.setEnableRollback();
+        }
+        int multiPackageId = packageInstaller.createSession(multiPackageParams);
+        PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
+
+        for (String resourceName : resourceNames) {
+            PackageInstaller.Session session = null;
+            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+            if (staged) {
+                params.setStaged();
+            }
+            if (enableRollback) {
+                params.setEnableRollback();
+            }
+            int sessionId = packageInstaller.createSession(params);
+            session = packageInstaller.openSession(sessionId);
+
+            ClassLoader loader = RollbackTest.class.getClassLoader();
+            try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+                 InputStream is = loader.getResourceAsStream(resourceName);) {
+                byte[] buffer = new byte[4096];
+                int n;
+                while ((n = is.read(buffer)) >= 0) {
+                    packageInSession.write(buffer, 0, n);
+                }
+            }
+            multiPackage.addChildSessionId(sessionId);
+        }
+
+        // Commit the session (this will start the installation workflow).
+        multiPackage.commit(LocalIntentSender.getIntentSender());
+        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+
+        if (staged) {
+            waitForSessionReady(multiPackageId);
+        }
+    }
+
+    /**
+     * Installs the apks with the given resource names as an atomic set.
+     *
+     * @param enableRollback if rollback should be enabled.
+     * @param resourceNames names of the class loader resource for the apks to
+     *        install.
+     * @throws AssertionError if the installation fails.
+     */
+    static void installMultiPackage(boolean enableRollback, String... resourceNames)
+            throws InterruptedException, IOException {
+        install(false, enableRollback, resourceNames);
+    }
+
+    /**
+     * Installs the apks with the given resource names as a staged atomic set.
+     *
+     * @param enableRollback if rollback should be enabled.
+     * @param resourceNames names of the class loader resource for the apks to
+     *        install.
+     * @throws AssertionError if the installation fails.
+     */
+    static void installStaged(boolean enableRollback, String... resourceNames)
+            throws InterruptedException, IOException {
+        install(true, enableRollback, resourceNames);
+    }
+
+    static void adoptShellPermissionIdentity(String... permissions) {
+        InstrumentationRegistry
+            .getInstrumentation()
+            .getUiAutomation()
+            .adoptShellPermissionIdentity(permissions);
+    }
+
+    static void dropShellPermissionIdentity() {
+        InstrumentationRegistry
+            .getInstrumentation()
+            .getUiAutomation()
+            .dropShellPermissionIdentity();
+    }
+
+    /**
+     * Returns 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.
+     */
+    static 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;
+    }
+
+    /**
+     * Asserts that the given PackageRollbackInfo has the expected package
+     * name and versions.
+     */
+    static void assertPackageRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            PackageRollbackInfo info) {
+        assertEquals(packageName, info.getPackageName());
+        assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
+        assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
+        assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
+        assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
+    }
+
+    /**
+     * Asserts that the given RollbackInfo has a single package with expected
+     * package name and versions.
+     */
+    static void assertRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            RollbackInfo info, VersionedPackage... causePackages) {
+        assertNotNull(info);
+        assertEquals(1, info.getPackages().size());
+        assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
+                info.getPackages().get(0));
+        assertEquals(causePackages.length, info.getCausePackages().size());
+        for (int i = 0; i < causePackages.length; ++i) {
+            assertEquals(causePackages[i].getPackageName(),
+                    info.getCausePackages().get(i).getPackageName());
+            assertEquals(causePackages[i].getLongVersionCode(),
+                    info.getCausePackages().get(i).getLongVersionCode());
+        }
+    }
+
+    /**
+     * Waits for the given session to be marked as ready.
+     * Throws an assertion if the session fails.
+     */
+    static void waitForSessionReady(int sessionId) {
+        BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
+        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                PackageInstaller.SessionInfo info =
+                        intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+                if (info != null && info.getSessionId() == sessionId) {
+                    if (info.isSessionReady() || info.isSessionFailed()) {
+                        try {
+                            sessionStatus.put(info);
+                        } catch (InterruptedException e) {
+                            Log.e(TAG, "Failed to put session info.", e);
+                        }
+                    }
+                }
+            }
+        };
+        IntentFilter sessionUpdatedFilter =
+                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+
+        Context context = InstrumentationRegistry.getContext();
+        context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+
+        PackageInstaller installer = context.getPackageManager().getPackageInstaller();
+        PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
+
+        try {
+            if (info.isSessionReady() || info.isSessionFailed()) {
+                sessionStatus.put(info);
+            }
+
+            info = sessionStatus.take();
+            context.unregisterReceiver(sessionUpdatedReceiver);
+            if (info.isSessionFailed()) {
+                throw new AssertionError(info.getStagedSessionErrorMessage());
+            }
+        } catch (InterruptedException e) {
+            throw new AssertionError(e);
+        }
+    }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
new file mode 100644
index 0000000..297bf86
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+
+import android.Manifest;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for rollback of staged installs.
+ * <p>
+ * Note: These tests require reboot in between test phases. They are run
+ * specially so that the testFooEnableRollback, testFooCommitRollback, and
+ * testFooConfirmRollback phases of each test are run in order with reboots in
+ * between them.
+ */
+@RunWith(JUnit4.class)
+public class StagedRollbackTest {
+
+    private static final String TAG = "RollbackTest";
+    private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+
+    /**
+     * Adopts common shell permissions needed for rollback tests.
+     */
+    @Before
+    public void adoptShellPermissions() {
+        RollbackTestUtils.adoptShellPermissionIdentity(
+                Manifest.permission.INSTALL_PACKAGES,
+                Manifest.permission.DELETE_PACKAGES,
+                Manifest.permission.MANAGE_ROLLBACKS);
+    }
+
+    /**
+     * Drops shell permissions needed for rollback tests.
+     */
+    @After
+    public void dropShellPermissions() {
+        RollbackTestUtils.dropShellPermissionIdentity();
+    }
+
+
+    /**
+     * Test basic rollbacks. Enable rollback phase.
+     */
+    @Test
+    public void testBasicEnableRollback() throws Exception {
+        RollbackTestUtils.uninstall(TEST_APP_A);
+        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk");
+
+        // At this point, the host test driver will reboot the device and run
+        // testBasicCommitRollback().
+    }
+
+    /**
+     * Test basic rollbacks. Commit rollback phase.
+     */
+    @Test
+    public void testBasicCommitRollback() throws Exception {
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TEST_APP_A);
+        assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+
+        RollbackTestUtils.rollback(rollback.getRollbackId());
+
+        rollback = getUniqueRollbackInfoForPackage(
+                rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+        assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+        assertNotEquals(-1, rollback.getCommittedSessionId());
+
+        RollbackTestUtils.waitForSessionReady(rollback.getCommittedSessionId());
+
+        // The app should not be rolled back until after reboot.
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        // At this point, the host test driver will reboot the device and run
+        // testBasicConfirmRollback().
+    }
+
+    /**
+     * Test basic rollbacks. Confirm rollback phase.
+     */
+    @Test
+    public void testBasicConfirmRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+        assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+        assertNotEquals(-1, rollback.getCommittedSessionId());
+    }
+}
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
new file mode 100644
index 0000000..2750d37
--- /dev/null
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs the staged rollback tests">
+    <option name="test-suite-tag" value="StagedRollbackTest" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="RollbackTest.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
+    </test>
+</configuration>
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
new file mode 100644
index 0000000..6cb0dd0
--- /dev/null
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback.host;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs the staged rollback tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class StagedRollbackTest extends BaseHostJUnit4Test {
+
+    /**
+     * Runs the given phase of a test by calling into the device.
+     * Throws an exception if the test phase fails.
+     * <p>
+     * For example, <code>runPhase("testBasicEnableRollback");</code>
+     */
+    private void runPhase(String phase) throws Exception {
+        assertTrue(runDeviceTests("com.android.tests.rollback",
+                    "com.android.tests.rollback.StagedRollbackTest",
+                    phase));
+    }
+
+    /**
+     * Tests staged rollbacks.
+     */
+    @Test
+    public void testBasic() throws Exception {
+        runPhase("testBasicEnableRollback");
+        getDevice().reboot();
+        runPhase("testBasicCommitRollback");
+        getDevice().reboot();
+        runPhase("testBasicConfirmRollback");
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
deleted file mode 100644
index 60c7a59..0000000
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tests.rollback;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.RollbackManager;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-class RollbackTestUtils {
-
-    private static final String TAG = "RollbackTest";
-
-    static RollbackManager getRollbackManager() {
-        Context context = InstrumentationRegistry.getContext();
-        RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
-        if (rm == null) {
-            throw new AssertionError("Failed to get RollbackManager");
-        }
-        return rm;
-    }
-
-    /**
-     * Returns the version of the given package installed on device.
-     * Returns -1 if the package is not currently installed.
-     */
-    static long getInstalledVersion(String packageName) {
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager pm = context.getPackageManager();
-        try {
-            PackageInfo info = pm.getPackageInfo(packageName, 0);
-            return info.getLongVersionCode();
-        } catch (PackageManager.NameNotFoundException e) {
-            return -1;
-        }
-    }
-
-    private static void assertStatusSuccess(Intent result) {
-        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-    }
-
-    /**
-     * Uninstalls the given package.
-     * Does nothing if the package is not installed.
-     * @throws AssertionError if package can't be uninstalled.
-     */
-    static void uninstall(String packageName) throws InterruptedException, IOException {
-        // No need to uninstall if the package isn't installed.
-        if (getInstalledVersion(packageName) == -1) {
-            return;
-        }
-
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager packageManager = context.getPackageManager();
-        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
-        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    /**
-     * Commit the given rollback.
-     * @throws AssertionError if the rollback fails.
-     */
-    static void rollback(int rollbackId, VersionedPackage... causePackages)
-            throws InterruptedException {
-        RollbackManager rm = getRollbackManager();
-        rm.commitRollback(rollbackId, Arrays.asList(causePackages),
-                LocalIntentSender.getIntentSender());
-        Intent result = LocalIntentSender.getIntentSenderResult();
-        int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
-                RollbackManager.STATUS_FAILURE);
-        if (status != RollbackManager.STATUS_SUCCESS) {
-            String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message);
-        }
-    }
-
-    /**
-     * Installs the apk with the given name.
-     *
-     * @param resourceName name of class loader resource for the apk to
-     *        install.
-     * @param enableRollback if rollback should be enabled.
-     * @throws AssertionError if the installation fails.
-     */
-    static void install(String resourceName, boolean enableRollback)
-            throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        PackageInstaller.Session session = null;
-        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        if (enableRollback) {
-            params.setEnableRollback();
-        }
-        int sessionId = packageInstaller.createSession(params);
-        session = packageInstaller.openSession(sessionId);
-
-        ClassLoader loader = RollbackTest.class.getClassLoader();
-        try (OutputStream packageInSession = session.openWrite("package", 0, -1);
-             InputStream is = loader.getResourceAsStream(resourceName);) {
-            byte[] buffer = new byte[4096];
-            int n;
-            while ((n = is.read(buffer)) >= 0) {
-                packageInSession.write(buffer, 0, n);
-            }
-        }
-
-        // Commit the session (this will start the installation workflow).
-        session.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
-    static void launchPackage(String packageName)
-            throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setPackage(packageName);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addCategory(Intent.CATEGORY_LAUNCHER);
-        context.startActivity(intent);
-    }
-
-    /**
-     * Installs the apks with the given resource names as an atomic set.
-     *
-     * @param enableRollback if rollback should be enabled.
-     * @param resourceNames names of the class loader resource for the apks to
-     *        install.
-     * @throws AssertionError if the installation fails.
-     */
-    static void installMultiPackage(boolean enableRollback, String... resourceNames)
-            throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-
-        PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        multiPackageParams.setMultiPackage();
-        if (enableRollback) {
-            // TODO: Do we set this on the parent params, the child params, or
-            // both?
-            multiPackageParams.setEnableRollback();
-        }
-        int multiPackageId = packageInstaller.createSession(multiPackageParams);
-        PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
-
-        for (String resourceName : resourceNames) {
-            PackageInstaller.Session session = null;
-            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-            if (enableRollback) {
-                params.setEnableRollback();
-            }
-            int sessionId = packageInstaller.createSession(params);
-            session = packageInstaller.openSession(sessionId);
-
-            ClassLoader loader = RollbackTest.class.getClassLoader();
-            try (OutputStream packageInSession = session.openWrite("package", 0, -1);
-                 InputStream is = loader.getResourceAsStream(resourceName);) {
-                byte[] buffer = new byte[4096];
-                int n;
-                while ((n = is.read(buffer)) >= 0) {
-                    packageInSession.write(buffer, 0, n);
-                }
-            }
-            multiPackage.addChildSessionId(sessionId);
-        }
-
-        // Commit the session (this will start the installation workflow).
-        multiPackage.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    static void adoptShellPermissionIdentity(String... permissions) {
-        InstrumentationRegistry
-            .getInstrumentation()
-            .getUiAutomation()
-            .adoptShellPermissionIdentity(permissions);
-    }
-
-    static void dropShellPermissionIdentity() {
-        InstrumentationRegistry
-            .getInstrumentation()
-            .getUiAutomation()
-            .dropShellPermissionIdentity();
-    }
-}