1 /* 2 * Copyright (C) 2024 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.IntDef; 20 21 /** 22 * UpdateEngineStable handles calls to the update engine stalbe which takes care of A/B OTA updates. 23 * This interface has lesser functionalities than UpdateEngine and doesn't allow cancel. 24 * 25 * <p>The minimal flow is: 26 * 27 * <ol> 28 * <li>Create a new UpdateEngineStable instance. 29 * <li>Call {@link #bind}, provide callback function. 30 * <li>Call {@link #applyPayloadFd}. 31 * </ol> 32 * 33 * The APIs defined in this class and UpdateEngineStableCallback class must be in sync with the ones 34 * in {@code system/update_engine/stable/android/os/IUpdateEngineStable.aidl} and {@code 35 * ssystem/update_engine/stable/android/os/IUpdateEngineStableCallback.aidl}. 36 * 37 * @hide 38 */ 39 public class UpdateEngineStable { 40 private static final String TAG = "UpdateEngineStable"; 41 42 private static final String UPDATE_ENGINE_STABLE_SERVICE = 43 "android.os.UpdateEngineStableService"; 44 45 /** 46 * Error codes from update engine upon finishing a call to {@link applyPayloadFd}. Values will 47 * be passed via the callback function {@link 48 * UpdateEngineStableCallback#onPayloadApplicationComplete}. Values must agree with the ones in 49 * {@code system/update_engine/common/error_code.h}. 50 */ 51 /** @hide */ 52 @IntDef( 53 value = { 54 UpdateEngine.ErrorCodeConstants.SUCCESS, 55 UpdateEngine.ErrorCodeConstants.ERROR, 56 UpdateEngine.ErrorCodeConstants.FILESYSTEM_COPIER_ERROR, 57 UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR, 58 UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR, 59 UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR, 60 UpdateEngine.ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR, 61 UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR, 62 UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR, 63 UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR, 64 UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR, 65 UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR, 66 UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE, 67 UpdateEngine.ErrorCodeConstants.NOT_ENOUGH_SPACE, 68 UpdateEngine.ErrorCodeConstants.DEVICE_CORRUPTED, 69 }) 70 public @interface ErrorCode {} 71 72 private final IUpdateEngineStable mUpdateEngineStable; 73 private IUpdateEngineStableCallback mUpdateEngineStableCallback = null; 74 private final Object mUpdateEngineStableCallbackLock = new Object(); 75 76 /** 77 * Creates a new instance. 78 * 79 * @hide 80 */ UpdateEngineStable()81 public UpdateEngineStable() { 82 mUpdateEngineStable = 83 IUpdateEngineStable.Stub.asInterface( 84 ServiceManager.getService(UPDATE_ENGINE_STABLE_SERVICE)); 85 if (mUpdateEngineStable == null) { 86 throw new IllegalStateException("Failed to find " + UPDATE_ENGINE_STABLE_SERVICE); 87 } 88 } 89 90 /** 91 * Prepares this instance for use. The callback will be notified on any status change, and when 92 * the update completes. A handler can be supplied to control which thread runs the callback, or 93 * null. 94 * 95 * @hide 96 */ bind(final UpdateEngineStableCallback callback, final Handler handler)97 public boolean bind(final UpdateEngineStableCallback callback, final Handler handler) { 98 synchronized (mUpdateEngineStableCallbackLock) { 99 mUpdateEngineStableCallback = 100 new IUpdateEngineStableCallback.Stub() { 101 @Override 102 public void onStatusUpdate(final int status, final float percent) { 103 if (handler != null) { 104 handler.post( 105 new Runnable() { 106 @Override 107 public void run() { 108 callback.onStatusUpdate(status, percent); 109 } 110 }); 111 } else { 112 callback.onStatusUpdate(status, percent); 113 } 114 } 115 116 @Override 117 public void onPayloadApplicationComplete(final int errorCode) { 118 if (handler != null) { 119 handler.post( 120 new Runnable() { 121 @Override 122 public void run() { 123 callback.onPayloadApplicationComplete(errorCode); 124 } 125 }); 126 } else { 127 callback.onPayloadApplicationComplete(errorCode); 128 } 129 } 130 131 @Override 132 public int getInterfaceVersion() { 133 return super.VERSION; 134 } 135 136 @Override 137 public String getInterfaceHash() { 138 return super.HASH; 139 } 140 }; 141 142 try { 143 return mUpdateEngineStable.bind(mUpdateEngineStableCallback); 144 } catch (RemoteException e) { 145 throw e.rethrowFromSystemServer(); 146 } 147 } 148 } 149 150 /** 151 * Equivalent to {@code bind(callback, null)}. 152 * 153 * @hide 154 */ bind(final UpdateEngineStableCallback callback)155 public boolean bind(final UpdateEngineStableCallback callback) { 156 return bind(callback, null); 157 } 158 159 /** 160 * Applies payload from given ParcelFileDescriptor. Usage is same as UpdateEngine#applyPayload 161 * 162 * @hide 163 */ applyPayloadFd( ParcelFileDescriptor fd, long offset, long size, String[] headerKeyValuePairs)164 public void applyPayloadFd( 165 ParcelFileDescriptor fd, long offset, long size, String[] headerKeyValuePairs) { 166 try { 167 mUpdateEngineStable.applyPayloadFd(fd, offset, size, headerKeyValuePairs); 168 } catch (RemoteException e) { 169 throw e.rethrowFromSystemServer(); 170 } 171 } 172 173 /** 174 * Unbinds the last bound callback function. 175 * 176 * @hide 177 */ unbind()178 public boolean unbind() { 179 synchronized (mUpdateEngineStableCallbackLock) { 180 if (mUpdateEngineStableCallback == null) { 181 return true; 182 } 183 try { 184 boolean result = mUpdateEngineStable.unbind(mUpdateEngineStableCallback); 185 mUpdateEngineStableCallback = null; 186 return result; 187 } catch (RemoteException e) { 188 throw e.rethrowFromSystemServer(); 189 } 190 } 191 } 192 } 193