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