1 // Copyright 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Stable C library for AVF.
16
17 use std::ffi::CStr;
18 use std::fs::File;
19 use std::os::fd::FromRawFd;
20 use std::os::raw::{c_char, c_int};
21 use std::ptr;
22
23 use android_system_virtualizationservice::{
24 aidl::android::system::virtualizationservice::{
25 DiskImage::DiskImage, IVirtualizationService::IVirtualizationService,
26 VirtualMachineConfig::VirtualMachineConfig,
27 VirtualMachineRawConfig::VirtualMachineRawConfig,
28 },
29 binder::{ParcelFileDescriptor, Strong},
30 };
31 use avf_bindgen::StopReason;
32 use vmclient::{DeathReason, VirtualizationService, VmInstance};
33
34 /// Create a new virtual machine config object with no properties.
35 #[no_mangle]
AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig36 pub extern "C" fn AVirtualMachineRawConfig_create() -> *mut VirtualMachineRawConfig {
37 let config = Box::new(VirtualMachineRawConfig {
38 platformVersion: "~1.0".to_owned(),
39 ..Default::default()
40 });
41 Box::into_raw(config)
42 }
43
44 /// Destroy a virtual machine config object.
45 ///
46 /// # Safety
47 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `config` must not be
48 /// used after deletion.
49 #[no_mangle]
AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig)50 pub unsafe extern "C" fn AVirtualMachineRawConfig_destroy(config: *mut VirtualMachineRawConfig) {
51 if !config.is_null() {
52 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
53 // AVirtualMachineRawConfig_create. It's the only reference to the object.
54 unsafe {
55 let _ = Box::from_raw(config);
56 }
57 }
58 }
59
60 /// Set a name of a virtual machine.
61 ///
62 /// # Safety
63 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
64 #[no_mangle]
AVirtualMachineRawConfig_setName( config: *mut VirtualMachineRawConfig, name: *const c_char, ) -> c_int65 pub unsafe extern "C" fn AVirtualMachineRawConfig_setName(
66 config: *mut VirtualMachineRawConfig,
67 name: *const c_char,
68 ) -> c_int {
69 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
70 // AVirtualMachineRawConfig_create. It's the only reference to the object.
71 let config = unsafe { &mut *config };
72 // SAFETY: `name` is assumed to be a pointer to a valid C string.
73 config.name = unsafe { CStr::from_ptr(name) }.to_string_lossy().into_owned();
74 0
75 }
76
77 /// Set an instance ID of a virtual machine.
78 ///
79 /// # Safety
80 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `instanceId` must be a
81 /// valid, non-null pointer to 64-byte data.
82 #[no_mangle]
AVirtualMachineRawConfig_setInstanceId( config: *mut VirtualMachineRawConfig, instance_id: *const u8, ) -> c_int83 pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
84 config: *mut VirtualMachineRawConfig,
85 instance_id: *const u8,
86 ) -> c_int {
87 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
88 // AVirtualMachineRawConfig_create. It's the only reference to the object.
89 let config = unsafe { &mut *config };
90 // SAFETY: `instanceId` is assumed to be a valid pointer to 64 bytes of memory. `config`
91 // is assumed to be a valid object returned by AVirtuaMachineConfig_create.
92 // Both never overlap.
93 unsafe {
94 ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), 64);
95 }
96 0
97 }
98
99 /// Set a kernel image of a virtual machine.
100 ///
101 /// # Safety
102 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
103 /// file descriptor or -1. `AVirtualMachineRawConfig_setKernel` takes ownership of `fd` and `fd`
104 /// will be closed upon `AVirtualMachineRawConfig_delete`.
105 #[no_mangle]
AVirtualMachineRawConfig_setKernel( config: *mut VirtualMachineRawConfig, fd: c_int, ) -> c_int106 pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
107 config: *mut VirtualMachineRawConfig,
108 fd: c_int,
109 ) -> c_int {
110 let file = get_file_from_fd(fd);
111 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
112 // AVirtualMachineRawConfig_create. It's the only reference to the object.
113 let config = unsafe { &mut *config };
114 config.kernel = file.map(ParcelFileDescriptor::new);
115 0
116 }
117
118 /// Set an init rd of a virtual machine.
119 ///
120 /// # Safety
121 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
122 /// file descriptor or -1. `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd` and `fd`
123 /// will be closed upon `AVirtualMachineRawConfig_delete`.
124 #[no_mangle]
AVirtualMachineRawConfig_setInitRd( config: *mut VirtualMachineRawConfig, fd: c_int, ) -> c_int125 pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
126 config: *mut VirtualMachineRawConfig,
127 fd: c_int,
128 ) -> c_int {
129 let file = get_file_from_fd(fd);
130 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
131 // AVirtualMachineRawConfig_create. It's the only reference to the object.
132 let config = unsafe { &mut *config };
133 config.initrd = file.map(ParcelFileDescriptor::new);
134 0
135 }
136
137 /// Add a disk for a virtual machine.
138 ///
139 /// # Safety
140 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `fd` must be a valid
141 /// file descriptor. `AVirtualMachineRawConfig_addDisk` takes ownership of `fd` and `fd` will be
142 /// closed upon `AVirtualMachineRawConfig_delete`.
143 #[no_mangle]
AVirtualMachineRawConfig_addDisk( config: *mut VirtualMachineRawConfig, fd: c_int, writable: bool, ) -> c_int144 pub unsafe extern "C" fn AVirtualMachineRawConfig_addDisk(
145 config: *mut VirtualMachineRawConfig,
146 fd: c_int,
147 writable: bool,
148 ) -> c_int {
149 let file = get_file_from_fd(fd);
150 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
151 // AVirtualMachineRawConfig_create. It's the only reference to the object.
152 let config = unsafe { &mut *config };
153 match file {
154 // partition not supported yet
155 None => -libc::EINVAL,
156 Some(file) => {
157 config.disks.push(DiskImage {
158 image: Some(ParcelFileDescriptor::new(file)),
159 writable,
160 ..Default::default()
161 });
162 0
163 }
164 }
165 }
166
167 /// Set how much memory will be given to a virtual machine.
168 ///
169 /// # Safety
170 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
171 #[no_mangle]
AVirtualMachineRawConfig_setMemoryMib( config: *mut VirtualMachineRawConfig, memory_mib: i32, ) -> c_int172 pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMib(
173 config: *mut VirtualMachineRawConfig,
174 memory_mib: i32,
175 ) -> c_int {
176 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
177 // AVirtualMachineRawConfig_create. It's the only reference to the object.
178 let config = unsafe { &mut *config };
179 config.memoryMib = memory_mib;
180 0
181 }
182
183 /// Set whether a virtual machine is protected or not.
184 ///
185 /// # Safety
186 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
187 #[no_mangle]
AVirtualMachineRawConfig_setProtectedVm( config: *mut VirtualMachineRawConfig, protected_vm: bool, ) -> c_int188 pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
189 config: *mut VirtualMachineRawConfig,
190 protected_vm: bool,
191 ) -> c_int {
192 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
193 // AVirtualMachineRawConfig_create. It's the only reference to the object.
194 let config = unsafe { &mut *config };
195 config.protectedVm = protected_vm;
196 0
197 }
198
199 /// Set whether a virtual machine uses memory ballooning or not.
200 ///
201 /// # Safety
202 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
203 #[no_mangle]
AVirtualMachineRawConfig_setBalloon( config: *mut VirtualMachineRawConfig, balloon: bool, ) -> c_int204 pub unsafe extern "C" fn AVirtualMachineRawConfig_setBalloon(
205 config: *mut VirtualMachineRawConfig,
206 balloon: bool,
207 ) -> c_int {
208 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
209 // AVirtualMachineRawConfig_create. It's the only reference to the object.
210 let config = unsafe { &mut *config };
211 config.noBalloon = !balloon;
212 0
213 }
214
215 /// NOT IMPLEMENTED.
216 ///
217 /// # Returns
218 /// It always returns `-ENOTSUP`.
219 #[no_mangle]
AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod( _config: *mut VirtualMachineRawConfig, _enable: bool, ) -> c_int220 pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
221 _config: *mut VirtualMachineRawConfig,
222 _enable: bool,
223 ) -> c_int {
224 -libc::ENOTSUP
225 }
226
227 /// NOT IMPLEMENTED.
228 ///
229 /// # Returns
230 /// It always returns `-ENOTSUP`.
231 #[no_mangle]
AVirtualMachineRawConfig_addCustomMemoryBackingFile( _config: *mut VirtualMachineRawConfig, _fd: c_int, _range_start: usize, _range_end: usize, ) -> c_int232 pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
233 _config: *mut VirtualMachineRawConfig,
234 _fd: c_int,
235 _range_start: usize,
236 _range_end: usize,
237 ) -> c_int {
238 -libc::ENOTSUP
239 }
240
241 /// Spawn a new instance of `virtmgr`, a child process that will host the `VirtualizationService`
242 /// AIDL service, and connect to the child process.
243 ///
244 /// # Safety
245 /// `service_ptr` must be a valid, non-null pointer to a mutable raw pointer.
246 #[no_mangle]
AVirtualizationService_create( service_ptr: *mut *mut Strong<dyn IVirtualizationService>, early: bool, ) -> c_int247 pub unsafe extern "C" fn AVirtualizationService_create(
248 service_ptr: *mut *mut Strong<dyn IVirtualizationService>,
249 early: bool,
250 ) -> c_int {
251 let virtmgr =
252 if early { VirtualizationService::new_early() } else { VirtualizationService::new() };
253 let virtmgr = match virtmgr {
254 Ok(virtmgr) => virtmgr,
255 Err(e) => return -e.raw_os_error().unwrap_or(libc::EIO),
256 };
257 match virtmgr.connect() {
258 Ok(service) => {
259 // SAFETY: `service` is assumed to be a valid, non-null pointer to a mutable raw
260 // pointer. `service` is the only reference here and `config` takes
261 // ownership.
262 unsafe {
263 *service_ptr = Box::into_raw(Box::new(service));
264 }
265 0
266 }
267 Err(_) => -libc::ECONNREFUSED,
268 }
269 }
270
271 /// Destroy a VirtualizationService object.
272 ///
273 /// # Safety
274 /// `service` must be a pointer returned by `AVirtualizationService_create` or
275 /// `AVirtualizationService_create_early`. `service` must not be reused after deletion.
276 #[no_mangle]
AVirtualizationService_destroy( service: *mut Strong<dyn IVirtualizationService>, )277 pub unsafe extern "C" fn AVirtualizationService_destroy(
278 service: *mut Strong<dyn IVirtualizationService>,
279 ) {
280 if !service.is_null() {
281 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
282 // `AVirtualizationService_create`. It's the only reference to the object.
283 unsafe {
284 let _ = Box::from_raw(service);
285 }
286 }
287 }
288
289 /// Create a virtual machine with given `config`.
290 ///
291 /// # Safety
292 /// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`. `service` must be a
293 /// pointer returned by `AVirtualMachineRawConfig_create`. `vm_ptr` must be a valid, non-null
294 /// pointer to a mutable raw pointer. `console_out_fd`, `console_in_fd`, and `log_fd` must be a
295 /// valid file descriptor or -1. `AVirtualMachine_create` takes ownership of `console_out_fd`,
296 /// `console_in_fd`, and `log_fd`, and taken file descriptors must not be reused.
297 #[no_mangle]
AVirtualMachine_createRaw( service: *const Strong<dyn IVirtualizationService>, config: *mut VirtualMachineRawConfig, console_out_fd: c_int, console_in_fd: c_int, log_fd: c_int, vm_ptr: *mut *mut VmInstance, ) -> c_int298 pub unsafe extern "C" fn AVirtualMachine_createRaw(
299 service: *const Strong<dyn IVirtualizationService>,
300 config: *mut VirtualMachineRawConfig,
301 console_out_fd: c_int,
302 console_in_fd: c_int,
303 log_fd: c_int,
304 vm_ptr: *mut *mut VmInstance,
305 ) -> c_int {
306 // SAFETY: `service` is assumed to be a valid, non-null pointer returned by
307 // `AVirtualizationService_create` or `AVirtualizationService_create_early`. It's the only
308 // reference to the object.
309 let service = unsafe { &*service };
310
311 // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
312 // `AVirtualMachineRawConfig_create`. It's the only reference to the object.
313 let config = unsafe { *Box::from_raw(config) };
314 let config = VirtualMachineConfig::RawConfig(config);
315
316 let console_out = get_file_from_fd(console_out_fd);
317 let console_in = get_file_from_fd(console_in_fd);
318 let log = get_file_from_fd(log_fd);
319
320 match VmInstance::create(service.as_ref(), &config, console_out, console_in, log, None, None) {
321 Ok(vm) => {
322 // SAFETY: `vm_ptr` is assumed to be a valid, non-null pointer to a mutable raw pointer.
323 // `vm` is the only reference here and `vm_ptr` takes ownership.
324 unsafe {
325 *vm_ptr = Box::into_raw(Box::new(vm));
326 }
327 0
328 }
329 Err(_) => -libc::EIO,
330 }
331 }
332
333 /// Start a virtual machine.
334 ///
335 /// # Safety
336 /// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
337 #[no_mangle]
AVirtualMachine_start(vm: *const VmInstance) -> c_int338 pub unsafe extern "C" fn AVirtualMachine_start(vm: *const VmInstance) -> c_int {
339 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
340 // `AVirtualMachine_createRaw`. It's the only reference to the object.
341 let vm = unsafe { &*vm };
342 match vm.start() {
343 Ok(_) => 0,
344 Err(_) => -libc::EIO,
345 }
346 }
347
348 /// Stop a virtual machine.
349 ///
350 /// # Safety
351 /// `vm` must be a pointer returned by `AVirtualMachine_create`.
352 #[no_mangle]
AVirtualMachine_stop(vm: *const VmInstance) -> c_int353 pub unsafe extern "C" fn AVirtualMachine_stop(vm: *const VmInstance) -> c_int {
354 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
355 // `AVirtualMachine_createRaw`. It's the only reference to the object.
356 let vm = unsafe { &*vm };
357 match vm.stop() {
358 Ok(_) => 0,
359 Err(_) => -libc::EIO,
360 }
361 }
362
363 /// Wait until a virtual machine stops.
364 ///
365 /// # Safety
366 /// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
367 #[no_mangle]
AVirtualMachine_waitForStop(vm: *const VmInstance) -> StopReason368 pub unsafe extern "C" fn AVirtualMachine_waitForStop(vm: *const VmInstance) -> StopReason {
369 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
370 // AVirtualMachine_create. It's the only reference to the object.
371 let vm = unsafe { &*vm };
372 match vm.wait_for_death() {
373 DeathReason::VirtualizationServiceDied => StopReason::VIRTUALIZATION_SERVICE_DIED,
374 DeathReason::InfrastructureError => StopReason::INFRASTRUCTURE_ERROR,
375 DeathReason::Killed => StopReason::KILLED,
376 DeathReason::Unknown => StopReason::UNKNOWN,
377 DeathReason::Shutdown => StopReason::SHUTDOWN,
378 DeathReason::StartFailed => StopReason::START_FAILED,
379 DeathReason::Reboot => StopReason::REBOOT,
380 DeathReason::Crash => StopReason::CRASH,
381 DeathReason::PvmFirmwarePublicKeyMismatch => StopReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH,
382 DeathReason::PvmFirmwareInstanceImageChanged => {
383 StopReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
384 }
385 DeathReason::Hangup => StopReason::HANGUP,
386 _ => StopReason::UNRECOGNISED,
387 }
388 }
389
390 /// Destroy a virtual machine.
391 ///
392 /// # Safety
393 /// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `vm` must not be reused after
394 /// deletion.
395 #[no_mangle]
AVirtualMachine_destroy(vm: *mut VmInstance)396 pub unsafe extern "C" fn AVirtualMachine_destroy(vm: *mut VmInstance) {
397 if !vm.is_null() {
398 // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
399 // AVirtualMachine_create. It's the only reference to the object.
400 unsafe {
401 let _ = Box::from_raw(vm);
402 }
403 }
404 }
405
get_file_from_fd(fd: i32) -> Option<File>406 fn get_file_from_fd(fd: i32) -> Option<File> {
407 if fd == -1 {
408 None
409 } else {
410 // SAFETY: transferring ownership of `fd` from the caller
411 Some(unsafe { File::from_raw_fd(fd) })
412 }
413 }
414