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