1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.rollback; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.annotation.SystemService; 24 import android.annotation.TestApi; 25 import android.content.Context; 26 import android.content.IntentSender; 27 import android.content.pm.ParceledListSlice; 28 import android.content.pm.VersionedPackage; 29 import android.os.RemoteException; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.List; 34 35 /** 36 * Offers the ability to rollback packages after upgrade. 37 * <p> 38 * For packages installed with rollbacks enabled, the RollbackManager can be 39 * used to initiate rollback of those packages for a limited time period after 40 * upgrade. 41 * 42 * @see PackageInstaller.SessionParams#setEnableRollback(boolean) 43 * @hide 44 */ 45 @SystemApi 46 @SystemService(Context.ROLLBACK_SERVICE) 47 public final class RollbackManager { 48 private final String mCallerPackageName; 49 private final IRollbackManager mBinder; 50 51 /** 52 * Lifetime duration of rollback packages in millis. A rollback will be available for 53 * at most that duration of time after a package is installed with 54 * {@link PackageInstaller.SessionParams#setEnableRollback(boolean)}. 55 * 56 * <p>If flag value is negative, the default value will be assigned. 57 * 58 * @see RollbackManager 59 * 60 * Flag type: {@code long} 61 * Namespace: NAMESPACE_ROLLBACK_BOOT 62 * 63 * @hide 64 */ 65 @TestApi 66 public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = 67 "rollback_lifetime_in_millis"; 68 69 /** {@hide} */ RollbackManager(Context context, IRollbackManager binder)70 public RollbackManager(Context context, IRollbackManager binder) { 71 mCallerPackageName = context.getPackageName(); 72 mBinder = binder; 73 } 74 75 /** 76 * Returns a list of all currently available rollbacks. 77 * 78 * @throws SecurityException if the caller does not have appropriate permissions. 79 */ 80 @RequiresPermission(anyOf = { 81 android.Manifest.permission.MANAGE_ROLLBACKS, 82 android.Manifest.permission.TEST_MANAGE_ROLLBACKS 83 }) 84 @NonNull getAvailableRollbacks()85 public List<RollbackInfo> getAvailableRollbacks() { 86 try { 87 return mBinder.getAvailableRollbacks().getList(); 88 } catch (RemoteException e) { 89 throw e.rethrowFromSystemServer(); 90 } 91 } 92 93 /** 94 * Gets the list of all recently committed rollbacks. 95 * This is for the purposes of preventing re-install of a bad version of a 96 * package and monitoring the status of a staged rollback. 97 * <p> 98 * Returns an empty list if there are no recently committed rollbacks. 99 * <p> 100 * To avoid having to keep around complete rollback history forever on a 101 * device, the returned list of rollbacks is only guaranteed to include 102 * rollbacks that are still relevant. A rollback is no longer considered 103 * relevant if the package is subsequently uninstalled or upgraded 104 * (without the possibility of rollback) to a higher version code than was 105 * rolled back from. 106 * 107 * @return the recently committed rollbacks 108 * @throws SecurityException if the caller does not have appropriate permissions. 109 */ 110 @RequiresPermission(anyOf = { 111 android.Manifest.permission.MANAGE_ROLLBACKS, 112 android.Manifest.permission.TEST_MANAGE_ROLLBACKS 113 }) getRecentlyCommittedRollbacks()114 public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() { 115 try { 116 return mBinder.getRecentlyCommittedRollbacks().getList(); 117 } catch (RemoteException e) { 118 throw e.rethrowFromSystemServer(); 119 } 120 } 121 122 /** 123 * Status of a rollback commit. Will be one of 124 * {@link #STATUS_SUCCESS}, {@link #STATUS_FAILURE}, 125 * {@link #STATUS_FAILURE_ROLLBACK_UNAVAILABLE}, {@link #STATUS_FAILURE_INSTALL} 126 * 127 * @see Intent#getIntExtra(String, int) 128 */ 129 public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS"; 130 131 /** 132 * Detailed string representation of the status, including raw details that 133 * are useful for debugging. 134 * 135 * @see Intent#getStringExtra(String) 136 */ 137 public static final String EXTRA_STATUS_MESSAGE = 138 "android.content.rollback.extra.STATUS_MESSAGE"; 139 140 /** 141 * Status result of committing a rollback. 142 * 143 * @hide 144 */ 145 @IntDef(prefix = "STATUS_", value = { 146 STATUS_SUCCESS, 147 STATUS_FAILURE, 148 STATUS_FAILURE_ROLLBACK_UNAVAILABLE, 149 STATUS_FAILURE_INSTALL, 150 }) 151 @Retention(RetentionPolicy.SOURCE) 152 public @interface Status {}; 153 154 /** 155 * The rollback was successfully committed. 156 */ 157 public static final int STATUS_SUCCESS = 0; 158 159 /** 160 * The rollback could not be committed due to some generic failure. 161 * 162 * @see #EXTRA_STATUS_MESSAGE 163 */ 164 public static final int STATUS_FAILURE = 1; 165 166 /** 167 * The rollback could not be committed because it was no longer available. 168 * 169 * @see #EXTRA_STATUS_MESSAGE 170 */ 171 public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; 172 173 /** 174 * The rollback failed to install successfully. 175 * 176 * @see #EXTRA_STATUS_MESSAGE 177 */ 178 public static final int STATUS_FAILURE_INSTALL = 3; 179 180 /** 181 * Commit the rollback with given id, rolling back all versions of the 182 * packages to the last good versions previously installed on the device 183 * as specified in the corresponding RollbackInfo object. The 184 * rollback will fail if any of the installed packages or available 185 * rollbacks are inconsistent with the versions specified in the given 186 * rollback object, which can happen if a package has been updated or a 187 * rollback expired since the rollback object was retrieved from 188 * {@link #getAvailableRollbacks()}. 189 * 190 * @param rollbackId ID of the rollback to commit 191 * @param causePackages package versions to record as the motivation for this 192 * rollback. 193 * @param statusReceiver where to deliver the results. Intents sent to 194 * this receiver contain {@link #EXTRA_STATUS} 195 * and {@link #EXTRA_STATUS_MESSAGE}. 196 * @throws SecurityException if the caller does not have appropriate permissions. 197 */ 198 @RequiresPermission(anyOf = { 199 android.Manifest.permission.MANAGE_ROLLBACKS, 200 android.Manifest.permission.TEST_MANAGE_ROLLBACKS 201 }) commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages, @NonNull IntentSender statusReceiver)202 public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages, 203 @NonNull IntentSender statusReceiver) { 204 try { 205 mBinder.commitRollback(rollbackId, new ParceledListSlice(causePackages), 206 mCallerPackageName, statusReceiver); 207 } catch (RemoteException e) { 208 throw e.rethrowFromSystemServer(); 209 } 210 } 211 212 /** 213 * Reload all persisted rollback data from device storage. 214 * This API is meant to test that rollback state is properly preserved 215 * across device reboot, by simulating what happens on reboot without 216 * actually rebooting the device. 217 * 218 * Note rollbacks in the process of enabling will be lost after calling 219 * this method since they are not persisted yet. Don't call this method 220 * in the middle of the install process. 221 * 222 * @throws SecurityException if the caller does not have appropriate permissions. 223 * 224 * @hide 225 */ 226 @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) 227 @TestApi reloadPersistedData()228 public void reloadPersistedData() { 229 try { 230 mBinder.reloadPersistedData(); 231 } catch (RemoteException e) { 232 throw e.rethrowFromSystemServer(); 233 } 234 } 235 236 /** 237 * Expire the rollback data for a given package. 238 * This API is meant to facilitate testing of rollback logic for 239 * expiring rollback data. Removes rollback data for available and 240 * recently committed rollbacks that contain the given package. 241 * 242 * @param packageName the name of the package to expire data for. 243 * @throws SecurityException if the caller does not have appropriate permissions. 244 * 245 * @hide 246 */ 247 @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) 248 @TestApi expireRollbackForPackage(@onNull String packageName)249 public void expireRollbackForPackage(@NonNull String packageName) { 250 try { 251 mBinder.expireRollbackForPackage(packageName); 252 } catch (RemoteException e) { 253 throw e.rethrowFromSystemServer(); 254 } 255 } 256 257 /** 258 * Block the RollbackManager for a specified amount of time. 259 * This API is meant to facilitate testing of race conditions in 260 * RollbackManager. Blocks RollbackManager from processing anything for 261 * the given number of milliseconds. 262 * 263 * @param millis number of milliseconds to block the RollbackManager for 264 * @throws SecurityException if the caller does not have appropriate permissions. 265 * 266 * @hide 267 */ 268 @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) 269 @TestApi blockRollbackManager(long millis)270 public void blockRollbackManager(long millis) { 271 try { 272 mBinder.blockRollbackManager(millis); 273 } catch (RemoteException e) { 274 throw e.rethrowFromSystemServer(); 275 } 276 } 277 } 278