1 /* 2 * Copyright (C) 2016 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.os; 18 19 import android.annotation.SystemApi; 20 import android.os.IUpdateEngine; 21 import android.os.IUpdateEngineCallback; 22 import android.os.RemoteException; 23 24 /** 25 * UpdateEngine handles calls to the update engine which takes care of A/B OTA 26 * updates. It wraps up the update engine Binder APIs and exposes them as 27 * SystemApis, which will be called by the system app responsible for OTAs. 28 * On a Google device, this will be GmsCore. 29 * 30 * The minimal flow is: 31 * <ol> 32 * <li>Create a new UpdateEngine instance. 33 * <li>Call {@link #bind}, optionally providing callbacks. 34 * <li>Call {@link #applyPayload}. 35 * </ol> 36 * 37 * In addition, methods are provided to {@link #cancel} or 38 * {@link #suspend}/{@link #resume} application of an update. 39 * 40 * The APIs defined in this class and UpdateEngineCallback class must be in 41 * sync with the ones in 42 * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl} 43 * and 44 * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}. 45 * 46 * {@hide} 47 */ 48 @SystemApi 49 public class UpdateEngine { 50 private static final String TAG = "UpdateEngine"; 51 52 private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService"; 53 54 /** 55 * Error codes from update engine upon finishing a call to 56 * {@link applyPayload}. Values will be passed via the callback function 57 * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must 58 * agree with the ones in {@code system/update_engine/common/error_code.h}. 59 */ 60 public static final class ErrorCodeConstants { 61 /** 62 * Error code: a request finished successfully. 63 */ 64 public static final int SUCCESS = 0; 65 /** 66 * Error code: a request failed due to a generic error. 67 */ 68 public static final int ERROR = 1; 69 /** 70 * Error code: an update failed to apply due to filesystem copier 71 * error. 72 */ 73 public static final int FILESYSTEM_COPIER_ERROR = 4; 74 /** 75 * Error code: an update failed to apply due to an error in running 76 * post-install hooks. 77 */ 78 public static final int POST_INSTALL_RUNNER_ERROR = 5; 79 /** 80 * Error code: an update failed to apply due to a mismatching payload. 81 * 82 * <p>For example, the given payload uses a feature that's not 83 * supported by the current update engine. 84 */ 85 public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; 86 /** 87 * Error code: an update failed to apply due to an error in opening 88 * devices. 89 */ 90 public static final int INSTALL_DEVICE_OPEN_ERROR = 7; 91 /** 92 * Error code: an update failed to apply due to an error in opening 93 * kernel device. 94 */ 95 public static final int KERNEL_DEVICE_OPEN_ERROR = 8; 96 /** 97 * Error code: an update failed to apply due to an error in fetching 98 * the payload. 99 * 100 * <p>For example, this could be a result of bad network connection 101 * when streaming an update. 102 */ 103 public static final int DOWNLOAD_TRANSFER_ERROR = 9; 104 /** 105 * Error code: an update failed to apply due to a mismatch in payload 106 * hash. 107 * 108 * <p>Update engine does sanity checks for the given payload and its 109 * metadata. 110 */ 111 public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; 112 113 /** 114 * Error code: an update failed to apply due to a mismatch in payload 115 * size. 116 */ 117 public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; 118 119 /** 120 * Error code: an update failed to apply due to failing to verify 121 * payload signatures. 122 */ 123 public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; 124 125 /** 126 * Error code: an update failed to apply due to a downgrade in payload 127 * timestamp. 128 * 129 * <p>The timestamp of a build is encoded into the payload, which will 130 * be enforced during install to prevent downgrading a device. 131 */ 132 public static final int PAYLOAD_TIMESTAMP_ERROR = 51; 133 134 /** 135 * Error code: an update has been applied successfully but the new slot 136 * hasn't been set to active. 137 * 138 * <p>It indicates a successful finish of calling {@link #applyPayload} with 139 * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}. 140 */ 141 public static final int UPDATED_BUT_NOT_ACTIVE = 52; 142 } 143 144 /** 145 * Status codes for update engine. Values must agree with the ones in 146 * {@code system/update_engine/client_library/include/update_engine/update_status.h}. 147 */ 148 public static final class UpdateStatusConstants { 149 /** 150 * Update status code: update engine is in idle state. 151 */ 152 public static final int IDLE = 0; 153 154 /** 155 * Update status code: update engine is checking for update. 156 */ 157 public static final int CHECKING_FOR_UPDATE = 1; 158 159 /** 160 * Update status code: an update is available. 161 */ 162 public static final int UPDATE_AVAILABLE = 2; 163 164 /** 165 * Update status code: update engine is downloading an update. 166 */ 167 public static final int DOWNLOADING = 3; 168 169 /** 170 * Update status code: update engine is verifying an update. 171 */ 172 public static final int VERIFYING = 4; 173 174 /** 175 * Update status code: update engine is finalizing an update. 176 */ 177 public static final int FINALIZING = 5; 178 179 /** 180 * Update status code: an update has been applied and is pending for 181 * reboot. 182 */ 183 public static final int UPDATED_NEED_REBOOT = 6; 184 185 /** 186 * Update status code: update engine is reporting an error event. 187 */ 188 public static final int REPORTING_ERROR_EVENT = 7; 189 190 /** 191 * Update status code: update engine is attempting to rollback an 192 * update. 193 */ 194 public static final int ATTEMPTING_ROLLBACK = 8; 195 196 /** 197 * Update status code: update engine is in disabled state. 198 */ 199 public static final int DISABLED = 9; 200 } 201 202 private IUpdateEngine mUpdateEngine; 203 private IUpdateEngineCallback mUpdateEngineCallback = null; 204 private final Object mUpdateEngineCallbackLock = new Object(); 205 206 /** 207 * Creates a new instance. 208 */ UpdateEngine()209 public UpdateEngine() { 210 mUpdateEngine = IUpdateEngine.Stub.asInterface( 211 ServiceManager.getService(UPDATE_ENGINE_SERVICE)); 212 } 213 214 /** 215 * Prepares this instance for use. The callback will be notified on any 216 * status change, and when the update completes. A handler can be supplied 217 * to control which thread runs the callback, or null. 218 */ bind(final UpdateEngineCallback callback, final Handler handler)219 public boolean bind(final UpdateEngineCallback callback, final Handler handler) { 220 synchronized (mUpdateEngineCallbackLock) { 221 mUpdateEngineCallback = new IUpdateEngineCallback.Stub() { 222 @Override 223 public void onStatusUpdate(final int status, final float percent) { 224 if (handler != null) { 225 handler.post(new Runnable() { 226 @Override 227 public void run() { 228 callback.onStatusUpdate(status, percent); 229 } 230 }); 231 } else { 232 callback.onStatusUpdate(status, percent); 233 } 234 } 235 236 @Override 237 public void onPayloadApplicationComplete(final int errorCode) { 238 if (handler != null) { 239 handler.post(new Runnable() { 240 @Override 241 public void run() { 242 callback.onPayloadApplicationComplete(errorCode); 243 } 244 }); 245 } else { 246 callback.onPayloadApplicationComplete(errorCode); 247 } 248 } 249 }; 250 251 try { 252 return mUpdateEngine.bind(mUpdateEngineCallback); 253 } catch (RemoteException e) { 254 throw e.rethrowFromSystemServer(); 255 } 256 } 257 } 258 259 /** 260 * Equivalent to {@code bind(callback, null)}. 261 */ bind(final UpdateEngineCallback callback)262 public boolean bind(final UpdateEngineCallback callback) { 263 return bind(callback, null); 264 } 265 266 /** 267 * Applies the payload found at the given {@code url}. For non-streaming 268 * updates, the URL can be a local file using the {@code file://} scheme. 269 * 270 * <p>The {@code offset} and {@code size} parameters specify the location 271 * of the payload within the file represented by the URL. This is useful 272 * if the downloadable package at the URL contains more than just the 273 * update_engine payload (such as extra metadata). This is true for 274 * Google's OTA system, where the URL points to a zip file in which the 275 * payload is stored uncompressed within the zip file alongside other 276 * data. 277 * 278 * <p>The {@code headerKeyValuePairs} parameter is used to pass metadata 279 * to update_engine. In Google's implementation, this is stored as 280 * {@code payload_properties.txt} in the zip file. It's generated by the 281 * script {@code system/update_engine/scripts/brillo_update_payload}. 282 * The complete list of keys and their documentation is in 283 * {@code system/update_engine/common/constants.cc}, but an example 284 * might be: 285 * <pre> 286 * String[] pairs = { 287 * "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=", 288 * "FILE_SIZE=871903868", 289 * "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=", 290 * "METADATA_SIZE=70604" 291 * }; 292 * </pre> 293 * 294 * <p>The callback functions registered via {@code #bind} will be called 295 * during and at the end of the payload application. 296 * 297 * <p>By default the newly updated slot will be set active upon 298 * successfully finishing an update. Device will attempt to boot into the 299 * new slot on next reboot. This behavior can be customized by specifying 300 * {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which 301 * allows the caller to later determine a good time to boot into the new 302 * slot. Calling {@code applyPayload} again with the same payload but with 303 * {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new 304 * slot active, after verifying its integrity. 305 */ applyPayload(String url, long offset, long size, String[] headerKeyValuePairs)306 public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) { 307 try { 308 mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs); 309 } catch (RemoteException e) { 310 throw e.rethrowFromSystemServer(); 311 } 312 } 313 314 /** 315 * Permanently cancels an in-progress update. 316 * 317 * <p>See {@link #resetStatus} to undo a finshed update (only available 318 * before the updated system has been rebooted). 319 * 320 * <p>See {@link #suspend} for a way to temporarily stop an in-progress 321 * update with the ability to resume it later. 322 */ cancel()323 public void cancel() { 324 try { 325 mUpdateEngine.cancel(); 326 } catch (RemoteException e) { 327 throw e.rethrowFromSystemServer(); 328 } 329 } 330 331 /** 332 * Suspends an in-progress update. This can be undone by calling 333 * {@link #resume}. 334 */ suspend()335 public void suspend() { 336 try { 337 mUpdateEngine.suspend(); 338 } catch (RemoteException e) { 339 throw e.rethrowFromSystemServer(); 340 } 341 } 342 343 /** 344 * Resumes a suspended update. 345 */ resume()346 public void resume() { 347 try { 348 mUpdateEngine.resume(); 349 } catch (RemoteException e) { 350 throw e.rethrowFromSystemServer(); 351 } 352 } 353 354 /** 355 * Resets the bootable flag on the non-current partition and all internal 356 * update_engine state. This can be used after an unwanted payload has been 357 * successfully applied and the device has not yet been rebooted to signal 358 * that we no longer want to boot into that updated system. After this call 359 * completes, update_engine will no longer report 360 * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding 361 * notification that rebooting into the new system is possible. 362 */ resetStatus()363 public void resetStatus() { 364 try { 365 mUpdateEngine.resetStatus(); 366 } catch (RemoteException e) { 367 throw e.rethrowFromSystemServer(); 368 } 369 } 370 371 /** 372 * Unbinds the last bound callback function. 373 */ unbind()374 public boolean unbind() { 375 synchronized (mUpdateEngineCallbackLock) { 376 if (mUpdateEngineCallback == null) { 377 return true; 378 } 379 try { 380 boolean result = mUpdateEngine.unbind(mUpdateEngineCallback); 381 mUpdateEngineCallback = null; 382 return result; 383 } catch (RemoteException e) { 384 throw e.rethrowFromSystemServer(); 385 } 386 } 387 } 388 389 /** 390 * Verifies that a payload associated with the given payload metadata 391 * {@code payloadMetadataFilename} can be safely applied to ths device. 392 * Returns {@code true} if the update can successfully be applied and 393 * returns {@code false} otherwise. 394 * 395 * @param payloadMetadataFilename the location of the metadata without the 396 * {@code file://} prefix. 397 */ verifyPayloadMetadata(String payloadMetadataFilename)398 public boolean verifyPayloadMetadata(String payloadMetadataFilename) { 399 try { 400 return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename); 401 } catch (RemoteException e) { 402 throw e.rethrowFromSystemServer(); 403 } 404 } 405 } 406