1 /* 2 * Copyright (C) 2019 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.image; 18 19 import android.annotation.RequiresPermission; 20 import android.annotation.SystemService; 21 import android.content.Context; 22 import android.gsi.AvbPublicKey; 23 import android.gsi.GsiProgress; 24 import android.os.ParcelFileDescriptor; 25 import android.os.RemoteException; 26 27 /** 28 * The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the 29 * installation, the device can reboot into this image with a new created /data. This image will 30 * last until the next reboot and then the device will go back to the original image. However the 31 * installed image and the new created /data are not deleted but disabled. Thus the application can 32 * either re-enable the installed image by calling {@link #toggle} or use the {@link #remove} to 33 * delete it completely. In other words, there are three device states: no installation, installed 34 * and running. The procedure to install a DynamicSystem starts with a {@link #startInstallation}, 35 * followed by a series of {@link #write} and ends with a {@link commit}. Once the installation is 36 * complete, the device state changes from no installation to the installed state and a followed 37 * reboot will change its state to running. Note one instance of DynamicSystem can exist on a given 38 * device thus the {@link #startInstallation} will fail if the device is currently running a 39 * DynamicSystem. 40 * 41 * @hide 42 */ 43 @SystemService(Context.DYNAMIC_SYSTEM_SERVICE) 44 public class DynamicSystemManager { 45 private static final String TAG = "DynamicSystemManager"; 46 47 private final IDynamicSystemService mService; 48 49 /** {@hide} */ DynamicSystemManager(IDynamicSystemService service)50 public DynamicSystemManager(IDynamicSystemService service) { 51 mService = service; 52 } 53 54 /** The DynamicSystemManager.Session represents a started session for the installation. */ 55 public class Session { Session()56 private Session() {} 57 58 /** 59 * Set the file descriptor that points to a ashmem which will be used 60 * to fetch data during the submitFromAshmem. 61 * 62 * @param ashmem fd that points to a ashmem 63 * @param size size of the ashmem file 64 */ 65 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) setAshmem(ParcelFileDescriptor ashmem, long size)66 public boolean setAshmem(ParcelFileDescriptor ashmem, long size) { 67 try { 68 return mService.setAshmem(ashmem, size); 69 } catch (RemoteException e) { 70 throw new RuntimeException(e.toString()); 71 } 72 } 73 74 /** 75 * Submit bytes to the DSU partition from the ashmem previously set with 76 * setAshmem. 77 * 78 * @param size Number of bytes 79 * @return true on success, false otherwise. 80 */ 81 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) submitFromAshmem(int size)82 public boolean submitFromAshmem(int size) { 83 try { 84 return mService.submitFromAshmem(size); 85 } catch (RemoteException e) { 86 throw new RuntimeException(e.toString()); 87 } 88 } 89 90 /** 91 * Retrieve AVB public key from installing partition. 92 * 93 * @param dst Output the AVB public key. 94 * @return true on success, false if partition doesn't have a 95 * valid VBMeta block to retrieve the AVB key from. 96 */ 97 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) getAvbPublicKey(AvbPublicKey dst)98 public boolean getAvbPublicKey(AvbPublicKey dst) { 99 try { 100 return mService.getAvbPublicKey(dst); 101 } catch (RemoteException e) { 102 throw new RuntimeException(e.toString()); 103 } 104 } 105 106 /** 107 * Finish write and make device to boot into the it after reboot. 108 * 109 * @return {@code true} if the call succeeds. {@code false} if there is any native runtime 110 * error. 111 */ 112 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) commit()113 public boolean commit() { 114 try { 115 return mService.setEnable(true, true); 116 } catch (RemoteException e) { 117 throw new RuntimeException(e.toString()); 118 } 119 } 120 } 121 /** 122 * Start DynamicSystem installation. 123 * 124 * @return true if the call succeeds 125 */ 126 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) startInstallation(String dsuSlot)127 public boolean startInstallation(String dsuSlot) { 128 try { 129 return mService.startInstallation(dsuSlot); 130 } catch (RemoteException e) { 131 throw new RuntimeException(e.toString()); 132 } 133 } 134 /** 135 * Start DynamicSystem installation. This call may take an unbounded amount of time. The caller 136 * may use another thread to call the getStartProgress() to get the progress. 137 * 138 * @param name The DSU partition name 139 * @param size Size of the DSU image in bytes 140 * @param readOnly True if the partition is read only, e.g. system. 141 * @return {@code true} if the call succeeds. {@code false} either the device does not contain 142 * enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be 143 * true. 144 */ 145 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) createPartition(String name, long size, boolean readOnly)146 public Session createPartition(String name, long size, boolean readOnly) { 147 try { 148 if (mService.createPartition(name, size, readOnly)) { 149 return new Session(); 150 } else { 151 return null; 152 } 153 } catch (RemoteException e) { 154 throw new RuntimeException(e.toString()); 155 } 156 } 157 /** 158 * Complete the current partition installation. 159 * 160 * @return true if the partition installation completes without error. 161 */ 162 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) closePartition()163 public boolean closePartition() { 164 try { 165 return mService.closePartition(); 166 } catch (RemoteException e) { 167 throw new RuntimeException(e.toString()); 168 } 169 } 170 /** 171 * Finish a previously started installation. Installations without a cooresponding 172 * finishInstallation() will be cleaned up during device boot. 173 */ 174 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) finishInstallation()175 public boolean finishInstallation() { 176 try { 177 return mService.finishInstallation(); 178 } catch (RemoteException e) { 179 throw new RuntimeException(e.toString()); 180 } 181 } 182 /** 183 * Query the progress of the current installation operation. This can be called while the 184 * installation is in progress. 185 * 186 * @return GsiProgress GsiProgress { int status; long bytes_processed; long total_bytes; } The 187 * status field can be IGsiService.STATUS_NO_OPERATION, IGsiService.STATUS_WORKING or 188 * IGsiService.STATUS_COMPLETE. 189 */ 190 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) getInstallationProgress()191 public GsiProgress getInstallationProgress() { 192 try { 193 return mService.getInstallationProgress(); 194 } catch (RemoteException e) { 195 throw new RuntimeException(e.toString()); 196 } 197 } 198 199 /** 200 * Abort the installation process. Note this method must be called in a thread other than the 201 * one calling the startInstallation method as the startInstallation method will not return 202 * until it is finished. 203 * 204 * @return {@code true} if the call succeeds. {@code false} if there is no installation 205 * currently. 206 */ 207 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) abort()208 public boolean abort() { 209 try { 210 return mService.abort(); 211 } catch (RemoteException e) { 212 throw new RuntimeException(e.toString()); 213 } 214 } 215 216 /** @return {@code true} if the device is running a dynamic system */ 217 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) isInUse()218 public boolean isInUse() { 219 try { 220 return mService.isInUse(); 221 } catch (RemoteException e) { 222 throw new RuntimeException(e.toString()); 223 } 224 } 225 226 /** @return {@code true} if the device has a dynamic system installed */ 227 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) isInstalled()228 public boolean isInstalled() { 229 try { 230 return mService.isInstalled(); 231 } catch (RemoteException e) { 232 throw new RuntimeException(e.toString()); 233 } 234 } 235 236 /** @return {@code true} if the device has a dynamic system enabled */ 237 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) isEnabled()238 public boolean isEnabled() { 239 try { 240 return mService.isEnabled(); 241 } catch (RemoteException e) { 242 throw new RuntimeException(e.toString()); 243 } 244 } 245 246 /** 247 * Remove DynamicSystem installation if present 248 * 249 * @return {@code true} if the call succeeds. {@code false} if there is no installed image. 250 */ 251 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) remove()252 public boolean remove() { 253 try { 254 return mService.remove(); 255 } catch (RemoteException e) { 256 throw new RuntimeException(e.toString()); 257 } 258 } 259 260 /** 261 * Enable or disable DynamicSystem. 262 * @return {@code true} if the call succeeds. {@code false} if there is no installed image. 263 */ 264 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) setEnable(boolean enable, boolean oneShot)265 public boolean setEnable(boolean enable, boolean oneShot) { 266 try { 267 return mService.setEnable(enable, oneShot); 268 } catch (RemoteException e) { 269 throw new RuntimeException(e.toString()); 270 } 271 } 272 273 /** 274 * Returns the suggested scratch partition size for overlayFS. 275 */ 276 @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) suggestScratchSize()277 public long suggestScratchSize() { 278 try { 279 return mService.suggestScratchSize(); 280 } catch (RemoteException e) { 281 throw new RuntimeException(e.toString()); 282 } 283 } 284 } 285