671 lines
25 KiB
Java
671 lines
25 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.os;
|
|
|
|
import android.annotation.IntDef;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.SystemApi;
|
|
import android.annotation.WorkerThread;
|
|
import android.content.res.AssetFileDescriptor;
|
|
import android.os.IUpdateEngine;
|
|
import android.os.IUpdateEngineCallback;
|
|
import android.os.RemoteException;
|
|
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
|
|
/**
|
|
* UpdateEngine handles calls to the update engine which takes care of A/B OTA
|
|
* updates. It wraps up the update engine Binder APIs and exposes them as
|
|
* SystemApis, which will be called by the system app responsible for OTAs.
|
|
* On a Google device, this will be GmsCore.
|
|
*
|
|
* The minimal flow is:
|
|
* <ol>
|
|
* <li>Create a new UpdateEngine instance.
|
|
* <li>Call {@link #bind}, optionally providing callbacks.
|
|
* <li>Call {@link #applyPayload}.
|
|
* </ol>
|
|
*
|
|
* In addition, methods are provided to {@link #cancel} or
|
|
* {@link #suspend}/{@link #resume} application of an update.
|
|
*
|
|
* The APIs defined in this class and UpdateEngineCallback class must be in
|
|
* sync with the ones in
|
|
* {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl}
|
|
* and
|
|
* {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}.
|
|
*
|
|
* {@hide}
|
|
*/
|
|
@SystemApi
|
|
public class UpdateEngine {
|
|
private static final String TAG = "UpdateEngine";
|
|
|
|
private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
|
|
|
|
/**
|
|
* Error codes from update engine upon finishing a call to
|
|
* {@link applyPayload}. Values will be passed via the callback function
|
|
* {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must
|
|
* agree with the ones in {@code system/update_engine/common/error_code.h}.
|
|
*/
|
|
public static final class ErrorCodeConstants {
|
|
/**
|
|
* Error code: a request finished successfully.
|
|
*/
|
|
public static final int SUCCESS = 0;
|
|
/**
|
|
* Error code: a request failed due to a generic error.
|
|
*/
|
|
public static final int ERROR = 1;
|
|
/**
|
|
* Error code: an update failed to apply due to filesystem copier
|
|
* error.
|
|
*/
|
|
public static final int FILESYSTEM_COPIER_ERROR = 4;
|
|
/**
|
|
* Error code: an update failed to apply due to an error in running
|
|
* post-install hooks.
|
|
*/
|
|
public static final int POST_INSTALL_RUNNER_ERROR = 5;
|
|
/**
|
|
* Error code: an update failed to apply due to a mismatching payload.
|
|
*
|
|
* <p>For example, the given payload uses a feature that's not
|
|
* supported by the current update engine.
|
|
*/
|
|
public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
|
|
/**
|
|
* Error code: an update failed to apply due to an error in opening
|
|
* devices.
|
|
*/
|
|
public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
|
|
/**
|
|
* Error code: an update failed to apply due to an error in opening
|
|
* kernel device.
|
|
*/
|
|
public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
|
|
/**
|
|
* Error code: an update failed to apply due to an error in fetching
|
|
* the payload.
|
|
*
|
|
* <p>For example, this could be a result of bad network connection
|
|
* when streaming an update.
|
|
*/
|
|
public static final int DOWNLOAD_TRANSFER_ERROR = 9;
|
|
/**
|
|
* Error code: an update failed to apply due to a mismatch in payload
|
|
* hash.
|
|
*
|
|
* <p>Update engine does validity checks for the given payload and its
|
|
* metadata.
|
|
*/
|
|
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
|
|
|
|
/**
|
|
* Error code: an update failed to apply due to a mismatch in payload
|
|
* size.
|
|
*/
|
|
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
|
|
|
|
/**
|
|
* Error code: an update failed to apply due to failing to verify
|
|
* payload signatures.
|
|
*/
|
|
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
|
|
|
|
/**
|
|
* Error code: an update failed to apply due to a downgrade in payload
|
|
* timestamp.
|
|
*
|
|
* <p>The timestamp of a build is encoded into the payload, which will
|
|
* be enforced during install to prevent downgrading a device.
|
|
*/
|
|
public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
|
|
|
|
/**
|
|
* Error code: an update has been applied successfully but the new slot
|
|
* hasn't been set to active.
|
|
*
|
|
* <p>It indicates a successful finish of calling {@link #applyPayload} with
|
|
* {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
|
|
*/
|
|
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
|
|
|
|
/**
|
|
* Error code: there is not enough space on the device to apply the update. User should
|
|
* be prompted to free up space and re-try the update.
|
|
*
|
|
* <p>See {@link UpdateEngine#allocateSpace}.
|
|
*/
|
|
public static final int NOT_ENOUGH_SPACE = 60;
|
|
|
|
/**
|
|
* Error code: the device is corrupted and no further updates may be applied.
|
|
*
|
|
* <p>See {@link UpdateEngine#cleanupAppliedPayload}.
|
|
*/
|
|
public static final int DEVICE_CORRUPTED = 61;
|
|
}
|
|
|
|
/** @hide */
|
|
@IntDef(value = {
|
|
ErrorCodeConstants.SUCCESS,
|
|
ErrorCodeConstants.ERROR,
|
|
ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
|
|
ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
|
|
ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
|
|
ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
|
|
ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
|
|
ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
|
|
ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
|
|
ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
|
|
ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
|
|
ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
|
|
ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
|
|
ErrorCodeConstants.NOT_ENOUGH_SPACE,
|
|
ErrorCodeConstants.DEVICE_CORRUPTED,
|
|
})
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
public @interface ErrorCode {}
|
|
|
|
/**
|
|
* Status codes for update engine. Values must agree with the ones in
|
|
* {@code system/update_engine/client_library/include/update_engine/update_status.h}.
|
|
*/
|
|
public static final class UpdateStatusConstants {
|
|
/**
|
|
* Update status code: update engine is in idle state.
|
|
*/
|
|
public static final int IDLE = 0;
|
|
|
|
/**
|
|
* Update status code: update engine is checking for update.
|
|
*/
|
|
public static final int CHECKING_FOR_UPDATE = 1;
|
|
|
|
/**
|
|
* Update status code: an update is available.
|
|
*/
|
|
public static final int UPDATE_AVAILABLE = 2;
|
|
|
|
/**
|
|
* Update status code: update engine is downloading an update.
|
|
*/
|
|
public static final int DOWNLOADING = 3;
|
|
|
|
/**
|
|
* Update status code: update engine is verifying an update.
|
|
*/
|
|
public static final int VERIFYING = 4;
|
|
|
|
/**
|
|
* Update status code: update engine is finalizing an update.
|
|
*/
|
|
public static final int FINALIZING = 5;
|
|
|
|
/**
|
|
* Update status code: an update has been applied and is pending for
|
|
* reboot.
|
|
*/
|
|
public static final int UPDATED_NEED_REBOOT = 6;
|
|
|
|
/**
|
|
* Update status code: update engine is reporting an error event.
|
|
*/
|
|
public static final int REPORTING_ERROR_EVENT = 7;
|
|
|
|
/**
|
|
* Update status code: update engine is attempting to rollback an
|
|
* update.
|
|
*/
|
|
public static final int ATTEMPTING_ROLLBACK = 8;
|
|
|
|
/**
|
|
* Update status code: update engine is in disabled state.
|
|
*/
|
|
public static final int DISABLED = 9;
|
|
}
|
|
|
|
private final IUpdateEngine mUpdateEngine;
|
|
private IUpdateEngineCallback mUpdateEngineCallback = null;
|
|
private final Object mUpdateEngineCallbackLock = new Object();
|
|
|
|
/**
|
|
* Creates a new instance.
|
|
*/
|
|
public UpdateEngine() {
|
|
mUpdateEngine = IUpdateEngine.Stub.asInterface(
|
|
ServiceManager.getService(UPDATE_ENGINE_SERVICE));
|
|
if (mUpdateEngine == null) {
|
|
throw new IllegalStateException("Failed to find update_engine");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prepares this instance for use. The callback will be notified on any
|
|
* status change, and when the update completes. A handler can be supplied
|
|
* to control which thread runs the callback, or null.
|
|
*/
|
|
public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
|
|
synchronized (mUpdateEngineCallbackLock) {
|
|
mUpdateEngineCallback = new IUpdateEngineCallback.Stub() {
|
|
@Override
|
|
public void onStatusUpdate(final int status, final float percent) {
|
|
if (handler != null) {
|
|
handler.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
callback.onStatusUpdate(status, percent);
|
|
}
|
|
});
|
|
} else {
|
|
callback.onStatusUpdate(status, percent);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPayloadApplicationComplete(final int errorCode) {
|
|
if (handler != null) {
|
|
handler.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
callback.onPayloadApplicationComplete(errorCode);
|
|
}
|
|
});
|
|
} else {
|
|
callback.onPayloadApplicationComplete(errorCode);
|
|
}
|
|
}
|
|
};
|
|
|
|
try {
|
|
return mUpdateEngine.bind(mUpdateEngineCallback);
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Equivalent to {@code bind(callback, null)}.
|
|
*/
|
|
public boolean bind(final UpdateEngineCallback callback) {
|
|
return bind(callback, null);
|
|
}
|
|
|
|
/**
|
|
* Applies the payload found at the given {@code url}. For non-streaming
|
|
* updates, the URL can be a local file using the {@code file://} scheme.
|
|
*
|
|
* <p>The {@code offset} and {@code size} parameters specify the location
|
|
* of the payload within the file represented by the URL. This is useful
|
|
* if the downloadable package at the URL contains more than just the
|
|
* update_engine payload (such as extra metadata). This is true for
|
|
* Google's OTA system, where the URL points to a zip file in which the
|
|
* payload is stored uncompressed within the zip file alongside other
|
|
* data.
|
|
*
|
|
* <p>The {@code headerKeyValuePairs} parameter is used to pass metadata
|
|
* to update_engine. In Google's implementation, this is stored as
|
|
* {@code payload_properties.txt} in the zip file. It's generated by the
|
|
* script {@code system/update_engine/scripts/brillo_update_payload}.
|
|
* The complete list of keys and their documentation is in
|
|
* {@code system/update_engine/common/constants.cc}, but an example
|
|
* might be:
|
|
* <pre>
|
|
* String[] pairs = {
|
|
* "FILE_HASH=lURPCIkIAjtMOyB/EjQcl8zDzqtD6Ta3tJef6G/+z2k=",
|
|
* "FILE_SIZE=871903868",
|
|
* "METADATA_HASH=tBvj43QOB0Jn++JojcpVdbRLz0qdAuL+uTkSy7hokaw=",
|
|
* "METADATA_SIZE=70604"
|
|
* };
|
|
* </pre>
|
|
*
|
|
* <p>The callback functions registered via {@code #bind} will be called
|
|
* during and at the end of the payload application.
|
|
*
|
|
* <p>By default the newly updated slot will be set active upon
|
|
* successfully finishing an update. Device will attempt to boot into the
|
|
* new slot on next reboot. This behavior can be customized by specifying
|
|
* {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which
|
|
* allows the caller to later determine a good time to boot into the new
|
|
* slot. Calling {@code applyPayload} again with the same payload but with
|
|
* {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new
|
|
* slot active, after verifying its integrity.
|
|
*/
|
|
public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
|
|
try {
|
|
mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Applies the payload passed as AssetFileDescriptor {@code assetFd}
|
|
* instead of using the {@code file://} scheme.
|
|
*
|
|
* <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and
|
|
* {@code headerKeyValuePairs} parameters.
|
|
*/
|
|
public void applyPayload(@NonNull AssetFileDescriptor assetFd,
|
|
@NonNull String[] headerKeyValuePairs) {
|
|
try {
|
|
mUpdateEngine.applyPayloadFd(assetFd.getParcelFileDescriptor(),
|
|
assetFd.getStartOffset(), assetFd.getLength(), headerKeyValuePairs);
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Permanently cancels an in-progress update.
|
|
*
|
|
* <p>See {@link #resetStatus} to undo a finshed update (only available
|
|
* before the updated system has been rebooted).
|
|
*
|
|
* <p>See {@link #suspend} for a way to temporarily stop an in-progress
|
|
* update with the ability to resume it later.
|
|
*/
|
|
public void cancel() {
|
|
try {
|
|
mUpdateEngine.cancel();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Suspends an in-progress update. This can be undone by calling
|
|
* {@link #resume}.
|
|
*/
|
|
public void suspend() {
|
|
try {
|
|
mUpdateEngine.suspend();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resumes a suspended update.
|
|
*/
|
|
public void resume() {
|
|
try {
|
|
mUpdateEngine.resume();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resets the bootable flag on the non-current partition and all internal
|
|
* update_engine state. Note this call will clear the entire update
|
|
* progress. So a subsequent {@link #applyPayload} will apply the update
|
|
* from scratch.
|
|
*
|
|
* <p>After this call completes, update_engine will no longer report
|
|
* {@code UPDATED_NEED_REBOOT}, so your callback can remove any outstanding
|
|
* notification that rebooting into the new system is possible.
|
|
*/
|
|
public void resetStatus() {
|
|
try {
|
|
mUpdateEngine.resetStatus();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the A/B slot switch for the next boot after applying an ota update. If
|
|
* {@link #applyPayload} hasn't switched the slot, the updater APP can call
|
|
* this API to switch the slot and apply the update on next boot.
|
|
*
|
|
* @param payloadMetadataFilename the location of the metadata without the
|
|
* {@code file://} prefix.
|
|
*/
|
|
public void setShouldSwitchSlotOnReboot(@NonNull String payloadMetadataFilename) {
|
|
try {
|
|
mUpdateEngine.setShouldSwitchSlotOnReboot(payloadMetadataFilename);
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resets the boot slot to the source/current slot, without cancelling the
|
|
* update progress. This can be called after the update is installed, and to
|
|
* prevent the device from accidentally taking the update when it reboots.
|
|
*
|
|
* This is useful when users don't want to take the update immediately; or
|
|
* the updater determines some condition hasn't met, e.g. insufficient space
|
|
* for boot.
|
|
*/
|
|
public void resetShouldSwitchSlotOnReboot() {
|
|
try {
|
|
mUpdateEngine.resetShouldSwitchSlotOnReboot();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unbinds the last bound callback function.
|
|
*/
|
|
public boolean unbind() {
|
|
synchronized (mUpdateEngineCallbackLock) {
|
|
if (mUpdateEngineCallback == null) {
|
|
return true;
|
|
}
|
|
try {
|
|
boolean result = mUpdateEngine.unbind(mUpdateEngineCallback);
|
|
mUpdateEngineCallback = null;
|
|
return result;
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verifies that a payload associated with the given payload metadata
|
|
* {@code payloadMetadataFilename} can be safely applied to ths device.
|
|
* Returns {@code true} if the update can successfully be applied and
|
|
* returns {@code false} otherwise.
|
|
*
|
|
* @param payloadMetadataFilename the location of the metadata without the
|
|
* {@code file://} prefix.
|
|
*/
|
|
public boolean verifyPayloadMetadata(String payloadMetadataFilename) {
|
|
try {
|
|
return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename);
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return value of {@link #allocateSpace.}
|
|
*/
|
|
public static final class AllocateSpaceResult {
|
|
private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS;
|
|
private long mFreeSpaceRequired = 0;
|
|
private AllocateSpaceResult() {}
|
|
/**
|
|
* Error code.
|
|
*
|
|
* @return The following error codes:
|
|
* <ul>
|
|
* <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated
|
|
* successfully.</li>
|
|
* <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient
|
|
* space.</li>
|
|
* <li>Other {@link ErrorCodeConstants} for other errors.</li>
|
|
* </ul>
|
|
*/
|
|
@ErrorCode
|
|
public int getErrorCode() {
|
|
return mErrorCode;
|
|
}
|
|
|
|
/**
|
|
* Estimated total space that needs to be available on the userdata partition to apply the
|
|
* payload (in bytes).
|
|
*
|
|
* <p>
|
|
* Note that in practice, more space needs to be made available before applying the payload
|
|
* to keep the device working.
|
|
*
|
|
* @return The following values:
|
|
* <ul>
|
|
* <li>zero if {@link #getErrorCode} returns {@link ErrorCodeConstants#SUCCESS}</li>
|
|
* <li>non-zero if {@link #getErrorCode} returns
|
|
* {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}.
|
|
* Value is the estimated total space required on userdata partition.</li>
|
|
* </ul>
|
|
* @throws IllegalStateException if {@link #getErrorCode} is not one of the above.
|
|
*
|
|
*/
|
|
public long getFreeSpaceRequired() {
|
|
if (mErrorCode == ErrorCodeConstants.SUCCESS) {
|
|
return 0;
|
|
}
|
|
if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) {
|
|
return mFreeSpaceRequired;
|
|
}
|
|
throw new IllegalStateException(String.format(
|
|
"getFreeSpaceRequired() is not available when error code is %d", mErrorCode));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize partitions for a payload associated with the given payload
|
|
* metadata {@code payloadMetadataFilename} by preallocating required space.
|
|
*
|
|
* <p>This function should be called after payload has been verified after
|
|
* {@link #verifyPayloadMetadata}. This function does not verify whether
|
|
* the given payload is applicable or not.
|
|
*
|
|
* <p>Implementation of {@code allocateSpace} uses
|
|
* {@code headerKeyValuePairs} to determine whether space has been allocated
|
|
* for a different or same payload previously. If space has been allocated
|
|
* for a different payload before, space will be reallocated for the given
|
|
* payload. If space has been allocated for the same payload, no actions to
|
|
* storage devices are taken.
|
|
*
|
|
* <p>This function is synchronous and may take a non-trivial amount of
|
|
* time. Callers should call this function in a background thread.
|
|
*
|
|
* @param payloadMetadataFilename See {@link #verifyPayloadMetadata}.
|
|
* @param headerKeyValuePairs See {@link #applyPayload}.
|
|
* @return See {@link AllocateSpaceResult#getErrorCode} and
|
|
* {@link AllocateSpaceResult#getFreeSpaceRequired}.
|
|
*/
|
|
@WorkerThread
|
|
@NonNull
|
|
public AllocateSpaceResult allocateSpace(
|
|
@NonNull String payloadMetadataFilename,
|
|
@NonNull String[] headerKeyValuePairs) {
|
|
AllocateSpaceResult result = new AllocateSpaceResult();
|
|
try {
|
|
result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload(
|
|
payloadMetadataFilename,
|
|
headerKeyValuePairs);
|
|
result.mErrorCode = result.mFreeSpaceRequired == 0
|
|
? ErrorCodeConstants.SUCCESS
|
|
: ErrorCodeConstants.NOT_ENOUGH_SPACE;
|
|
return result;
|
|
} catch (ServiceSpecificException e) {
|
|
result.mErrorCode = e.errorCode;
|
|
result.mFreeSpaceRequired = 0;
|
|
return result;
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
private static class CleanupAppliedPayloadCallback extends IUpdateEngineCallback.Stub {
|
|
private int mErrorCode = ErrorCodeConstants.ERROR;
|
|
private boolean mCompleted = false;
|
|
private Object mLock = new Object();
|
|
private int getResult() {
|
|
synchronized (mLock) {
|
|
while (!mCompleted) {
|
|
try {
|
|
mLock.wait();
|
|
} catch (InterruptedException ex) {
|
|
// do nothing, just wait again.
|
|
}
|
|
}
|
|
return mErrorCode;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onStatusUpdate(int status, float percent) {
|
|
}
|
|
|
|
@Override
|
|
public void onPayloadApplicationComplete(int errorCode) {
|
|
synchronized (mLock) {
|
|
mErrorCode = errorCode;
|
|
mCompleted = true;
|
|
mLock.notifyAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cleanup files used by the previous update and free up space after the
|
|
* device has been booted successfully into the new build.
|
|
*
|
|
* <p>In particular, this function waits until delta files for snapshots for
|
|
* Virtual A/B update are merged to OS partitions, then delete these delta
|
|
* files.
|
|
*
|
|
* <p>This function is synchronous and may take a non-trivial amount of
|
|
* time. Callers should call this function in a background thread.
|
|
*
|
|
* <p>This function does not delete payload binaries downloaded for a
|
|
* non-streaming OTA update.
|
|
*
|
|
* @return One of the following:
|
|
* <ul>
|
|
* <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li>
|
|
* <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred.
|
|
* The device should be able to recover after a reboot. The function should
|
|
* be retried after the reboot.</li>
|
|
* <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is
|
|
* encountered. Device is corrupted, and future updates must not be applied.
|
|
* The device cannot recover without flashing and factory resets.
|
|
* </ul>
|
|
*/
|
|
@WorkerThread
|
|
@ErrorCode
|
|
public int cleanupAppliedPayload() {
|
|
CleanupAppliedPayloadCallback callback = new CleanupAppliedPayloadCallback();
|
|
try {
|
|
mUpdateEngine.cleanupSuccessfulUpdate(callback);
|
|
return callback.getResult();
|
|
} catch (RemoteException e) {
|
|
throw e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
}
|