blob: a9ddffe7d55c00ed92c4b2e0d7187a5afc407eb9 [file] [log] [blame]
Tao Bao43cd1bc2016-02-08 09:51:38 -08001/*
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
17package android.os;
18
Kyeongkab.Nam77f1aac2019-09-12 11:33:39 +090019import android.annotation.NonNull;
Tao Bao43cd1bc2016-02-08 09:51:38 -080020import android.annotation.SystemApi;
21import android.os.IUpdateEngine;
22import android.os.IUpdateEngineCallback;
23import android.os.RemoteException;
24
Tao Bao43cd1bc2016-02-08 09:51:38 -080025/**
26 * UpdateEngine handles calls to the update engine which takes care of A/B OTA
27 * updates. It wraps up the update engine Binder APIs and exposes them as
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -080028 * SystemApis, which will be called by the system app responsible for OTAs.
29 * On a Google device, this will be GmsCore.
30 *
31 * The minimal flow is:
32 * <ol>
33 * <li>Create a new UpdateEngine instance.
34 * <li>Call {@link #bind}, optionally providing callbacks.
35 * <li>Call {@link #applyPayload}.
36 * </ol>
37 *
38 * In addition, methods are provided to {@link #cancel} or
39 * {@link #suspend}/{@link #resume} application of an update.
Tao Bao43cd1bc2016-02-08 09:51:38 -080040 *
41 * The APIs defined in this class and UpdateEngineCallback class must be in
42 * sync with the ones in
Tao Baoaa028f02019-03-08 13:37:57 -080043 * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl}
44 * and
45 * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}.
Tao Bao43cd1bc2016-02-08 09:51:38 -080046 *
47 * {@hide}
48 */
49@SystemApi
50public class UpdateEngine {
51 private static final String TAG = "UpdateEngine";
52
53 private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
54
55 /**
Tao Baoaa028f02019-03-08 13:37:57 -080056 * Error codes from update engine upon finishing a call to
57 * {@link applyPayload}. Values will be passed via the callback function
58 * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must
59 * agree with the ones in {@code system/update_engine/common/error_code.h}.
Tao Bao43cd1bc2016-02-08 09:51:38 -080060 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080061 public static final class ErrorCodeConstants {
Tao Baoaa028f02019-03-08 13:37:57 -080062 /**
63 * Error code: a request finished successfully.
64 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080065 public static final int SUCCESS = 0;
Tao Baoaa028f02019-03-08 13:37:57 -080066 /**
67 * Error code: a request failed due to a generic error.
68 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080069 public static final int ERROR = 1;
Tao Baoaa028f02019-03-08 13:37:57 -080070 /**
71 * Error code: an update failed to apply due to filesystem copier
72 * error.
73 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080074 public static final int FILESYSTEM_COPIER_ERROR = 4;
Tao Baoaa028f02019-03-08 13:37:57 -080075 /**
76 * Error code: an update failed to apply due to an error in running
77 * post-install hooks.
78 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080079 public static final int POST_INSTALL_RUNNER_ERROR = 5;
Tao Baoaa028f02019-03-08 13:37:57 -080080 /**
81 * Error code: an update failed to apply due to a mismatching payload.
82 *
83 * <p>For example, the given payload uses a feature that's not
84 * supported by the current update engine.
85 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080086 public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
Tao Baoaa028f02019-03-08 13:37:57 -080087 /**
88 * Error code: an update failed to apply due to an error in opening
89 * devices.
90 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080091 public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
Tao Baoaa028f02019-03-08 13:37:57 -080092 /**
93 * Error code: an update failed to apply due to an error in opening
94 * kernel device.
95 */
Tao Bao43cd1bc2016-02-08 09:51:38 -080096 public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
Tao Baoaa028f02019-03-08 13:37:57 -080097 /**
98 * Error code: an update failed to apply due to an error in fetching
99 * the payload.
100 *
101 * <p>For example, this could be a result of bad network connection
102 * when streaming an update.
103 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800104 public static final int DOWNLOAD_TRANSFER_ERROR = 9;
Tao Baoaa028f02019-03-08 13:37:57 -0800105 /**
106 * Error code: an update failed to apply due to a mismatch in payload
107 * hash.
108 *
109 * <p>Update engine does sanity checks for the given payload and its
110 * metadata.
111 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800112 public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
Tao Baoaa028f02019-03-08 13:37:57 -0800113
114 /**
115 * Error code: an update failed to apply due to a mismatch in payload
116 * size.
117 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800118 public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
Tao Baoaa028f02019-03-08 13:37:57 -0800119
120 /**
121 * Error code: an update failed to apply due to failing to verify
122 * payload signatures.
123 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800124 public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
Tao Baoaa028f02019-03-08 13:37:57 -0800125
126 /**
127 * Error code: an update failed to apply due to a downgrade in payload
128 * timestamp.
129 *
130 * <p>The timestamp of a build is encoded into the payload, which will
131 * be enforced during install to prevent downgrading a device.
132 */
Alex Kershaw7bcb2fa2019-01-04 15:17:39 +0000133 public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
Tao Baoaa028f02019-03-08 13:37:57 -0800134
135 /**
136 * Error code: an update has been applied successfully but the new slot
137 * hasn't been set to active.
138 *
139 * <p>It indicates a successful finish of calling {@link #applyPayload} with
140 * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
141 */
scypherf5a53652017-11-06 14:45:12 -0800142 public static final int UPDATED_BUT_NOT_ACTIVE = 52;
Tao Bao43cd1bc2016-02-08 09:51:38 -0800143 }
144
145 /**
Tao Baoaa028f02019-03-08 13:37:57 -0800146 * Status codes for update engine. Values must agree with the ones in
147 * {@code system/update_engine/client_library/include/update_engine/update_status.h}.
Tao Bao43cd1bc2016-02-08 09:51:38 -0800148 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800149 public static final class UpdateStatusConstants {
Tao Baoaa028f02019-03-08 13:37:57 -0800150 /**
151 * Update status code: update engine is in idle state.
152 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800153 public static final int IDLE = 0;
Tao Baoaa028f02019-03-08 13:37:57 -0800154
155 /**
156 * Update status code: update engine is checking for update.
157 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800158 public static final int CHECKING_FOR_UPDATE = 1;
Tao Baoaa028f02019-03-08 13:37:57 -0800159
160 /**
161 * Update status code: an update is available.
162 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800163 public static final int UPDATE_AVAILABLE = 2;
Tao Baoaa028f02019-03-08 13:37:57 -0800164
165 /**
166 * Update status code: update engine is downloading an update.
167 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800168 public static final int DOWNLOADING = 3;
Tao Baoaa028f02019-03-08 13:37:57 -0800169
170 /**
171 * Update status code: update engine is verifying an update.
172 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800173 public static final int VERIFYING = 4;
Tao Baoaa028f02019-03-08 13:37:57 -0800174
175 /**
176 * Update status code: update engine is finalizing an update.
177 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800178 public static final int FINALIZING = 5;
Tao Baoaa028f02019-03-08 13:37:57 -0800179
180 /**
181 * Update status code: an update has been applied and is pending for
182 * reboot.
183 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800184 public static final int UPDATED_NEED_REBOOT = 6;
Tao Baoaa028f02019-03-08 13:37:57 -0800185
186 /**
187 * Update status code: update engine is reporting an error event.
188 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800189 public static final int REPORTING_ERROR_EVENT = 7;
Tao Baoaa028f02019-03-08 13:37:57 -0800190
191 /**
192 * Update status code: update engine is attempting to rollback an
193 * update.
194 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800195 public static final int ATTEMPTING_ROLLBACK = 8;
Tao Baoaa028f02019-03-08 13:37:57 -0800196
197 /**
198 * Update status code: update engine is in disabled state.
199 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800200 public static final int DISABLED = 9;
201 }
202
203 private IUpdateEngine mUpdateEngine;
Tao Bao445c3042017-07-16 11:21:03 -0700204 private IUpdateEngineCallback mUpdateEngineCallback = null;
205 private final Object mUpdateEngineCallbackLock = new Object();
Tao Bao43cd1bc2016-02-08 09:51:38 -0800206
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800207 /**
208 * Creates a new instance.
209 */
Tao Bao43cd1bc2016-02-08 09:51:38 -0800210 public UpdateEngine() {
211 mUpdateEngine = IUpdateEngine.Stub.asInterface(
212 ServiceManager.getService(UPDATE_ENGINE_SERVICE));
213 }
214
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800215 /**
216 * Prepares this instance for use. The callback will be notified on any
217 * status change, and when the update completes. A handler can be supplied
218 * to control which thread runs the callback, or null.
219 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700220 public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
Tao Bao445c3042017-07-16 11:21:03 -0700221 synchronized (mUpdateEngineCallbackLock) {
222 mUpdateEngineCallback = new IUpdateEngineCallback.Stub() {
223 @Override
224 public void onStatusUpdate(final int status, final float percent) {
225 if (handler != null) {
226 handler.post(new Runnable() {
227 @Override
228 public void run() {
229 callback.onStatusUpdate(status, percent);
230 }
231 });
232 } else {
233 callback.onStatusUpdate(status, percent);
234 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800235 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800236
Tao Bao445c3042017-07-16 11:21:03 -0700237 @Override
238 public void onPayloadApplicationComplete(final int errorCode) {
239 if (handler != null) {
240 handler.post(new Runnable() {
241 @Override
242 public void run() {
243 callback.onPayloadApplicationComplete(errorCode);
244 }
245 });
246 } else {
247 callback.onPayloadApplicationComplete(errorCode);
248 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800249 }
Tao Bao445c3042017-07-16 11:21:03 -0700250 };
Tao Bao43cd1bc2016-02-08 09:51:38 -0800251
Tao Bao445c3042017-07-16 11:21:03 -0700252 try {
253 return mUpdateEngine.bind(mUpdateEngineCallback);
254 } catch (RemoteException e) {
255 throw e.rethrowFromSystemServer();
256 }
Tao Baob7e47ae2016-03-22 12:30:23 -0700257 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800258 }
259
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800260 /**
261 * Equivalent to {@code bind(callback, null)}.
262 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700263 public boolean bind(final UpdateEngineCallback callback) {
Tao Bao43cd1bc2016-02-08 09:51:38 -0800264 return bind(callback, null);
265 }
266
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800267 /**
268 * Applies the payload found at the given {@code url}. For non-streaming
269 * updates, the URL can be a local file using the {@code file://} scheme.
270 *
271 * <p>The {@code offset} and {@code size} parameters specify the location
272 * of the payload within the file represented by the URL. This is useful
273 * if the downloadable package at the URL contains more than just the
274 * update_engine payload (such as extra metadata). This is true for
275 * Google's OTA system, where the URL points to a zip file in which the
276 * payload is stored uncompressed within the zip file alongside other
277 * data.
278 *
279 * <p>The {@code headerKeyValuePairs} parameter is used to pass metadata
280 * to update_engine. In Google's implementation, this is stored as
281 * {@code payload_properties.txt} in the zip file. It's generated by the
282 * script {@code system/update_engine/scripts/brillo_update_payload}.
283 * The complete list of keys and their documentation is in
284 * {@code system/update_engine/common/constants.cc}, but an example
285 * might be:
286 * <pre>
287 * String[] pairs = {
288 * "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=",
289 * "FILE_SIZE=871903868",
290 * "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=",
291 * "METADATA_SIZE=70604"
292 * };
293 * </pre>
Tao Baoaa028f02019-03-08 13:37:57 -0800294 *
295 * <p>The callback functions registered via {@code #bind} will be called
296 * during and at the end of the payload application.
297 *
298 * <p>By default the newly updated slot will be set active upon
299 * successfully finishing an update. Device will attempt to boot into the
300 * new slot on next reboot. This behavior can be customized by specifying
301 * {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which
302 * allows the caller to later determine a good time to boot into the new
303 * slot. Calling {@code applyPayload} again with the same payload but with
304 * {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new
305 * slot active, after verifying its integrity.
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800306 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700307 public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
308 try {
309 mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
310 } catch (RemoteException e) {
311 throw e.rethrowFromSystemServer();
312 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800313 }
314
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800315 /**
Kyeongkab.Nam73fde382019-09-26 10:44:32 +0900316 * Applies the payload passed as ParcelFileDescriptor {@code pfd} instead of
Kyeongkab.Nambcc56332019-04-09 12:07:37 +0900317 * using the {@code file://} scheme.
318 *
319 * <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and
320 * {@code headerKeyValuePairs} parameters.
321 */
Kyeongkab.Nam73fde382019-09-26 10:44:32 +0900322 public void applyPayload(@NonNull ParcelFileDescriptor pfd, long offset, long size,
Kyeongkab.Nam77f1aac2019-09-12 11:33:39 +0900323 @NonNull String[] headerKeyValuePairs) {
Kyeongkab.Nambcc56332019-04-09 12:07:37 +0900324 try {
Kyeongkab.Nam73fde382019-09-26 10:44:32 +0900325 mUpdateEngine.applyPayloadFd(pfd, offset, size, headerKeyValuePairs);
Kyeongkab.Nambcc56332019-04-09 12:07:37 +0900326 } catch (RemoteException e) {
327 throw e.rethrowFromSystemServer();
328 }
329 }
330
331 /**
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800332 * Permanently cancels an in-progress update.
333 *
334 * <p>See {@link #resetStatus} to undo a finshed update (only available
335 * before the updated system has been rebooted).
336 *
337 * <p>See {@link #suspend} for a way to temporarily stop an in-progress
338 * update with the ability to resume it later.
339 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700340 public void cancel() {
341 try {
342 mUpdateEngine.cancel();
343 } catch (RemoteException e) {
344 throw e.rethrowFromSystemServer();
345 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800346 }
347
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800348 /**
349 * Suspends an in-progress update. This can be undone by calling
350 * {@link #resume}.
351 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700352 public void suspend() {
353 try {
354 mUpdateEngine.suspend();
355 } catch (RemoteException e) {
356 throw e.rethrowFromSystemServer();
357 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800358 }
359
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800360 /**
361 * Resumes a suspended update.
362 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700363 public void resume() {
364 try {
365 mUpdateEngine.resume();
366 } catch (RemoteException e) {
367 throw e.rethrowFromSystemServer();
368 }
369 }
370
Elliott Hughese3ce3e8b2017-02-27 09:37:02 -0800371 /**
372 * Resets the bootable flag on the non-current partition and all internal
373 * update_engine state. This can be used after an unwanted payload has been
374 * successfully applied and the device has not yet been rebooted to signal
375 * that we no longer want to boot into that updated system. After this call
376 * completes, update_engine will no longer report
377 * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
378 * notification that rebooting into the new system is possible.
379 */
Tao Baob7e47ae2016-03-22 12:30:23 -0700380 public void resetStatus() {
381 try {
382 mUpdateEngine.resetStatus();
383 } catch (RemoteException e) {
384 throw e.rethrowFromSystemServer();
385 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800386 }
Tao Bao445c3042017-07-16 11:21:03 -0700387
388 /**
389 * Unbinds the last bound callback function.
390 */
Tao Bao445c3042017-07-16 11:21:03 -0700391 public boolean unbind() {
392 synchronized (mUpdateEngineCallbackLock) {
393 if (mUpdateEngineCallback == null) {
394 return true;
395 }
396 try {
397 boolean result = mUpdateEngine.unbind(mUpdateEngineCallback);
398 mUpdateEngineCallback = null;
399 return result;
400 } catch (RemoteException e) {
401 throw e.rethrowFromSystemServer();
402 }
403 }
404 }
Tao Baod27be342018-01-10 11:40:19 -0800405
406 /**
407 * Verifies that a payload associated with the given payload metadata
408 * {@code payloadMetadataFilename} can be safely applied to ths device.
409 * Returns {@code true} if the update can successfully be applied and
410 * returns {@code false} otherwise.
411 *
412 * @param payloadMetadataFilename the location of the metadata without the
413 * {@code file://} prefix.
414 */
Tao Baod27be342018-01-10 11:40:19 -0800415 public boolean verifyPayloadMetadata(String payloadMetadataFilename) {
416 try {
417 return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename);
418 } catch (RemoteException e) {
419 throw e.rethrowFromSystemServer();
420 }
421 }
Tao Bao43cd1bc2016-02-08 09:51:38 -0800422}