Make RollbackManager @SystemApi.

Require callers hold a new MANAGE_ROLLBACKS permission to interact with
the RollbackManager.

Bug: 112431924
Test: atest RollbackTest, with new test for permissions added,
      and with selinux in permissive mode.
Test: atest CtsPermission2TestCases:PermissionPolicyTest
Change-Id: I73f4f3457d85be580670cd69c89066d2cc348186
diff --git a/api/system-current.txt b/api/system-current.txt
index 47bb88a..9515b46 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -94,6 +94,7 @@
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
+    field public static final java.lang.String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final java.lang.String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
     field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
@@ -1038,6 +1039,7 @@
     field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
     field public static final java.lang.String PERMISSION_SERVICE = "permission";
     field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
+    field public static final java.lang.String ROLLBACK_SERVICE = "rollback";
     field public static final java.lang.String SECURE_ELEMENT_SERVICE = "secure_element";
     field public static final java.lang.String STATS_MANAGER = "stats";
     field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
@@ -1069,6 +1071,7 @@
     field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
     field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
     field public static final java.lang.String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
+    field public static final java.lang.String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
     field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
@@ -1204,6 +1207,7 @@
     method public void setAllocateAggressive(boolean);
     method public void setAllowDowngrade(boolean);
     method public void setDontKillApp(boolean);
+    method public void setEnableRollback();
     method public void setGrantedRuntimePermissions(java.lang.String[]);
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
@@ -1398,6 +1402,41 @@
 
 }
 
+package android.content.rollback {
+
+  public final class PackageRollbackInfo implements android.os.Parcelable {
+    ctor public PackageRollbackInfo(java.lang.String, android.content.rollback.PackageRollbackInfo.PackageVersion, android.content.rollback.PackageRollbackInfo.PackageVersion);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
+    field public final android.content.rollback.PackageRollbackInfo.PackageVersion higherVersion;
+    field public final android.content.rollback.PackageRollbackInfo.PackageVersion lowerVersion;
+    field public final java.lang.String packageName;
+  }
+
+  public static class PackageRollbackInfo.PackageVersion {
+    ctor public PackageRollbackInfo.PackageVersion(long);
+    field public final long versionCode;
+  }
+
+  public final class RollbackInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
+    field public final android.content.rollback.PackageRollbackInfo targetPackage;
+  }
+
+  public final class RollbackManager {
+    method public void executeRollback(android.content.rollback.RollbackInfo, android.content.IntentSender);
+    method public void expireRollbackForPackage(java.lang.String);
+    method public android.content.rollback.RollbackInfo getAvailableRollback(java.lang.String);
+    method public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
+    method public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+    method public void reloadPersistedData();
+  }
+
+}
+
 package android.hardware {
 
   public final class Sensor {
diff --git a/api/test-current.txt b/api/test-current.txt
index c1e4162..71a06f1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -329,11 +329,6 @@
     method public android.os.UserHandle getUser();
     method public int getUserId();
     method public void setAutofillCompatibilityEnabled(boolean);
-    field public static final java.lang.String ROLLBACK_SERVICE = "rollback";
-  }
-
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
   }
 
 }
@@ -356,10 +351,6 @@
     ctor public LauncherApps(android.content.Context);
   }
 
-  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
-    method public void setEnableRollback();
-  }
-
   public abstract class PackageManager {
     method public abstract boolean arePermissionsIndividuallyControlled();
     method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
@@ -407,42 +398,6 @@
 
 }
 
-package android.content.rollback {
-
-  public final class PackageRollbackInfo implements android.os.Parcelable {
-    ctor public PackageRollbackInfo(java.lang.String, android.content.rollback.PackageRollbackInfo.PackageVersion, android.content.rollback.PackageRollbackInfo.PackageVersion);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
-    field public final android.content.rollback.PackageRollbackInfo.PackageVersion higherVersion;
-    field public final android.content.rollback.PackageRollbackInfo.PackageVersion lowerVersion;
-    field public final java.lang.String packageName;
-  }
-
-  public static class PackageRollbackInfo.PackageVersion {
-    ctor public PackageRollbackInfo.PackageVersion(long);
-    field public final long versionCode;
-  }
-
-  public final class RollbackInfo implements android.os.Parcelable {
-    ctor public RollbackInfo(android.content.rollback.PackageRollbackInfo);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
-    field public final android.content.rollback.PackageRollbackInfo targetPackage;
-  }
-
-  public final class RollbackManager {
-    method public void executeRollback(android.content.rollback.RollbackInfo, android.content.IntentSender);
-    method public void expireRollbackForPackage(java.lang.String);
-    method public android.content.rollback.RollbackInfo getAvailableRollback(java.lang.String);
-    method public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
-    method public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
-    method public void reloadPersistedData();
-  }
-
-}
-
 package android.database.sqlite {
 
   public class SQLiteCompatibilityWalFlags {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 125c4c6..0aa6a8c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4009,9 +4009,9 @@
      * with the rollback manager
      *
      * @see #getSystemService(String)
-     * @hide TODO(ruhler): hidden, @TestApi until we decide on public vs. @SystemApi.
+     * @hide
      */
-    @TestApi
+    @SystemApi
     public static final String ROLLBACK_SERVICE = "rollback";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1e3908c..4d0f4cd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -27,7 +27,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -2268,9 +2267,9 @@
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      *
-     * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+     * @hide
      */
-    @TestApi
+    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
             "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a2fd83f..94b7c45 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -24,7 +24,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
@@ -1428,9 +1427,9 @@
 
         /**
          * Request that rollbacks be enabled for the given upgrade.
-         * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+         * @hide
          */
-        @TestApi
+        @SystemApi
         public void setEnableRollback() {
             installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
         }
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 0c05765..2040024 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.rollback;
 
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -25,9 +25,9 @@
 /**
  * Information about a rollback available for a particular package.
  *
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 public final class PackageRollbackInfo implements Parcelable {
     /**
      * The name of a package being rolled back.
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 5fa4e57..66df4fe 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.rollback;
 
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,9 +24,9 @@
  * Information about a set of packages that can be, or already have been
  * rolled back together.
  *
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 public final class RollbackInfo implements Parcelable {
 
     /**
@@ -39,6 +39,7 @@
     // TODO: Add a flag to indicate if reboot is required, when rollback of
     // staged installs is supported.
 
+    /** @hide */
     public RollbackInfo(PackageRollbackInfo targetPackage) {
         this.targetPackage = targetPackage;
     }
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 294151a..c1c0bc1 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -18,8 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.content.Context;
 import android.content.IntentSender;
 import android.os.RemoteException;
@@ -33,12 +34,10 @@
  * used to initiate rollback of those packages for a limited time period after
  * upgrade.
  *
- * TODO: Require an appropriate permission for apps to use these APIs.
- *
  * @see PackageInstaller.SessionParams#setEnableRollback()
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 @SystemService(Context.ROLLBACK_SERVICE)
 public final class RollbackManager {
     private final String mCallerPackageName;
@@ -63,7 +62,10 @@
      * @param packageName name of the package to get the availble RollbackInfo for.
      * @return the rollback available for the package, or null if no rollback
      *         is available for the package.
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
         try {
             return mBinder.getAvailableRollback(packageName);
@@ -78,7 +80,10 @@
      * about the rollback available for a particular package.
      *
      * @return the names of packages that are available for rollback.
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @NonNull List<String> getPackagesWithAvailableRollbacks() {
         try {
             return mBinder.getPackagesWithAvailableRollbacks().getList();
@@ -103,7 +108,10 @@
      * rolled back from.
      *
      * @return the recently executed rollbacks
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
         try {
             return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -127,7 +135,10 @@
      *
      * @param rollback to execute
      * @param statusReceiver where to deliver the results
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void executeRollback(@NonNull RollbackInfo rollback,
             @NonNull IntentSender statusReceiver) {
         try {
@@ -143,9 +154,10 @@
      * across device reboot, by simulating what happens on reboot without
      * actually rebooting the device.
      *
-     * @hide
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
-    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void reloadPersistedData() {
         try {
             mBinder.reloadPersistedData();
@@ -160,10 +172,10 @@
      * expiring rollback data.
      *
      * @param packageName the name of the package to expire data for.
-     *
-     * @hide
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
-    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void expireRollbackForPackage(@NonNull String packageName) {
         try {
             mBinder.expireRollbackForPackage(packageName);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b16c16d..be37ca9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3854,6 +3854,10 @@
     <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows managing apk level rollbacks. -->
+    <permission android:name="android.permission.MANAGE_ROLLBACKS"
+        android:protectionLevel="signature|installer" />
+
     <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
     <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
         android:protectionLevel="signature|verifier" />
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8cfc2a6..bff2c84 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -82,6 +82,7 @@
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index 5bf2040..248e6c9 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import android.Manifest;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -42,7 +43,6 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.Process;
 import android.os.SELinux;
 import android.util.Log;
 
@@ -203,6 +203,10 @@
 
     @Override
     public RollbackInfo getAvailableRollback(String packageName) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getAvailableRollback");
+
         PackageRollbackInfo.PackageVersion installedVersion =
                 getInstalledPackageVersion(packageName);
         if (installedVersion == null) {
@@ -228,6 +232,10 @@
 
     @Override
     public StringParceledListSlice getPackagesWithAvailableRollbacks() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getPackagesWithAvailableRollbacks");
+
         // TODO: This may return packages whose rollback is out of date or
         // expired.  Presumably that's okay because the package rollback could
         // be expired anyway between when the caller calls this method and
@@ -245,6 +253,10 @@
 
     @Override
     public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getRecentlyExecutedRollbacks");
+
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
             List<RollbackInfo> rollbacks = new ArrayList<>(mRecentlyExecutedRollbacks);
@@ -255,11 +267,13 @@
     @Override
     public void executeRollback(RollbackInfo rollback, String callerPackageName,
             IntentSender statusReceiver) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "executeRollback");
+
         final int callingUid = Binder.getCallingUid();
-        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
-            AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
-            appOps.checkPackage(callingUid, callerPackageName);
-        }
+        AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+        appOps.checkPackage(callingUid, callerPackageName);
 
         getHandler().post(() ->
                 executeRollbackInternal(rollback, callerPackageName, statusReceiver));
@@ -362,10 +376,8 @@
             addRecentlyExecutedRollback(rollback);
             sendSuccess(statusReceiver);
 
-            // TODO: Restrict permissions for who can listen for this
-            // broadcast?
             Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
-                    Uri.fromParts("package", packageName, null));
+                    Uri.fromParts("package", packageName, Manifest.permission.MANAGE_ROLLBACKS));
 
             // TODO: This call emits the warning "Calling a method in the
             // system process without a qualified user". Fix that.
@@ -379,6 +391,10 @@
 
     @Override
     public void reloadPersistedData() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "reloadPersistedData");
+
         synchronized (mLock) {
             mAvailableRollbacks = null;
             mRecentlyExecutedRollbacks = null;
@@ -388,6 +404,10 @@
 
     @Override
     public void expireRollbackForPackage(String packageName) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "expireRollbackForPackage");
+
         // TODO: Should this take a package version number in addition to
         // package name? For now, just remove all rollbacks matching the
         // package name. This method is only currently used to facilitate
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index f2bd407..8aadde9 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -43,9 +43,8 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_RESOURCE_FILES := $(ROLLBACK_TEST_APP_V1) $(ROLLBACK_TEST_APP_V2)
-LOCAL_SDK_VERSION := test_current
+LOCAL_SDK_VERSION := system_current
 LOCAL_TEST_CONFIG := RollbackTest.xml
 include $(BUILD_PACKAGE)
 
diff --git a/tests/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/AndroidManifest.xml
index d1535a3..e57a768 100644
--- a/tests/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/AndroidManifest.xml
@@ -17,9 +17,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.tests.rollback" >
 
-    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
-    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
-
     <application>
         <receiver android:name="com.android.tests.rollback.LocalIntentSender"
                   android:exported="true" />
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 02c1ce2..503dbde 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,6 +16,7 @@
 
 package com.android.tests.rollback;
 
+import android.Manifest;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -71,85 +72,94 @@
         };
         context.registerReceiver(enableRollbackReceiver, enableRollbackFilter);
 
-        // Register a broadcast receiver for notification when the rollback is
-        // done executing.
-        RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // Uninstall com.android.tests.rollback.testapp
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            // Register a broadcast receiver for notification when the rollback is
+            // done executing.
+            RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
-        // TODO: There is currently a race condition between when the app is
-        // uninstalled and when rollback manager deletes the rollback. Fix it
-        // so that's not the case!
-        for (int i = 0; i < 5; ++i) {
-            for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-                if (TEST_APP_PACKAGE_NAME.equals(info.targetPackage.packageName)) {
-                    Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
-                    Thread.sleep(1000);
-                    break;
+            // Uninstall com.android.tests.rollback.testapp
+            RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
+            assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+
+            // TODO: There is currently a race condition between when the app is
+            // uninstalled and when rollback manager deletes the rollback. Fix it
+            // so that's not the case!
+            for (int i = 0; i < 5; ++i) {
+                for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+                    if (TEST_APP_PACKAGE_NAME.equals(info.targetPackage.packageName)) {
+                        Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+                        Thread.sleep(1000);
+                        break;
+                    }
                 }
             }
-        }
 
-        // The app should not be available for rollback.
-        assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
-        assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            // The app should not be available for rollback.
+            assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
+            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
 
-        // There should be no recently executed rollbacks for this package.
-        for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-            assertNotEquals(TEST_APP_PACKAGE_NAME, info.targetPackage.packageName);
-        }
-
-        // Install v1 of the app (without rollbacks enabled).
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // Upgrade from v1 to v2, with rollbacks enabled.
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
-
-        // We should not have received any rollback requests yet.
-        // TODO: Possibly flaky if, by chance, some other app on device
-        // happens to be rolled back at the same time?
-        assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
-
-        // Roll back the app.
-        RollbackTestUtils.rollback(rollback);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // Verify we received a broadcast for the rollback.
-        // TODO: Race condition between the timeout and when the broadcast is
-        // received could lead to test flakiness.
-        Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
-        assertNotNull(broadcast);
-        assertEquals(TEST_APP_PACKAGE_NAME, broadcast.getData().getSchemeSpecificPart());
-        assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
-
-        // Verify the recent rollback has been recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
+            // There should be no recently executed rollbacks for this package.
+            for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+                assertNotEquals(TEST_APP_PACKAGE_NAME, info.targetPackage.packageName);
             }
-        }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        broadcastReceiver.unregister();
-        context.unregisterReceiver(enableRollbackReceiver);
+            // Install v1 of the app (without rollbacks enabled).
+            RollbackTestUtils.install("RollbackTestAppV1.apk", false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+
+            // Upgrade from v1 to v2, with rollbacks enabled.
+            RollbackTestUtils.install("RollbackTestAppV2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+
+            // The app should now be available for rollback.
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+            // We should not have received any rollback requests yet.
+            // TODO: Possibly flaky if, by chance, some other app on device
+            // happens to be rolled back at the same time?
+            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+            // Roll back the app.
+            RollbackTestUtils.rollback(rollback);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+
+            // Verify we received a broadcast for the rollback.
+            // TODO: Race condition between the timeout and when the broadcast is
+            // received could lead to test flakiness.
+            Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
+            assertNotNull(broadcast);
+            assertEquals(TEST_APP_PACKAGE_NAME, broadcast.getData().getSchemeSpecificPart());
+            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+            // Verify the recent rollback has been recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
+            }
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+            broadcastReceiver.unregister();
+            context.unregisterReceiver(enableRollbackReceiver);
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
     }
 
     /**
@@ -157,65 +167,74 @@
      */
     @Test
     public void testRollbackDataPersistence() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // Prep installation of com.android.tests.rollback.testapp
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            // Prep installation of com.android.tests.rollback.testapp
+            RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
+            RollbackTestUtils.install("RollbackTestAppV1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppV2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
 
-        // Reload the persisted data.
-        rm.reloadPersistedData();
+            // The app should now be available for rollback.
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        // The app should still be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            // Reload the persisted data.
+            rm.reloadPersistedData();
 
-        // Roll back the app.
-        RollbackTestUtils.rollback(rollback);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            // The app should still be available for rollback.
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        // Verify the recent rollback has been recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
+            // Roll back the app.
+            RollbackTestUtils.rollback(rollback);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+
+            // Verify the recent rollback has been recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
             }
-        }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        // Reload the persisted data.
-        rm.reloadPersistedData();
+            // Reload the persisted data.
+            rm.reloadPersistedData();
 
-        // Verify the recent rollback is still recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
+            // Verify the recent rollback is still recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
             }
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
         }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
     }
 
     /**
@@ -224,26 +243,35 @@
      */
     @Test
     public void testRollbackExpiration() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
+            RollbackTestUtils.install("RollbackTestAppV1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppV2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
 
-        // Expire the rollback.
-        rm.expireRollbackForPackage(TEST_APP_PACKAGE_NAME);
+            // The app should now be available for rollback.
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
+            assertNotNull(rollback);
+            assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
+            assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+            assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        // The rollback should no longer be available.
-        assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
-        assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            // Expire the rollback.
+            rm.expireRollbackForPackage(TEST_APP_PACKAGE_NAME);
+
+            // The rollback should no longer be available.
+            assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
+            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
     }
 
     /**
@@ -270,4 +298,59 @@
         // called, even when the test fails?
         broadcastReceiver.unregister();
     }
+
+    /**
+     * Test that the MANAGE_ROLLBACKS permission is required to call
+     * RollbackManager APIs.
+     */
+    @Test
+    public void testManageRollbacksPermission() throws Exception {
+        // We shouldn't be allowed to call any of the RollbackManager APIs
+        // without the MANAGE_ROLLBACKS permission.
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+        try {
+            rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.getPackagesWithAvailableRollbacks();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.getRecentlyExecutedRollbacks();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            // TODO: What if the implementation checks arguments for non-null
+            // first? Then this test isn't valid.
+            rm.executeRollback(null, null);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.reloadPersistedData();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.expireRollbackForPackage(TEST_APP_PACKAGE_NAME);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
 }
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index c5ce3fa..f16c917 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -135,15 +135,13 @@
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
-    // TODO: Unused
-    static void adoptShellPermissionIdentity() {
+    static void adoptShellPermissionIdentity(String... permissions) {
         InstrumentationRegistry
             .getInstrumentation()
             .getUiAutomation()
-            .adoptShellPermissionIdentity();
+            .adoptShellPermissionIdentity(permissions);
     }
 
-    // TODO: Unused
     static void dropShellPermissionIdentity() {
         InstrumentationRegistry
             .getInstrumentation()