• 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.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.annotation.WorkerThread;
24 import android.content.res.AssetFileDescriptor;
25 import android.os.IUpdateEngine;
26 import android.os.IUpdateEngineCallback;
27 import android.os.RemoteException;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * UpdateEngine handles calls to the update engine which takes care of A/B OTA
34  * updates. It wraps up the update engine Binder APIs and exposes them as
35  * SystemApis, which will be called by the system app responsible for OTAs.
36  * On a Google device, this will be GmsCore.
37  *
38  * The minimal flow is:
39  * <ol>
40  * <li>Create a new UpdateEngine instance.
41  * <li>Call {@link #bind}, optionally providing callbacks.
42  * <li>Call {@link #applyPayload}.
43  * </ol>
44  *
45  * In addition, methods are provided to {@link #cancel} or
46  * {@link #suspend}/{@link #resume} application of an update.
47  *
48  * The APIs defined in this class and UpdateEngineCallback class must be in
49  * sync with the ones in
50  * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl}
51  * and
52  * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}.
53  *
54  * {@hide}
55  */
56 @SystemApi
57 public class UpdateEngine {
58     private static final String TAG = "UpdateEngine";
59 
60     private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
61 
62     /**
63      * Error codes from update engine upon finishing a call to
64      * {@link applyPayload}. Values will be passed via the callback function
65      * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must
66      * agree with the ones in {@code system/update_engine/common/error_code.h}.
67      */
68     public static final class ErrorCodeConstants {
69         /**
70          * Error code: a request finished successfully.
71          */
72         public static final int SUCCESS = 0;
73         /**
74          * Error code: a request failed due to a generic error.
75          */
76         public static final int ERROR = 1;
77         /**
78          * Error code: an update failed to apply due to filesystem copier
79          * error.
80          */
81         public static final int FILESYSTEM_COPIER_ERROR = 4;
82         /**
83          * Error code: an update failed to apply due to an error in running
84          * post-install hooks.
85          */
86         public static final int POST_INSTALL_RUNNER_ERROR = 5;
87         /**
88          * Error code: an update failed to apply due to a mismatching payload.
89          *
90          * <p>For example, the given payload uses a feature that's not
91          * supported by the current update engine.
92          */
93         public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
94         /**
95          * Error code: an update failed to apply due to an error in opening
96          * devices.
97          */
98         public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
99         /**
100          * Error code: an update failed to apply due to an error in opening
101          * kernel device.
102          */
103         public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
104         /**
105          * Error code: an update failed to apply due to an error in fetching
106          * the payload.
107          *
108          * <p>For example, this could be a result of bad network connection
109          * when streaming an update.
110          */
111         public static final int DOWNLOAD_TRANSFER_ERROR = 9;
112         /**
113          * Error code: an update failed to apply due to a mismatch in payload
114          * hash.
115          *
116          * <p>Update engine does validity checks for the given payload and its
117          * metadata.
118          */
119         public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
120 
121         /**
122          * Error code: an update failed to apply due to a mismatch in payload
123          * size.
124          */
125         public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
126 
127         /**
128          * Error code: an update failed to apply due to failing to verify
129          * payload signatures.
130          */
131         public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
132 
133         /**
134          * Error code: an update failed to apply due to a downgrade in payload
135          * timestamp.
136          *
137          * <p>The timestamp of a build is encoded into the payload, which will
138          * be enforced during install to prevent downgrading a device.
139          */
140         public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
141 
142         /**
143          * Error code: an update has been applied successfully but the new slot
144          * hasn't been set to active.
145          *
146          * <p>It indicates a successful finish of calling {@link #applyPayload} with
147          * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
148          */
149         public static final int UPDATED_BUT_NOT_ACTIVE = 52;
150 
151         /**
152          * Error code: there is not enough space on the device to apply the update. User should
153          * be prompted to free up space and re-try the update.
154          *
155          * <p>See {@link UpdateEngine#allocateSpace}.
156          */
157         public static final int NOT_ENOUGH_SPACE = 60;
158 
159         /**
160          * Error code: the device is corrupted and no further updates may be applied.
161          *
162          * <p>See {@link UpdateEngine#cleanupAppliedPayload}.
163          */
164         public static final int DEVICE_CORRUPTED = 61;
165     }
166 
167     /** @hide */
168     @IntDef(value = {
169             ErrorCodeConstants.SUCCESS,
170             ErrorCodeConstants.ERROR,
171             ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
172             ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
173             ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
174             ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
175             ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
176             ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
177             ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
178             ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
179             ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
180             ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
181             ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
182             ErrorCodeConstants.NOT_ENOUGH_SPACE,
183             ErrorCodeConstants.DEVICE_CORRUPTED,
184     })
185     @Retention(RetentionPolicy.SOURCE)
186     public @interface ErrorCode {}
187 
188     /**
189      * Status codes for update engine. Values must agree with the ones in
190      * {@code system/update_engine/client_library/include/update_engine/update_status.h}.
191      */
192     public static final class UpdateStatusConstants {
193         /**
194          * Update status code: update engine is in idle state.
195          */
196         public static final int IDLE = 0;
197 
198         /**
199          * Update status code: update engine is checking for update.
200          */
201         public static final int CHECKING_FOR_UPDATE = 1;
202 
203         /**
204          * Update status code: an update is available.
205          */
206         public static final int UPDATE_AVAILABLE = 2;
207 
208         /**
209          * Update status code: update engine is downloading an update.
210          */
211         public static final int DOWNLOADING = 3;
212 
213         /**
214          * Update status code: update engine is verifying an update.
215          */
216         public static final int VERIFYING = 4;
217 
218         /**
219          * Update status code: update engine is finalizing an update.
220          */
221         public static final int FINALIZING = 5;
222 
223         /**
224          * Update status code: an update has been applied and is pending for
225          * reboot.
226          */
227         public static final int UPDATED_NEED_REBOOT = 6;
228 
229         /**
230          * Update status code: update engine is reporting an error event.
231          */
232         public static final int REPORTING_ERROR_EVENT = 7;
233 
234         /**
235          * Update status code: update engine is attempting to rollback an
236          * update.
237          */
238         public static final int ATTEMPTING_ROLLBACK = 8;
239 
240         /**
241          * Update status code: update engine is in disabled state.
242          */
243         public static final int DISABLED = 9;
244     }
245 
246     private final IUpdateEngine mUpdateEngine;
247     private IUpdateEngineCallback mUpdateEngineCallback = null;
248     private final Object mUpdateEngineCallbackLock = new Object();
249 
250     /**
251      * Creates a new instance.
252      */
UpdateEngine()253     public UpdateEngine() {
254         mUpdateEngine = IUpdateEngine.Stub.asInterface(
255                 ServiceManager.getService(UPDATE_ENGINE_SERVICE));
256         if (mUpdateEngine == null) {
257             throw new IllegalStateException("Failed to find update_engine");
258         }
259     }
260 
261     /**
262      * Prepares this instance for use. The callback will be notified on any
263      * status change, and when the update completes. A handler can be supplied
264      * to control which thread runs the callback, or null.
265      */
bind(final UpdateEngineCallback callback, final Handler handler)266     public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
267         synchronized (mUpdateEngineCallbackLock) {
268             mUpdateEngineCallback = new IUpdateEngineCallback.Stub() {
269                 @Override
270                 public void onStatusUpdate(final int status, final float percent) {
271                     if (handler != null) {
272                         handler.post(new Runnable() {
273                             @Override
274                             public void run() {
275                                 callback.onStatusUpdate(status, percent);
276                             }
277                         });
278                     } else {
279                         callback.onStatusUpdate(status, percent);
280                     }
281                 }
282 
283                 @Override
284                 public void onPayloadApplicationComplete(final int errorCode) {
285                     if (handler != null) {
286                         handler.post(new Runnable() {
287                             @Override
288                             public void run() {
289                                 callback.onPayloadApplicationComplete(errorCode);
290                             }
291                         });
292                     } else {
293                         callback.onPayloadApplicationComplete(errorCode);
294                     }
295                 }
296             };
297 
298             try {
299                 return mUpdateEngine.bind(mUpdateEngineCallback);
300             } catch (RemoteException e) {
301                 throw e.rethrowFromSystemServer();
302             }
303         }
304     }
305 
306     /**
307      * Equivalent to {@code bind(callback, null)}.
308      */
bind(final UpdateEngineCallback callback)309     public boolean bind(final UpdateEngineCallback callback) {
310         return bind(callback, null);
311     }
312 
313     /**
314      * Applies the payload found at the given {@code url}. For non-streaming
315      * updates, the URL can be a local file using the {@code file://} scheme.
316      *
317      * <p>The {@code offset} and {@code size} parameters specify the location
318      * of the payload within the file represented by the URL. This is useful
319      * if the downloadable package at the URL contains more than just the
320      * update_engine payload (such as extra metadata). This is true for
321      * Google's OTA system, where the URL points to a zip file in which the
322      * payload is stored uncompressed within the zip file alongside other
323      * data.
324      *
325      * <p>The {@code headerKeyValuePairs} parameter is used to pass metadata
326      * to update_engine. In Google's implementation, this is stored as
327      * {@code payload_properties.txt} in the zip file. It's generated by the
328      * script {@code system/update_engine/scripts/brillo_update_payload}.
329      * The complete list of keys and their documentation is in
330      * {@code system/update_engine/common/constants.cc}, but an example
331      * might be:
332      * <pre>
333      * String[] pairs = {
334      *   "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=",
335      *   "FILE_SIZE=871903868",
336      *   "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=",
337      *   "METADATA_SIZE=70604"
338      * };
339      * </pre>
340      *
341      * <p>The callback functions registered via {@code #bind} will be called
342      * during and at the end of the payload application.
343      *
344      * <p>By default the newly updated slot will be set active upon
345      * successfully finishing an update. Device will attempt to boot into the
346      * new slot on next reboot. This behavior can be customized by specifying
347      * {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which
348      * allows the caller to later determine a good time to boot into the new
349      * slot. Calling {@code applyPayload} again with the same payload but with
350      * {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new
351      * slot active, after verifying its integrity.
352      */
applyPayload(String url, long offset, long size, String[] headerKeyValuePairs)353     public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
354         try {
355             mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
356         } catch (RemoteException e) {
357             throw e.rethrowFromSystemServer();
358         }
359     }
360 
361     /**
362      * Applies the payload passed as AssetFileDescriptor {@code assetFd}
363      * instead of using the {@code file://} scheme.
364      *
365      * <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and
366      * {@code headerKeyValuePairs} parameters.
367      */
applyPayload(@onNull AssetFileDescriptor assetFd, @NonNull String[] headerKeyValuePairs)368     public void applyPayload(@NonNull AssetFileDescriptor assetFd,
369             @NonNull String[] headerKeyValuePairs) {
370         try {
371             mUpdateEngine.applyPayloadFd(assetFd.getParcelFileDescriptor(),
372                     assetFd.getStartOffset(), assetFd.getLength(), headerKeyValuePairs);
373         } catch (RemoteException e) {
374             throw e.rethrowFromSystemServer();
375         }
376     }
377 
378     /**
379      * Permanently cancels an in-progress update.
380      *
381      * <p>See {@link #resetStatus} to undo a finshed update (only available
382      * before the updated system has been rebooted).
383      *
384      * <p>See {@link #suspend} for a way to temporarily stop an in-progress
385      * update with the ability to resume it later.
386      */
cancel()387     public void cancel() {
388         try {
389             mUpdateEngine.cancel();
390         } catch (RemoteException e) {
391             throw e.rethrowFromSystemServer();
392         }
393     }
394 
395     /**
396      * Suspends an in-progress update. This can be undone by calling
397      * {@link #resume}.
398      */
suspend()399     public void suspend() {
400         try {
401             mUpdateEngine.suspend();
402         } catch (RemoteException e) {
403             throw e.rethrowFromSystemServer();
404         }
405     }
406 
407     /**
408      * Resumes a suspended update.
409      */
resume()410     public void resume() {
411         try {
412             mUpdateEngine.resume();
413         } catch (RemoteException e) {
414             throw e.rethrowFromSystemServer();
415         }
416     }
417 
418     /**
419      * Resets the bootable flag on the non-current partition and all internal
420      * update_engine state. Note this call will clear the entire update
421      * progress. So a subsequent {@link #applyPayload} will apply the update
422      * from scratch.
423      *
424      * <p>After this call completes, update_engine will no longer report
425      * {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
426      * notification that rebooting into the new system is possible.
427      */
resetStatus()428     public void resetStatus() {
429         try {
430             mUpdateEngine.resetStatus();
431         } catch (RemoteException e) {
432             throw e.rethrowFromSystemServer();
433         }
434     }
435 
436     /**
437      * Sets the A/B slot switch for the next boot after applying an ota update. If
438      * {@link #applyPayload} hasn't switched the slot, the updater APP can call
439      * this API to switch the slot and apply the update on next boot.
440      *
441      * @param payloadMetadataFilename the location of the metadata without the
442      * {@code file://} prefix.
443      */
setShouldSwitchSlotOnReboot(@onNull String payloadMetadataFilename)444     public void setShouldSwitchSlotOnReboot(@NonNull String payloadMetadataFilename) {
445         try {
446             mUpdateEngine.setShouldSwitchSlotOnReboot(payloadMetadataFilename);
447         } catch (RemoteException e) {
448             throw e.rethrowFromSystemServer();
449         }
450     }
451 
452    /**
453     * Resets the boot slot to the source/current slot, without cancelling the
454     * update progress. This can be called after the update is installed, and to
455     * prevent the device from accidentally taking the update when it reboots.
456     *
457     * This is useful when users don't want to take the update immediately; or
458     * the updater determines some condition hasn't met, e.g. insufficient space
459     * for boot.
460     */
resetShouldSwitchSlotOnReboot()461     public void resetShouldSwitchSlotOnReboot() {
462         try {
463             mUpdateEngine.resetShouldSwitchSlotOnReboot();
464         } catch (RemoteException e) {
465             throw e.rethrowFromSystemServer();
466         }
467     }
468 
469     /**
470      * Unbinds the last bound callback function.
471      */
unbind()472     public boolean unbind() {
473         synchronized (mUpdateEngineCallbackLock) {
474             if (mUpdateEngineCallback == null) {
475                 return true;
476             }
477             try {
478                 boolean result = mUpdateEngine.unbind(mUpdateEngineCallback);
479                 mUpdateEngineCallback = null;
480                 return result;
481             } catch (RemoteException e) {
482                 throw e.rethrowFromSystemServer();
483             }
484         }
485     }
486 
487     /**
488      * Verifies that a payload associated with the given payload metadata
489      * {@code payloadMetadataFilename} can be safely applied to ths device.
490      * Returns {@code true} if the update can successfully be applied and
491      * returns {@code false} otherwise.
492      *
493      * @param payloadMetadataFilename the location of the metadata without the
494      * {@code file://} prefix.
495      */
verifyPayloadMetadata(String payloadMetadataFilename)496     public boolean verifyPayloadMetadata(String payloadMetadataFilename) {
497         try {
498             return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename);
499         } catch (RemoteException e) {
500             throw e.rethrowFromSystemServer();
501         }
502     }
503 
504     /**
505      * Return value of {@link #allocateSpace.}
506      */
507     public static final class AllocateSpaceResult {
508         private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS;
509         private long mFreeSpaceRequired = 0;
AllocateSpaceResult()510         private AllocateSpaceResult() {}
511         /**
512          * Error code.
513          *
514          * @return The following error codes:
515          * <ul>
516          * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated
517          *         successfully.</li>
518          * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient
519          *         space.</li>
520          * <li>Other {@link ErrorCodeConstants} for other errors.</li>
521          * </ul>
522          */
523         @ErrorCode
getErrorCode()524         public int getErrorCode() {
525             return mErrorCode;
526         }
527 
528         /**
529          * Estimated total space that needs to be available on the userdata partition to apply the
530          * payload (in bytes).
531          *
532          * <p>
533          * Note that in practice, more space needs to be made available before applying the payload
534          * to keep the device working.
535          *
536          * @return The following values:
537          * <ul>
538          * <li>zero if {@link #getErrorCode} returns {@link ErrorCodeConstants#SUCCESS}</li>
539          * <li>non-zero if {@link #getErrorCode} returns
540          * {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}.
541          * Value is the estimated total space required on userdata partition.</li>
542          * </ul>
543          * @throws IllegalStateException if {@link #getErrorCode} is not one of the above.
544          *
545          */
getFreeSpaceRequired()546         public long getFreeSpaceRequired() {
547             if (mErrorCode == ErrorCodeConstants.SUCCESS) {
548                 return 0;
549             }
550             if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) {
551                 return mFreeSpaceRequired;
552             }
553             throw new IllegalStateException(String.format(
554                     "getFreeSpaceRequired() is not available when error code is %d", mErrorCode));
555         }
556     }
557 
558     /**
559      * Initialize partitions for a payload associated with the given payload
560      * metadata {@code payloadMetadataFilename} by preallocating required space.
561      *
562      * <p>This function should be called after payload has been verified after
563      * {@link #verifyPayloadMetadata}. This function does not verify whether
564      * the given payload is applicable or not.
565      *
566      * <p>Implementation of {@code allocateSpace} uses
567      * {@code headerKeyValuePairs} to determine whether space has been allocated
568      * for a different or same payload previously. If space has been allocated
569      * for a different payload before, space will be reallocated for the given
570      * payload. If space has been allocated for the same payload, no actions to
571      * storage devices are taken.
572      *
573      * <p>This function is synchronous and may take a non-trivial amount of
574      * time. Callers should call this function in a background thread.
575      *
576      * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}.
577      * @param headerKeyValuePairs See {@link #applyPayload}.
578      * @return See {@link AllocateSpaceResult#getErrorCode} and
579      *             {@link AllocateSpaceResult#getFreeSpaceRequired}.
580      */
581     @WorkerThread
582     @NonNull
allocateSpace( @onNull String payloadMetadataFilename, @NonNull String[] headerKeyValuePairs)583     public AllocateSpaceResult allocateSpace(
584                 @NonNull String payloadMetadataFilename,
585                 @NonNull String[] headerKeyValuePairs) {
586         AllocateSpaceResult result = new AllocateSpaceResult();
587         try {
588             result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload(
589                     payloadMetadataFilename,
590                     headerKeyValuePairs);
591             result.mErrorCode = result.mFreeSpaceRequired == 0
592                     ? ErrorCodeConstants.SUCCESS
593                     : ErrorCodeConstants.NOT_ENOUGH_SPACE;
594             return result;
595         } catch (ServiceSpecificException e) {
596             result.mErrorCode = e.errorCode;
597             result.mFreeSpaceRequired = 0;
598             return result;
599         } catch (RemoteException e) {
600             throw e.rethrowFromSystemServer();
601         }
602     }
603 
604     private static class CleanupAppliedPayloadCallback extends IUpdateEngineCallback.Stub {
605         private int mErrorCode = ErrorCodeConstants.ERROR;
606         private boolean mCompleted = false;
607         private Object mLock = new Object();
getResult()608         private int getResult() {
609             synchronized (mLock) {
610                 while (!mCompleted) {
611                     try {
612                         mLock.wait();
613                     } catch (InterruptedException ex) {
614                         // do nothing, just wait again.
615                     }
616                 }
617                 return mErrorCode;
618             }
619         }
620 
621         @Override
onStatusUpdate(int status, float percent)622         public void onStatusUpdate(int status, float percent) {
623         }
624 
625         @Override
onPayloadApplicationComplete(int errorCode)626         public void onPayloadApplicationComplete(int errorCode) {
627             synchronized (mLock) {
628                 mErrorCode = errorCode;
629                 mCompleted = true;
630                 mLock.notifyAll();
631             }
632         }
633     }
634 
635     /**
636      * Cleanup files used by the previous update and free up space after the
637      * device has been booted successfully into the new build.
638      *
639      * <p>In particular, this function waits until delta files for snapshots for
640      * Virtual A/B update are merged to OS partitions, then delete these delta
641      * files.
642      *
643      * <p>This function is synchronous and may take a non-trivial amount of
644      * time. Callers should call this function in a background thread.
645      *
646      * <p>This function does not delete payload binaries downloaded for a
647      * non-streaming OTA update.
648      *
649      * @return One of the following:
650      * <ul>
651      * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li>
652      * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred.
653      * The device should be able to recover after a reboot. The function should
654      * be retried after the reboot.</li>
655      * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is
656      * encountered. Device is corrupted, and future updates must not be applied.
657      * The device cannot recover without flashing and factory resets.
658      * </ul>
659      */
660     @WorkerThread
661     @ErrorCode
cleanupAppliedPayload()662     public int cleanupAppliedPayload() {
663         CleanupAppliedPayloadCallback callback = new CleanupAppliedPayloadCallback();
664         try {
665             mUpdateEngine.cleanupSuccessfulUpdate(callback);
666             return callback.getResult();
667         } catch (RemoteException e) {
668             throw e.rethrowFromSystemServer();
669         }
670     }
671 
672     /**
673      * Run postinstall script for specified partition |partition|
674      *
675      * @param partition The partition to trigger postinstall runs
676      *
677      * @throws ServiceSpecificException error code of this exception would be one of
678      * https://cs.android.com/android/platform/superproject/main/+/main:system/update_engine/common/error_code.h
679      * @hide
680      */
681     @FlaggedApi(Flags.FLAG_UPDATE_ENGINE_API)
682     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
triggerPostinstall(@onNull String partition)683     public void triggerPostinstall(@NonNull String partition) {
684         try {
685             mUpdateEngine.triggerPostinstall(partition);
686         } catch (RemoteException e) {
687             throw e.rethrowFromSystemServer();
688         }
689     }
690 }
691