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
|
/*
* 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;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.gsi.GsiProgress;
/**
* The DynamicAndroidManager offers a mechanism to use a new Android 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 DynamicAndroid 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 dynamic android can exist on a
* given device thus the {@link #startInstallation} will fail if the device is currently running a
* DynamicAndroid.
*
* @hide
*/
@SystemService(Context.DYNAMIC_ANDROID_SERVICE)
public class DynamicAndroidManager {
private static final String TAG = "DynamicAndroidManager";
private final IDynamicAndroidService mService;
/** {@hide} */
public DynamicAndroidManager(IDynamicAndroidService service) {
mService = service;
}
/** The DynamicAndroidManager.Session represents a started session for the installation. */
public class Session {
private Session() {}
/**
* Write a chunk of the DynamicAndroid system image
*
* @return {@code true} if the call succeeds. {@code false} if there is any native runtime
* error.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
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_ANDROID)
public boolean commit() {
try {
return mService.commit();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
}
/**
* Start DynamicAndroid 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 DynamicAndroid is currently in use where the {@link #isInUse} would be
* true.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
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_ANDROID)
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_ANDROID)
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 android */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
public boolean isInUse() {
try {
return mService.isInUse();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/** @return {@code true} if the device has a dynamic android installed */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
public boolean isInstalled() {
try {
return mService.isInstalled();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Remove DynamicAndroid installation if present
*
* @return {@code true} if the call succeeds. {@code false} if there is no installed image.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
public boolean remove() {
try {
return mService.remove();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
/**
* Enable DynamicAndroid when it's not enabled, otherwise, disable it.
*
* @return {@code true} if the call succeeds. {@code false} if there is no installed image.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
public boolean toggle() {
try {
return mService.toggle();
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
}
}
|