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