1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
/*
* Copyright (C) 2019 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.image;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.gsi.GsiProgress;
import android.os.RemoteException;
/**
* The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the
* installation, the device can reboot into this image with a new created /data. This image will
* last until the next reboot and then the device will go back to the original image. However the
* installed image and the new created /data are not deleted but disabled. Thus the application can
* either re-enable the installed image by calling {@link #toggle} or use the {@link #remove} to
* delete it completely. In other words, there are three device states: no installation, installed
* and running. The procedure to install a DynamicSystem starts with a {@link #startInstallation},
* followed by a series of {@link #write} and ends with a {@link commit}. Once the installation is
* complete, the device state changes from no installation to the installed state and a followed
* reboot will change its state to running. Note one instance of DynamicSystem can exist on a given
* device thus the {@link #startInstallation} will fail if the device is currently running a
* DynamicSystem.
*
* @hide
*/
@SystemService(Context.DYNAMIC_SYSTEM_SERVICE)
public class DynamicSystemManager {
private static final String TAG = "DynamicSystemManager";
private final IDynamicSystemService mService;
/** {@hide} */
public DynamicSystemManager(IDynamicSystemService service) {
mService = service;
}
/** The DynamicSystemManager.Session represents a started session for the installation. */
public class Session {
private Session() {}
/**
* Write a chunk of the DynamicSystem system image
*
* @return {@code true} if the call succeeds. {@code false} if there is any native runtime
* error.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean write(byte[] buf) {
try {
return mService.write(buf);
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Finish write and make device to boot into the it after reboot.
*
* @return {@code true} if the call succeeds. {@code false} if there is any native runtime
* error.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean commit() {
try {
return mService.commit();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
}
/**
* Start DynamicSystem installation. This call may take an unbounded amount of time. The caller
* may use another thread to call the getStartProgress() to get the progress.
*
* @param systemSize system size in bytes
* @param userdataSize userdata size in bytes
* @return {@code true} if the call succeeds. {@code false} either the device does not contain
* enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be
* true.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public Session startInstallation(long systemSize, long userdataSize) {
try {
if (mService.startInstallation(systemSize, userdataSize)) {
return new Session();
} else {
return null;
}
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Query the progress of the current installation operation. This can be called while the
* installation is in progress.
*
* @return GsiProgress GsiProgress { int status; long bytes_processed; long total_bytes; } The
* status field can be IGsiService.STATUS_NO_OPERATION, IGsiService.STATUS_WORKING or
* IGsiService.STATUS_COMPLETE.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public GsiProgress getInstallationProgress() {
try {
return mService.getInstallationProgress();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Abort the installation process. Note this method must be called in a thread other than the
* one calling the startInstallation method as the startInstallation method will not return
* until it is finished.
*
* @return {@code true} if the call succeeds. {@code false} if there is no installation
* currently.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean abort() {
try {
return mService.abort();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/** @return {@code true} if the device is running a dynamic system */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean isInUse() {
try {
return mService.isInUse();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/** @return {@code true} if the device has a dynamic system installed */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean isInstalled() {
try {
return mService.isInstalled();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/** @return {@code true} if the device has a dynamic system enabled */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean isEnabled() {
try {
return mService.isEnabled();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Remove DynamicSystem installation if present
*
* @return {@code true} if the call succeeds. {@code false} if there is no installed image.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean remove() {
try {
return mService.remove();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Enable or disable DynamicSystem.
* @return {@code true} if the call succeeds. {@code false} if there is no installed image.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean setEnable(boolean enable) {
try {
return mService.setEnable(enable);
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
}
|