• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.system.virtualmachine;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresFeature;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SystemApi;
27 import android.annotation.WorkerThread;
28 import android.content.Context;
29 import android.content.pm.PackageManager;
30 import android.sysprop.HypervisorProperties;
31 import android.util.ArrayMap;
32 
33 import com.android.internal.annotations.GuardedBy;
34 
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.lang.ref.WeakReference;
38 import java.util.Map;
39 
40 /**
41  * Manages {@linkplain VirtualMachine virtual machine} instances created by an app. Each instance is
42  * created from a {@linkplain VirtualMachineConfig configuration} that defines the shape of the VM
43  * (RAM, CPUs), the code to execute within it, etc.
44  *
45  * <p>Each virtual machine instance is named; the configuration and related state of each is
46  * persisted in the app's private data directory and an instance can be retrieved given the name.
47  * The name must be a valid directory name and must not contain '/'.
48  *
49  * <p>The app can then start, stop and otherwise interact with the VM.
50  *
51  * <p>An instance of {@link VirtualMachineManager} can be obtained by calling {@link
52  * Context#getSystemService(Class)}.
53  *
54  * @hide
55  */
56 @SystemApi
57 @RequiresFeature(PackageManager.FEATURE_VIRTUALIZATION_FRAMEWORK)
58 public class VirtualMachineManager {
59     /**
60      * A lock used to synchronize the creation of virtual machines. It protects {@link #mVmsByName},
61      * but is also held throughout VM creation / retrieval / deletion, to prevent these actions
62      * racing with each other.
63      */
64     private static final Object sCreateLock = new Object();
65 
66     @NonNull private final Context mContext;
67 
68     /** @hide */
VirtualMachineManager(@onNull Context context)69     public VirtualMachineManager(@NonNull Context context) {
70         mContext = requireNonNull(context);
71     }
72 
73     @GuardedBy("sCreateLock")
74     private final Map<String, WeakReference<VirtualMachine>> mVmsByName = new ArrayMap<>();
75 
76     /**
77      * Capabilities of the virtual machine implementation.
78      *
79      * @hide
80      */
81     @Retention(RetentionPolicy.SOURCE)
82     @IntDef(prefix = "CAPABILITY_", flag = true, value = {
83             CAPABILITY_PROTECTED_VM,
84             CAPABILITY_NON_PROTECTED_VM
85     })
86     public @interface Capability {}
87 
88     /* The implementation supports creating protected VMs, whose memory is inaccessible to the
89      * host OS.
90      */
91     public static final int CAPABILITY_PROTECTED_VM = 1;
92 
93     /* The implementation supports creating non-protected VMs, whose memory is accessible to the
94      * host OS.
95      */
96     public static final int CAPABILITY_NON_PROTECTED_VM = 2;
97 
98     /**
99      * Returns a set of flags indicating what this implementation of virtualization is capable of.
100      *
101      * @see #CAPABILITY_PROTECTED_VM
102      * @see #CAPABILITY_NON_PROTECTED_VM
103      * @hide
104      */
105     @SystemApi
106     @Capability
getCapabilities()107     public int getCapabilities() {
108         @Capability int result = 0;
109         if (HypervisorProperties.hypervisor_protected_vm_supported().orElse(false)) {
110             result |= CAPABILITY_PROTECTED_VM;
111         }
112         if (HypervisorProperties.hypervisor_vm_supported().orElse(false)) {
113             result |= CAPABILITY_NON_PROTECTED_VM;
114         }
115         return result;
116     }
117 
118     /**
119      * Creates a new {@link VirtualMachine} with the given name and config. Creating a virtual
120      * machine with the same name as an existing virtual machine is an error. The existing virtual
121      * machine has to be deleted before its name can be reused.
122      *
123      * <p>Each successful call to this method creates a new (and different) virtual machine even if
124      * the name and the config are the same as a deleted one. The new virtual machine will initially
125      * be stopped.
126      *
127      * <p>NOTE: This method may block and should not be called on the main thread.
128      *
129      * @throws VirtualMachineException if the VM cannot be created, or there is an existing VM with
130      *     the given name.
131      * @hide
132      */
133     @SystemApi
134     @NonNull
135     @WorkerThread
136     @RequiresPermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION)
create(@onNull String name, @NonNull VirtualMachineConfig config)137     public VirtualMachine create(@NonNull String name, @NonNull VirtualMachineConfig config)
138             throws VirtualMachineException {
139         synchronized (sCreateLock) {
140             return createLocked(name, config);
141         }
142     }
143 
144     @NonNull
145     @GuardedBy("sCreateLock")
createLocked(@onNull String name, @NonNull VirtualMachineConfig config)146     private VirtualMachine createLocked(@NonNull String name, @NonNull VirtualMachineConfig config)
147             throws VirtualMachineException {
148         VirtualMachine vm = VirtualMachine.create(mContext, name, config);
149         mVmsByName.put(name, new WeakReference<>(vm));
150         return vm;
151     }
152 
153     /**
154      * Returns an existing {@link VirtualMachine} with the given name. Returns null if there is no
155      * such virtual machine.
156      *
157      * <p>There is at most one {@code VirtualMachine} object corresponding to a given virtual
158      * machine instance. Multiple calls to get() passing the same name will get the same object
159      * returned, until the virtual machine is deleted (via {@link #delete}) and then recreated.
160      *
161      * <p>NOTE: This method may block and should not be called on the main thread.
162      *
163      * @see #getOrCreate
164      * @throws VirtualMachineException if the virtual machine exists but could not be successfully
165      *     retrieved.
166      * @hide
167      */
168     @SystemApi
169     @WorkerThread
170     @Nullable
get(@onNull String name)171     public VirtualMachine get(@NonNull String name) throws VirtualMachineException {
172         synchronized (sCreateLock) {
173             return getLocked(name);
174         }
175     }
176 
177     @Nullable
178     @GuardedBy("sCreateLock")
getLocked(@onNull String name)179     private VirtualMachine getLocked(@NonNull String name) throws VirtualMachineException {
180         VirtualMachine vm = getVmByName(name);
181         if (vm != null) return vm;
182 
183         vm = VirtualMachine.load(mContext, name);
184         if (vm != null) {
185             mVmsByName.put(name, new WeakReference<>(vm));
186         }
187         return vm;
188     }
189 
190     /**
191      * Imports a virtual machine from an {@link VirtualMachineDescriptor} object and associates it
192      * with the given name.
193      *
194      * <p>The new virtual machine will be in the same state as the descriptor indicates. The
195      * descriptor is automatically closed and cannot be used again.
196      *
197      * <p>NOTE: This method may block and should not be called on the main thread.
198      *
199      * @throws VirtualMachineException if the VM cannot be imported or the {@code
200      *     VirtualMachineDescriptor} has already been closed.
201      * @hide
202      */
203     @NonNull
204     @SystemApi
205     @WorkerThread
importFromDescriptor( @onNull String name, @NonNull VirtualMachineDescriptor vmDescriptor)206     public VirtualMachine importFromDescriptor(
207             @NonNull String name, @NonNull VirtualMachineDescriptor vmDescriptor)
208             throws VirtualMachineException {
209         synchronized (sCreateLock) {
210             VirtualMachine vm = VirtualMachine.fromDescriptor(mContext, name, vmDescriptor);
211             mVmsByName.put(name, new WeakReference<>(vm));
212             return vm;
213         }
214     }
215 
216     /**
217      * Returns an existing {@link VirtualMachine} if it exists, or create a new one. The config
218      * parameter is used only when a new virtual machine is created.
219      *
220      * <p>NOTE: This method may block and should not be called on the main thread.
221      *
222      * @throws VirtualMachineException if the virtual machine could not be created or retrieved.
223      * @hide
224      */
225     @SystemApi
226     @WorkerThread
227     @NonNull
getOrCreate(@onNull String name, @NonNull VirtualMachineConfig config)228     public VirtualMachine getOrCreate(@NonNull String name, @NonNull VirtualMachineConfig config)
229             throws VirtualMachineException {
230         synchronized (sCreateLock) {
231             VirtualMachine vm = getLocked(name);
232             if (vm != null) {
233                 return vm;
234             } else {
235                 return createLocked(name, config);
236             }
237         }
238     }
239 
240     /**
241      * Deletes an existing {@link VirtualMachine}. Deleting a virtual machine means deleting any
242      * persisted data associated with it including the per-VM secret. This is an irreversible
243      * action. A virtual machine once deleted can never be restored. A new virtual machine created
244      * with the same name is different from an already deleted virtual machine even if it has the
245      * same config.
246      *
247      * <p>NOTE: This method may block and should not be called on the main thread.
248      *
249      * @throws VirtualMachineException if the virtual machine does not exist, is not stopped, or
250      *     cannot be deleted.
251      * @hide
252      */
253     @SystemApi
254     @WorkerThread
delete(@onNull String name)255     public void delete(@NonNull String name) throws VirtualMachineException {
256         synchronized (sCreateLock) {
257             VirtualMachine vm = getVmByName(name);
258             if (vm == null) {
259                 VirtualMachine.deleteVmDirectory(mContext, name);
260             } else {
261                 vm.delete(mContext, name);
262             }
263             mVmsByName.remove(name);
264         }
265     }
266 
267     @Nullable
268     @GuardedBy("sCreateLock")
getVmByName(@onNull String name)269     private VirtualMachine getVmByName(@NonNull String name) {
270         requireNonNull(name);
271         WeakReference<VirtualMachine> weakReference = mVmsByName.get(name);
272         if (weakReference != null) {
273             VirtualMachine vm = weakReference.get();
274             if (vm != null && vm.getStatus() != VirtualMachine.STATUS_DELETED) {
275                 return vm;
276             }
277         }
278         return null;
279     }
280 }
281