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