Home | History | Annotate | Download | only in os
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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