• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl and
43  * system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl.
44  *
45  * {@hide}
46  */
47 @SystemApi
48 public class UpdateEngine {
49     private static final String TAG = "UpdateEngine";
50 
51     private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
52 
53     /**
54      * Error code from the update engine. Values must agree with the ones in
55      * system/update_engine/common/error_code.h.
56      */
57     @SystemApi
58     public static final class ErrorCodeConstants {
59         public static final int SUCCESS = 0;
60         public static final int ERROR = 1;
61         public static final int FILESYSTEM_COPIER_ERROR = 4;
62         public static final int POST_INSTALL_RUNNER_ERROR = 5;
63         public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
64         public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
65         public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
66         public static final int DOWNLOAD_TRANSFER_ERROR = 9;
67         public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
68         public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
69         public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
70         public static final int UPDATED_BUT_NOT_ACTIVE = 52;
71     }
72 
73     /**
74      * Update status code from the update engine. Values must agree with the
75      * ones in system/update_engine/client_library/include/update_engine/update_status.h.
76      */
77     @SystemApi
78     public static final class UpdateStatusConstants {
79         public static final int IDLE = 0;
80         public static final int CHECKING_FOR_UPDATE = 1;
81         public static final int UPDATE_AVAILABLE = 2;
82         public static final int DOWNLOADING = 3;
83         public static final int VERIFYING = 4;
84         public static final int FINALIZING = 5;
85         public static final int UPDATED_NEED_REBOOT = 6;
86         public static final int REPORTING_ERROR_EVENT = 7;
87         public static final int ATTEMPTING_ROLLBACK = 8;
88         public static final int DISABLED = 9;
89     }
90 
91     private IUpdateEngine mUpdateEngine;
92     private IUpdateEngineCallback mUpdateEngineCallback = null;
93     private final Object mUpdateEngineCallbackLock = new Object();
94 
95     /**
96      * Creates a new instance.
97      */
98     @SystemApi
UpdateEngine()99     public UpdateEngine() {
100         mUpdateEngine = IUpdateEngine.Stub.asInterface(
101                 ServiceManager.getService(UPDATE_ENGINE_SERVICE));
102     }
103 
104     /**
105      * Prepares this instance for use. The callback will be notified on any
106      * status change, and when the update completes. A handler can be supplied
107      * to control which thread runs the callback, or null.
108      */
109     @SystemApi
bind(final UpdateEngineCallback callback, final Handler handler)110     public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
111         synchronized (mUpdateEngineCallbackLock) {
112             mUpdateEngineCallback = new IUpdateEngineCallback.Stub() {
113                 @Override
114                 public void onStatusUpdate(final int status, final float percent) {
115                     if (handler != null) {
116                         handler.post(new Runnable() {
117                             @Override
118                             public void run() {
119                                 callback.onStatusUpdate(status, percent);
120                             }
121                         });
122                     } else {
123                         callback.onStatusUpdate(status, percent);
124                     }
125                 }
126 
127                 @Override
128                 public void onPayloadApplicationComplete(final int errorCode) {
129                     if (handler != null) {
130                         handler.post(new Runnable() {
131                             @Override
132                             public void run() {
133                                 callback.onPayloadApplicationComplete(errorCode);
134                             }
135                         });
136                     } else {
137                         callback.onPayloadApplicationComplete(errorCode);
138                     }
139                 }
140             };
141 
142             try {
143                 return mUpdateEngine.bind(mUpdateEngineCallback);
144             } catch (RemoteException e) {
145                 throw e.rethrowFromSystemServer();
146             }
147         }
148     }
149 
150     /**
151      * Equivalent to {@code bind(callback, null)}.
152      */
153     @SystemApi
bind(final UpdateEngineCallback callback)154     public boolean bind(final UpdateEngineCallback callback) {
155         return bind(callback, null);
156     }
157 
158     /**
159      * Applies the payload found at the given {@code url}. For non-streaming
160      * updates, the URL can be a local file using the {@code file://} scheme.
161      *
162      * <p>The {@code offset} and {@code size} parameters specify the location
163      * of the payload within the file represented by the URL. This is useful
164      * if the downloadable package at the URL contains more than just the
165      * update_engine payload (such as extra metadata). This is true for
166      * Google's OTA system, where the URL points to a zip file in which the
167      * payload is stored uncompressed within the zip file alongside other
168      * data.
169      *
170      * <p>The {@code headerKeyValuePairs} parameter is used to pass metadata
171      * to update_engine. In Google's implementation, this is stored as
172      * {@code payload_properties.txt} in the zip file. It's generated by the
173      * script {@code system/update_engine/scripts/brillo_update_payload}.
174      * The complete list of keys and their documentation is in
175      * {@code system/update_engine/common/constants.cc}, but an example
176      * might be:
177      * <pre>
178      * String[] pairs = {
179      *   "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=",
180      *   "FILE_SIZE=871903868",
181      *   "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=",
182      *   "METADATA_SIZE=70604"
183      * };
184      * </pre>
185      */
186     @SystemApi
applyPayload(String url, long offset, long size, String[] headerKeyValuePairs)187     public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
188         try {
189             mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
190         } catch (RemoteException e) {
191             throw e.rethrowFromSystemServer();
192         }
193     }
194 
195     /**
196      * Permanently cancels an in-progress update.
197      *
198      * <p>See {@link #resetStatus} to undo a finshed update (only available
199      * before the updated system has been rebooted).
200      *
201      * <p>See {@link #suspend} for a way to temporarily stop an in-progress
202      * update with the ability to resume it later.
203      */
204     @SystemApi
cancel()205     public void cancel() {
206         try {
207             mUpdateEngine.cancel();
208         } catch (RemoteException e) {
209             throw e.rethrowFromSystemServer();
210         }
211     }
212 
213     /**
214      * Suspends an in-progress update. This can be undone by calling
215      * {@link #resume}.
216      */
217     @SystemApi
suspend()218     public void suspend() {
219         try {
220             mUpdateEngine.suspend();
221         } catch (RemoteException e) {
222             throw e.rethrowFromSystemServer();
223         }
224     }
225 
226     /**
227      * Resumes a suspended update.
228      */
229     @SystemApi
resume()230     public void resume() {
231         try {
232             mUpdateEngine.resume();
233         } catch (RemoteException e) {
234             throw e.rethrowFromSystemServer();
235         }
236     }
237 
238     /**
239      * Resets the bootable flag on the non-current partition and all internal
240      * update_engine state. This can be used after an unwanted payload has been
241      * successfully applied and the device has not yet been rebooted to signal
242      * that we no longer want to boot into that updated system. After this call
243      * completes, update_engine will no longer report
244      * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
245      * notification that rebooting into the new system is possible.
246      */
247     @SystemApi
resetStatus()248     public void resetStatus() {
249         try {
250             mUpdateEngine.resetStatus();
251         } catch (RemoteException e) {
252             throw e.rethrowFromSystemServer();
253         }
254     }
255 
256     /**
257      * Unbinds the last bound callback function.
258      */
259     @SystemApi
unbind()260     public boolean unbind() {
261         synchronized (mUpdateEngineCallbackLock) {
262             if (mUpdateEngineCallback == null) {
263                 return true;
264             }
265             try {
266                 boolean result = mUpdateEngine.unbind(mUpdateEngineCallback);
267                 mUpdateEngineCallback = null;
268                 return result;
269             } catch (RemoteException e) {
270                 throw e.rethrowFromSystemServer();
271             }
272         }
273     }
274 
275     /**
276      * Verifies that a payload associated with the given payload metadata
277      * {@code payloadMetadataFilename} can be safely applied to ths device.
278      * Returns {@code true} if the update can successfully be applied and
279      * returns {@code false} otherwise.
280      *
281      * @param payloadMetadataFilename the location of the metadata without the
282      * {@code file://} prefix.
283      */
284     @SystemApi
verifyPayloadMetadata(String payloadMetadataFilename)285     public boolean verifyPayloadMetadata(String payloadMetadataFilename) {
286         try {
287             return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename);
288         } catch (RemoteException e) {
289             throw e.rethrowFromSystemServer();
290         }
291     }
292 }
293