• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021, 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 //! Implementation of the AIDL interface of the VirtualizationService.
16 
17 use crate::composite::make_composite_image;
18 use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmInstance, VmState};
19 use crate::payload::add_microdroid_images;
20 use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
21 use crate::selinux::{SeContext, getfilecon};
22 use ::binder::unstable_api::AsNative;
23 use android_os_permissions_aidl::aidl::android::os::IPermissionController;
24 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
25     DeathReason::DeathReason,
26     DiskImage::DiskImage,
27     IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
28     IVirtualMachineCallback::IVirtualMachineCallback,
29     IVirtualizationService::IVirtualizationService,
30     Partition::Partition,
31     PartitionType::PartitionType,
32     VirtualMachineAppConfig::VirtualMachineAppConfig,
33     VirtualMachineConfig::VirtualMachineConfig,
34     VirtualMachineDebugInfo::VirtualMachineDebugInfo,
35     VirtualMachineRawConfig::VirtualMachineRawConfig,
36     VirtualMachineState::VirtualMachineState,
37 };
38 use android_system_virtualizationservice::binder::{
39     self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, StatusCode, Strong,
40     ThreadState,
41 };
42 use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
43     IVirtualMachineService::{
44         BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
45         VM_STREAM_SERVICE_PORT, VM_TOMBSTONES_SERVICE_PORT,
46     },
47 };
48 use anyhow::{anyhow, bail, Context, Result};
49 use binder_common::{lazy_service::LazyServiceGuard, new_binder_exception};
50 use disk::QcowFile;
51 use idsig::{HashAlgorithm, V4Signature};
52 use log::{debug, error, info, warn, trace};
53 use microdroid_payload_config::VmPayloadConfig;
54 use rustutils::system_properties;
55 use semver::VersionReq;
56 use statslog_virtualization_rust::vm_creation_requested::{stats_write, Hypervisor};
57 use std::convert::TryInto;
58 use std::ffi::CStr;
59 use std::fs::{create_dir, File, OpenOptions};
60 use std::io::{Error, ErrorKind, Write, Read};
61 use std::num::NonZeroU32;
62 use std::os::raw;
63 use std::os::unix::io::{FromRawFd, IntoRawFd};
64 use std::path::{Path, PathBuf};
65 use std::ptr::null_mut;
66 use std::sync::{Arc, Mutex, Weak};
67 use tombstoned_client::{TombstonedConnection, DebuggerdDumpType};
68 use vmconfig::VmConfig;
69 use vsock::{SockAddr, VsockListener, VsockStream};
70 use zip::ZipArchive;
71 
72 pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
73 
74 /// Directory in which to write disk image files used while running VMs.
75 pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
76 
77 /// The CID representing the host VM
78 const VMADDR_CID_HOST: u32 = 2;
79 
80 /// The size of zero.img.
81 /// Gaps in composite disk images are filled with a shared zero.img.
82 const ZERO_FILLER_SIZE: u64 = 4096;
83 
84 /// Magic string for the instance image
85 const ANDROID_VM_INSTANCE_MAGIC: &str = "Android-VM-instance";
86 
87 /// Version of the instance image format
88 const ANDROID_VM_INSTANCE_VERSION: u16 = 1;
89 
90 const CHUNK_RECV_MAX_LEN: usize = 1024;
91 
92 /// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
93 #[derive(Debug, Default)]
94 pub struct VirtualizationService {
95     state: Arc<Mutex<State>>,
96 }
97 
98 impl Interface for VirtualizationService {
dump(&self, mut file: &File, _args: &[&CStr]) -> Result<(), StatusCode>99     fn dump(&self, mut file: &File, _args: &[&CStr]) -> Result<(), StatusCode> {
100         check_permission("android.permission.DUMP").or(Err(StatusCode::PERMISSION_DENIED))?;
101         let state = &mut *self.state.lock().unwrap();
102         let vms = state.vms();
103         writeln!(file, "Running {0} VMs:", vms.len()).or(Err(StatusCode::UNKNOWN_ERROR))?;
104         for vm in vms {
105             writeln!(file, "VM CID: {}", vm.cid).or(Err(StatusCode::UNKNOWN_ERROR))?;
106             writeln!(file, "\tState: {:?}", vm.vm_state.lock().unwrap())
107                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
108             writeln!(file, "\tPayload state {:?}", vm.payload_state())
109                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
110             writeln!(file, "\tProtected: {}", vm.protected).or(Err(StatusCode::UNKNOWN_ERROR))?;
111             writeln!(file, "\ttemporary_directory: {}", vm.temporary_directory.to_string_lossy())
112                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
113             writeln!(file, "\trequester_uid: {}", vm.requester_uid)
114                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
115             writeln!(file, "\trequester_sid: {}", vm.requester_sid)
116                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
117             writeln!(file, "\trequester_debug_pid: {}", vm.requester_debug_pid)
118                 .or(Err(StatusCode::UNKNOWN_ERROR))?;
119         }
120         Ok(())
121     }
122 }
123 
124 impl IVirtualizationService for VirtualizationService {
125     /// Creates (but does not start) a new VM with the given configuration, assigning it the next
126     /// available CID.
127     ///
128     /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client.
createVm( &self, config: &VirtualMachineConfig, console_fd: Option<&ParcelFileDescriptor>, log_fd: Option<&ParcelFileDescriptor>, ) -> binder::Result<Strong<dyn IVirtualMachine>>129     fn createVm(
130         &self,
131         config: &VirtualMachineConfig,
132         console_fd: Option<&ParcelFileDescriptor>,
133         log_fd: Option<&ParcelFileDescriptor>,
134     ) -> binder::Result<Strong<dyn IVirtualMachine>> {
135         let mut is_protected = false;
136         let ret = self.create_vm_internal(config, console_fd, log_fd, &mut is_protected);
137         match ret {
138             Ok(_) => {
139                 let ok_status = Status::ok();
140                 write_vm_creation_stats(
141                     is_protected,
142                     /*creation_succeeded*/ true,
143                     ok_status.exception_code() as i32,
144                 );
145             }
146             Err(ref e) => {
147                 write_vm_creation_stats(
148                     is_protected,
149                     /*creation_succeeded*/ false,
150                     e.exception_code() as i32,
151                 );
152             }
153         }
154         ret
155     }
156 
157     /// Initialise an empty partition image of the given size to be used as a writable partition.
initializeWritablePartition( &self, image_fd: &ParcelFileDescriptor, size: i64, partition_type: PartitionType, ) -> binder::Result<()>158     fn initializeWritablePartition(
159         &self,
160         image_fd: &ParcelFileDescriptor,
161         size: i64,
162         partition_type: PartitionType,
163     ) -> binder::Result<()> {
164         check_manage_access()?;
165         let size = size.try_into().map_err(|e| {
166             new_binder_exception(
167                 ExceptionCode::ILLEGAL_ARGUMENT,
168                 format!("Invalid size {}: {}", size, e),
169             )
170         })?;
171         let image = clone_file(image_fd)?;
172         // initialize the file. Any data in the file will be erased.
173         image.set_len(0).map_err(|e| {
174             new_binder_exception(
175                 ExceptionCode::SERVICE_SPECIFIC,
176                 format!("Failed to reset a file: {}", e),
177             )
178         })?;
179         let mut part = QcowFile::new(image, size).map_err(|e| {
180             new_binder_exception(
181                 ExceptionCode::SERVICE_SPECIFIC,
182                 format!("Failed to create QCOW2 image: {}", e),
183             )
184         })?;
185 
186         match partition_type {
187             PartitionType::RAW => Ok(()),
188             PartitionType::ANDROID_VM_INSTANCE => format_as_android_vm_instance(&mut part),
189             _ => Err(Error::new(
190                 ErrorKind::Unsupported,
191                 format!("Unsupported partition type {:?}", partition_type),
192             )),
193         }
194         .map_err(|e| {
195             new_binder_exception(
196                 ExceptionCode::SERVICE_SPECIFIC,
197                 format!("Failed to initialize partition as {:?}: {}", partition_type, e),
198             )
199         })?;
200 
201         Ok(())
202     }
203 
204     /// Creates or update the idsig file by digesting the input APK file.
createOrUpdateIdsigFile( &self, input_fd: &ParcelFileDescriptor, idsig_fd: &ParcelFileDescriptor, ) -> binder::Result<()>205     fn createOrUpdateIdsigFile(
206         &self,
207         input_fd: &ParcelFileDescriptor,
208         idsig_fd: &ParcelFileDescriptor,
209     ) -> binder::Result<()> {
210         // TODO(b/193504400): do this only when (1) idsig_fd is empty or (2) the APK digest in
211         // idsig_fd is different from APK digest in input_fd
212 
213         let mut input = clone_file(input_fd)?;
214         let mut sig = V4Signature::create(&mut input, 4096, &[], HashAlgorithm::SHA256).unwrap();
215 
216         let mut output = clone_file(idsig_fd)?;
217         output.set_len(0).unwrap();
218         sig.write_into(&mut output).unwrap();
219         Ok(())
220     }
221 
222     /// Get a list of all currently running VMs. This method is only intended for debug purposes,
223     /// and as such is only permitted from the shell user.
debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>>224     fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
225         check_debug_access()?;
226 
227         let state = &mut *self.state.lock().unwrap();
228         let vms = state.vms();
229         let cids = vms
230             .into_iter()
231             .map(|vm| VirtualMachineDebugInfo {
232                 cid: vm.cid as i32,
233                 temporaryDirectory: vm.temporary_directory.to_string_lossy().to_string(),
234                 requesterUid: vm.requester_uid as i32,
235                 requesterSid: vm.requester_sid.clone(),
236                 requesterPid: vm.requester_debug_pid,
237                 state: get_state(&vm),
238             })
239             .collect();
240         Ok(cids)
241     }
242 
243     /// Hold a strong reference to a VM in VirtualizationService. This method is only intended for
244     /// debug purposes, and as such is only permitted from the shell user.
debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()>245     fn debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()> {
246         check_debug_access()?;
247 
248         let state = &mut *self.state.lock().unwrap();
249         state.debug_hold_vm(vmref.clone());
250         Ok(())
251     }
252 
253     /// Drop reference to a VM that is being held by VirtualizationService. Returns the reference if
254     /// the VM was found and None otherwise. This method is only intended for debug purposes, and as
255     /// such is only permitted from the shell user.
debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>>256     fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> {
257         check_debug_access()?;
258 
259         let state = &mut *self.state.lock().unwrap();
260         Ok(state.debug_drop_vm(cid))
261     }
262 }
263 
handle_stream_connection_tombstoned() -> Result<()>264 fn handle_stream_connection_tombstoned() -> Result<()> {
265     let listener =
266         VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as u32)?;
267     info!("Listening to tombstones from guests ...");
268     for incoming_stream in listener.incoming() {
269         let mut incoming_stream = match incoming_stream {
270             Err(e) => {
271                 warn!("invalid incoming connection: {}", e);
272                 continue;
273             }
274             Ok(s) => s,
275         };
276         std::thread::spawn(move || {
277             if let Err(e) = handle_tombstone(&mut incoming_stream) {
278                 error!("Failed to write tombstone- {:?}", e);
279             }
280         });
281     }
282     Ok(())
283 }
284 
handle_tombstone(stream: &mut VsockStream) -> Result<()>285 fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
286     if let Ok(SockAddr::Vsock(addr)) = stream.peer_addr() {
287         info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
288     }
289     let tb_connection =
290         TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
291             .context("Failed to connect to tombstoned")?;
292     let mut text_output = tb_connection
293         .text_output
294         .as_ref()
295         .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
296     let mut num_bytes_read = 0;
297     loop {
298         let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
299         let n = stream
300             .read(&mut chunk_recv)
301             .context("Failed to read tombstone data from Vsock stream")?;
302         if n == 0 {
303             break;
304         }
305         num_bytes_read += n;
306         text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
307     }
308     info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
309     tb_connection.notify_completion()?;
310     Ok(())
311 }
312 
313 impl VirtualizationService {
init() -> VirtualizationService314     pub fn init() -> VirtualizationService {
315         let service = VirtualizationService::default();
316 
317         // server for payload output
318         let state = service.state.clone(); // reference to state (not the state itself) is copied
319         std::thread::spawn(move || {
320             handle_stream_connection_from_vm(state).unwrap();
321         });
322 
323         std::thread::spawn(|| {
324             if let Err(e) = handle_stream_connection_tombstoned() {
325                 warn!("Error receiving tombstone from guest or writing them. Error: {}", e);
326             }
327         });
328 
329         // binder server for vm
330         // reference to state (not the state itself) is copied
331         let mut state = service.state.clone();
332         std::thread::spawn(move || {
333             let state_ptr = &mut state as *mut _ as *mut raw::c_void;
334 
335             debug!("virtual machine service is starting as an RPC service.");
336             // SAFETY: factory function is only ever called by RunRpcServerWithFactory, within the
337             // lifetime of the state, with context taking the pointer value above (so a properly
338             // aligned non-null pointer to an initialized instance).
339             let retval = unsafe {
340                 binder_rpc_unstable_bindgen::RunRpcServerWithFactory(
341                     Some(VirtualMachineService::factory),
342                     state_ptr,
343                     VM_BINDER_SERVICE_PORT as u32,
344                 )
345             };
346             if retval {
347                 debug!("RPC server has shut down gracefully");
348             } else {
349                 bail!("Premature termination of RPC server");
350             }
351 
352             Ok(retval)
353         });
354         service
355     }
356 
create_vm_internal( &self, config: &VirtualMachineConfig, console_fd: Option<&ParcelFileDescriptor>, log_fd: Option<&ParcelFileDescriptor>, is_protected: &mut bool, ) -> binder::Result<Strong<dyn IVirtualMachine>>357     fn create_vm_internal(
358         &self,
359         config: &VirtualMachineConfig,
360         console_fd: Option<&ParcelFileDescriptor>,
361         log_fd: Option<&ParcelFileDescriptor>,
362         is_protected: &mut bool,
363     ) -> binder::Result<Strong<dyn IVirtualMachine>> {
364         check_manage_access()?;
365         let state = &mut *self.state.lock().unwrap();
366         let console_fd = console_fd.map(clone_file).transpose()?;
367         let log_fd = log_fd.map(clone_file).transpose()?;
368         let requester_uid = ThreadState::get_calling_uid();
369         let requester_sid = get_calling_sid()?;
370         let requester_debug_pid = ThreadState::get_calling_pid();
371         let cid = next_cid().or(Err(ExceptionCode::ILLEGAL_STATE))?;
372 
373         // Counter to generate unique IDs for temporary image files.
374         let mut next_temporary_image_id = 0;
375         // Files which are referred to from composite images. These must be mapped to the crosvm
376         // child process, and not closed before it is started.
377         let mut indirect_files = vec![];
378 
379         // Make directory for temporary files.
380         let temporary_directory: PathBuf = format!("{}/{}", TEMPORARY_DIRECTORY, cid).into();
381         create_dir(&temporary_directory).map_err(|e| {
382             // At this point, we do not know the protected status of Vm
383             // setting it to false, though this may not be correct.
384             error!(
385                 "Failed to create temporary directory {:?} for VM files: {}",
386                 temporary_directory, e
387             );
388             new_binder_exception(
389                 ExceptionCode::SERVICE_SPECIFIC,
390                 format!(
391                     "Failed to create temporary directory {:?} for VM files: {}",
392                     temporary_directory, e
393                 ),
394             )
395         })?;
396 
397         let is_app_config = matches!(config, VirtualMachineConfig::AppConfig(_));
398 
399         let config = match config {
400             VirtualMachineConfig::AppConfig(config) => BorrowedOrOwned::Owned(
401                 load_app_config(config, &temporary_directory).map_err(|e| {
402                     error!("Failed to load app config from {}: {}", &config.configPath, e);
403                     *is_protected = config.protectedVm;
404                     new_binder_exception(
405                         ExceptionCode::SERVICE_SPECIFIC,
406                         format!("Failed to load app config from {}: {}", &config.configPath, e),
407                     )
408                 })?,
409             ),
410             VirtualMachineConfig::RawConfig(config) => BorrowedOrOwned::Borrowed(config),
411         };
412         let config = config.as_ref();
413         *is_protected = config.protectedVm;
414 
415         // Check if partition images are labeled incorrectly. This is to prevent random images
416         // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
417         // being loaded in a pVM.  Specifically, for images in the raw config, nothing is allowed
418         // to be labeled as app_data_file. For images in the app config, nothing but the instance
419         // partition is allowed to be labeled as such.
420         config
421             .disks
422             .iter()
423             .flat_map(|disk| disk.partitions.iter())
424             .filter(|partition| {
425                 if is_app_config {
426                     partition.label != "vm-instance"
427                 } else {
428                     true // all partitions are checked
429                 }
430             })
431             .try_for_each(check_label_for_partition)
432             .map_err(|e| new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string()))?;
433 
434         let zero_filler_path = temporary_directory.join("zero.img");
435         write_zero_filler(&zero_filler_path).map_err(|e| {
436             error!("Failed to make composite image: {}", e);
437             new_binder_exception(
438                 ExceptionCode::SERVICE_SPECIFIC,
439                 format!("Failed to make composite image: {}", e),
440             )
441         })?;
442 
443         // Assemble disk images if needed.
444         let disks = config
445             .disks
446             .iter()
447             .map(|disk| {
448                 assemble_disk_image(
449                     disk,
450                     &zero_filler_path,
451                     &temporary_directory,
452                     &mut next_temporary_image_id,
453                     &mut indirect_files,
454                 )
455             })
456             .collect::<Result<Vec<DiskFile>, _>>()?;
457 
458         // Actually start the VM.
459         let crosvm_config = CrosvmConfig {
460             cid,
461             bootloader: maybe_clone_file(&config.bootloader)?,
462             kernel: maybe_clone_file(&config.kernel)?,
463             initrd: maybe_clone_file(&config.initrd)?,
464             disks,
465             params: config.params.to_owned(),
466             protected: *is_protected,
467             memory_mib: config.memoryMib.try_into().ok().and_then(NonZeroU32::new),
468             cpus: config.numCpus.try_into().ok().and_then(NonZeroU32::new),
469             cpu_affinity: config.cpuAffinity.clone(),
470             task_profiles: config.taskProfiles.clone(),
471             console_fd,
472             log_fd,
473             indirect_files,
474             platform_version: parse_platform_version_req(&config.platformVersion)?,
475         };
476         let instance = Arc::new(
477             VmInstance::new(
478                 crosvm_config,
479                 temporary_directory,
480                 requester_uid,
481                 requester_sid,
482                 requester_debug_pid,
483             )
484             .map_err(|e| {
485                 error!("Failed to create VM with config {:?}: {}", config, e);
486                 new_binder_exception(
487                     ExceptionCode::SERVICE_SPECIFIC,
488                     format!("Failed to create VM: {}", e),
489                 )
490             })?,
491         );
492         state.add_vm(Arc::downgrade(&instance));
493         Ok(VirtualMachine::create(instance))
494     }
495 }
496 
497 /// Write the stats of VMCreation to statsd
write_vm_creation_stats(is_protected: bool, creation_succeeded: bool, exception_code: i32)498 fn write_vm_creation_stats(is_protected: bool, creation_succeeded: bool, exception_code: i32) {
499     match stats_write(Hypervisor::Pkvm, is_protected, creation_succeeded, exception_code) {
500         Err(e) => {
501             warn!("statslog_rust failed with error: {}", e);
502         }
503         Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
504     }
505 }
506 
507 /// Waits for incoming connections from VM. If a new connection is made, stores the stream in the
508 /// corresponding `VmInstance`.
handle_stream_connection_from_vm(state: Arc<Mutex<State>>) -> Result<()>509 fn handle_stream_connection_from_vm(state: Arc<Mutex<State>>) -> Result<()> {
510     let listener =
511         VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_STREAM_SERVICE_PORT as u32)?;
512     for stream in listener.incoming() {
513         let stream = match stream {
514             Err(e) => {
515                 warn!("invalid incoming connection: {}", e);
516                 continue;
517             }
518             Ok(s) => s,
519         };
520         if let Ok(SockAddr::Vsock(addr)) = stream.peer_addr() {
521             let cid = addr.cid();
522             let port = addr.port();
523             info!("payload stream connected from cid={}, port={}", cid, port);
524             if let Some(vm) = state.lock().unwrap().get_vm(cid) {
525                 *vm.stream.lock().unwrap() = Some(stream);
526             } else {
527                 error!("connection from cid={} is not from a guest VM", cid);
528             }
529         }
530     }
531     Ok(())
532 }
533 
write_zero_filler(zero_filler_path: &Path) -> Result<()>534 fn write_zero_filler(zero_filler_path: &Path) -> Result<()> {
535     let file = OpenOptions::new()
536         .create_new(true)
537         .read(true)
538         .write(true)
539         .open(zero_filler_path)
540         .with_context(|| "Failed to create zero.img")?;
541     file.set_len(ZERO_FILLER_SIZE)?;
542     Ok(())
543 }
544 
format_as_android_vm_instance(part: &mut dyn Write) -> std::io::Result<()>545 fn format_as_android_vm_instance(part: &mut dyn Write) -> std::io::Result<()> {
546     part.write_all(ANDROID_VM_INSTANCE_MAGIC.as_bytes())?;
547     part.write_all(&ANDROID_VM_INSTANCE_VERSION.to_le_bytes())?;
548     part.flush()
549 }
550 
551 /// Given the configuration for a disk image, assembles the `DiskFile` to pass to crosvm.
552 ///
553 /// This may involve assembling a composite disk from a set of partition images.
assemble_disk_image( disk: &DiskImage, zero_filler_path: &Path, temporary_directory: &Path, next_temporary_image_id: &mut u64, indirect_files: &mut Vec<File>, ) -> Result<DiskFile, Status>554 fn assemble_disk_image(
555     disk: &DiskImage,
556     zero_filler_path: &Path,
557     temporary_directory: &Path,
558     next_temporary_image_id: &mut u64,
559     indirect_files: &mut Vec<File>,
560 ) -> Result<DiskFile, Status> {
561     let image = if !disk.partitions.is_empty() {
562         if disk.image.is_some() {
563             warn!("DiskImage {:?} contains both image and partitions.", disk);
564             return Err(new_binder_exception(
565                 ExceptionCode::ILLEGAL_ARGUMENT,
566                 "DiskImage contains both image and partitions.",
567             ));
568         }
569 
570         let composite_image_filenames =
571             make_composite_image_filenames(temporary_directory, next_temporary_image_id);
572         let (image, partition_files) = make_composite_image(
573             &disk.partitions,
574             zero_filler_path,
575             &composite_image_filenames.composite,
576             &composite_image_filenames.header,
577             &composite_image_filenames.footer,
578         )
579         .map_err(|e| {
580             error!("Failed to make composite image with config {:?}: {}", disk, e);
581             new_binder_exception(
582                 ExceptionCode::SERVICE_SPECIFIC,
583                 format!("Failed to make composite image: {}", e),
584             )
585         })?;
586 
587         // Pass the file descriptors for the various partition files to crosvm when it
588         // is run.
589         indirect_files.extend(partition_files);
590 
591         image
592     } else if let Some(image) = &disk.image {
593         clone_file(image)?
594     } else {
595         warn!("DiskImage {:?} didn't contain image or partitions.", disk);
596         return Err(new_binder_exception(
597             ExceptionCode::ILLEGAL_ARGUMENT,
598             "DiskImage didn't contain image or partitions.",
599         ));
600     };
601 
602     Ok(DiskFile { image, writable: disk.writable })
603 }
604 
load_app_config( config: &VirtualMachineAppConfig, temporary_directory: &Path, ) -> Result<VirtualMachineRawConfig>605 fn load_app_config(
606     config: &VirtualMachineAppConfig,
607     temporary_directory: &Path,
608 ) -> Result<VirtualMachineRawConfig> {
609     let apk_file = clone_file(config.apk.as_ref().unwrap())?;
610     let idsig_file = clone_file(config.idsig.as_ref().unwrap())?;
611     let instance_file = clone_file(config.instanceImage.as_ref().unwrap())?;
612     let config_path = &config.configPath;
613 
614     let mut apk_zip = ZipArchive::new(&apk_file)?;
615     let config_file = apk_zip.by_name(config_path)?;
616     let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
617 
618     let os_name = &vm_payload_config.os.name;
619 
620     // For now, the only supported "os" value is "microdroid"
621     if os_name != "microdroid" {
622         bail!("Unknown OS \"{}\"", os_name);
623     }
624 
625     // It is safe to construct a filename based on the os_name because we've already checked that it
626     // is one of the allowed values.
627     let vm_config_path = PathBuf::from(format!("/apex/com.android.virt/etc/{}.json", os_name));
628     let vm_config_file = File::open(vm_config_path)?;
629     let mut vm_config = VmConfig::load(&vm_config_file)?.to_parcelable()?;
630 
631     if config.memoryMib > 0 {
632         vm_config.memoryMib = config.memoryMib;
633     }
634 
635     vm_config.protectedVm = config.protectedVm;
636     vm_config.numCpus = config.numCpus;
637     vm_config.cpuAffinity = config.cpuAffinity.clone();
638     vm_config.taskProfiles = config.taskProfiles.clone();
639 
640     // Microdroid requires an additional payload disk image and the bootconfig partition.
641     if os_name == "microdroid" {
642         add_microdroid_images(
643             config,
644             temporary_directory,
645             apk_file,
646             idsig_file,
647             instance_file,
648             &vm_payload_config,
649             &mut vm_config,
650         )?;
651     }
652 
653     Ok(vm_config)
654 }
655 
656 /// Generates a unique filename to use for a composite disk image.
make_composite_image_filenames( temporary_directory: &Path, next_temporary_image_id: &mut u64, ) -> CompositeImageFilenames657 fn make_composite_image_filenames(
658     temporary_directory: &Path,
659     next_temporary_image_id: &mut u64,
660 ) -> CompositeImageFilenames {
661     let id = *next_temporary_image_id;
662     *next_temporary_image_id += 1;
663     CompositeImageFilenames {
664         composite: temporary_directory.join(format!("composite-{}.img", id)),
665         header: temporary_directory.join(format!("composite-{}-header.img", id)),
666         footer: temporary_directory.join(format!("composite-{}-footer.img", id)),
667     }
668 }
669 
670 /// Filenames for a composite disk image, including header and footer partitions.
671 #[derive(Clone, Debug, Eq, PartialEq)]
672 struct CompositeImageFilenames {
673     /// The composite disk image itself.
674     composite: PathBuf,
675     /// The header partition image.
676     header: PathBuf,
677     /// The footer partition image.
678     footer: PathBuf,
679 }
680 
681 /// Gets the calling SID of the current Binder thread.
get_calling_sid() -> Result<String, Status>682 fn get_calling_sid() -> Result<String, Status> {
683     ThreadState::with_calling_sid(|sid| {
684         if let Some(sid) = sid {
685             match sid.to_str() {
686                 Ok(sid) => Ok(sid.to_owned()),
687                 Err(e) => {
688                     error!("SID was not valid UTF-8: {}", e);
689                     Err(new_binder_exception(
690                         ExceptionCode::ILLEGAL_ARGUMENT,
691                         format!("SID was not valid UTF-8: {}", e),
692                     ))
693                 }
694             }
695         } else {
696             error!("Missing SID on createVm");
697             Err(new_binder_exception(ExceptionCode::SECURITY, "Missing SID on createVm"))
698         }
699     })
700 }
701 
702 /// Checks whether the caller has a specific permission
check_permission(perm: &str) -> binder::Result<()>703 fn check_permission(perm: &str) -> binder::Result<()> {
704     let calling_pid = ThreadState::get_calling_pid();
705     let calling_uid = ThreadState::get_calling_uid();
706     // Root can do anything
707     if calling_uid == 0 {
708         return Ok(());
709     }
710     let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
711         binder::get_interface("permission")?;
712     if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
713         Ok(())
714     } else {
715         Err(new_binder_exception(
716             ExceptionCode::SECURITY,
717             format!("does not have the {} permission", perm),
718         ))
719     }
720 }
721 
722 /// Check whether the caller of the current Binder method is allowed to call debug methods.
check_debug_access() -> binder::Result<()>723 fn check_debug_access() -> binder::Result<()> {
724     check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
725 }
726 
727 /// Check whether the caller of the current Binder method is allowed to manage VMs
check_manage_access() -> binder::Result<()>728 fn check_manage_access() -> binder::Result<()> {
729     check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
730 }
731 
732 /// Check if a partition has selinux labels that are not allowed
check_label_for_partition(partition: &Partition) -> Result<()>733 fn check_label_for_partition(partition: &Partition) -> Result<()> {
734     let ctx = getfilecon(partition.image.as_ref().unwrap().as_ref())?;
735     if ctx == SeContext::new("u:object_r:app_data_file:s0").unwrap() {
736         Err(anyhow!("Partition {} shouldn't be labeled as {}", &partition.label, ctx))
737     } else {
738         Ok(())
739     }
740 }
741 
742 /// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
743 #[derive(Debug)]
744 struct VirtualMachine {
745     instance: Arc<VmInstance>,
746     /// Keeps our service process running as long as this VM instance exists.
747     #[allow(dead_code)]
748     lazy_service_guard: LazyServiceGuard,
749 }
750 
751 impl VirtualMachine {
create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine>752     fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
753         let binder = VirtualMachine { instance, lazy_service_guard: Default::default() };
754         BnVirtualMachine::new_binder(binder, BinderFeatures::default())
755     }
756 }
757 
758 impl Interface for VirtualMachine {}
759 
760 impl IVirtualMachine for VirtualMachine {
getCid(&self) -> binder::Result<i32>761     fn getCid(&self) -> binder::Result<i32> {
762         // Don't check permission. The owner of the VM might have passed this binder object to
763         // others.
764         Ok(self.instance.cid as i32)
765     }
766 
getState(&self) -> binder::Result<VirtualMachineState>767     fn getState(&self) -> binder::Result<VirtualMachineState> {
768         // Don't check permission. The owner of the VM might have passed this binder object to
769         // others.
770         Ok(get_state(&self.instance))
771     }
772 
registerCallback( &self, callback: &Strong<dyn IVirtualMachineCallback>, ) -> binder::Result<()>773     fn registerCallback(
774         &self,
775         callback: &Strong<dyn IVirtualMachineCallback>,
776     ) -> binder::Result<()> {
777         // Don't check permission. The owner of the VM might have passed this binder object to
778         // others.
779         //
780         // TODO: Should this give an error if the VM is already dead?
781         self.instance.callbacks.add(callback.clone());
782         Ok(())
783     }
784 
start(&self) -> binder::Result<()>785     fn start(&self) -> binder::Result<()> {
786         self.instance.start().map_err(|e| {
787             error!("Error starting VM with CID {}: {:?}", self.instance.cid, e);
788             new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string())
789         })
790     }
791 
connectVsock(&self, port: i32) -> binder::Result<ParcelFileDescriptor>792     fn connectVsock(&self, port: i32) -> binder::Result<ParcelFileDescriptor> {
793         if !matches!(&*self.instance.vm_state.lock().unwrap(), VmState::Running { .. }) {
794             return Err(new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, "VM is not running"));
795         }
796         let stream =
797             VsockStream::connect_with_cid_port(self.instance.cid, port as u32).map_err(|e| {
798                 new_binder_exception(
799                     ExceptionCode::SERVICE_SPECIFIC,
800                     format!("Failed to connect: {}", e),
801                 )
802             })?;
803         Ok(vsock_stream_to_pfd(stream))
804     }
805 }
806 
807 impl Drop for VirtualMachine {
drop(&mut self)808     fn drop(&mut self) {
809         debug!("Dropping {:?}", self);
810         self.instance.kill();
811     }
812 }
813 
814 /// A set of Binders to be called back in response to various events on the VM, such as when it
815 /// dies.
816 #[derive(Debug, Default)]
817 pub struct VirtualMachineCallbacks(Mutex<Vec<Strong<dyn IVirtualMachineCallback>>>);
818 
819 impl VirtualMachineCallbacks {
820     /// Call all registered callbacks to notify that the payload has started.
notify_payload_started(&self, cid: Cid, stream: Option<VsockStream>)821     pub fn notify_payload_started(&self, cid: Cid, stream: Option<VsockStream>) {
822         let callbacks = &*self.0.lock().unwrap();
823         let pfd = stream.map(vsock_stream_to_pfd);
824         for callback in callbacks {
825             if let Err(e) = callback.onPayloadStarted(cid as i32, pfd.as_ref()) {
826                 error!("Error notifying payload start event from VM CID {}: {}", cid, e);
827             }
828         }
829     }
830 
831     /// Call all registered callbacks to notify that the payload is ready to serve.
notify_payload_ready(&self, cid: Cid)832     pub fn notify_payload_ready(&self, cid: Cid) {
833         let callbacks = &*self.0.lock().unwrap();
834         for callback in callbacks {
835             if let Err(e) = callback.onPayloadReady(cid as i32) {
836                 error!("Error notifying payload ready event from VM CID {}: {}", cid, e);
837             }
838         }
839     }
840 
841     /// Call all registered callbacks to notify that the payload has finished.
notify_payload_finished(&self, cid: Cid, exit_code: i32)842     pub fn notify_payload_finished(&self, cid: Cid, exit_code: i32) {
843         let callbacks = &*self.0.lock().unwrap();
844         for callback in callbacks {
845             if let Err(e) = callback.onPayloadFinished(cid as i32, exit_code) {
846                 error!("Error notifying payload finish event from VM CID {}: {}", cid, e);
847             }
848         }
849     }
850 
851     /// Call all registered callbacks to say that the VM encountered an error.
notify_error(&self, cid: Cid, error_code: i32, message: &str)852     pub fn notify_error(&self, cid: Cid, error_code: i32, message: &str) {
853         let callbacks = &*self.0.lock().unwrap();
854         for callback in callbacks {
855             if let Err(e) = callback.onError(cid as i32, error_code, message) {
856                 error!("Error notifying error event from VM CID {}: {}", cid, e);
857             }
858         }
859     }
860 
861     /// Call all registered callbacks to say that the VM has died.
callback_on_died(&self, cid: Cid, reason: DeathReason)862     pub fn callback_on_died(&self, cid: Cid, reason: DeathReason) {
863         let callbacks = &*self.0.lock().unwrap();
864         for callback in callbacks {
865             if let Err(e) = callback.onDied(cid as i32, reason) {
866                 error!("Error notifying exit of VM CID {}: {}", cid, e);
867             }
868         }
869     }
870 
871     /// Add a new callback to the set.
add(&self, callback: Strong<dyn IVirtualMachineCallback>)872     fn add(&self, callback: Strong<dyn IVirtualMachineCallback>) {
873         self.0.lock().unwrap().push(callback);
874     }
875 }
876 
877 /// The mutable state of the VirtualizationService. There should only be one instance of this
878 /// struct.
879 #[derive(Debug, Default)]
880 struct State {
881     /// The VMs which have been started. When VMs are started a weak reference is added to this list
882     /// while a strong reference is returned to the caller over Binder. Once all copies of the
883     /// Binder client are dropped the weak reference here will become invalid, and will be removed
884     /// from the list opportunistically the next time `add_vm` is called.
885     vms: Vec<Weak<VmInstance>>,
886 
887     /// Vector of strong VM references held on behalf of users that cannot hold them themselves.
888     /// This is only used for debugging purposes.
889     debug_held_vms: Vec<Strong<dyn IVirtualMachine>>,
890 }
891 
892 impl State {
893     /// Get a list of VMs which still have Binder references to them.
vms(&self) -> Vec<Arc<VmInstance>>894     fn vms(&self) -> Vec<Arc<VmInstance>> {
895         // Attempt to upgrade the weak pointers to strong pointers.
896         self.vms.iter().filter_map(Weak::upgrade).collect()
897     }
898 
899     /// Add a new VM to the list.
add_vm(&mut self, vm: Weak<VmInstance>)900     fn add_vm(&mut self, vm: Weak<VmInstance>) {
901         // Garbage collect any entries from the stored list which no longer exist.
902         self.vms.retain(|vm| vm.strong_count() > 0);
903 
904         // Actually add the new VM.
905         self.vms.push(vm);
906     }
907 
908     /// Get a VM that corresponds to the given cid
get_vm(&self, cid: Cid) -> Option<Arc<VmInstance>>909     fn get_vm(&self, cid: Cid) -> Option<Arc<VmInstance>> {
910         self.vms().into_iter().find(|vm| vm.cid == cid)
911     }
912 
913     /// Store a strong VM reference.
debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>)914     fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
915         self.debug_held_vms.push(vm);
916     }
917 
918     /// Retrieve and remove a strong VM reference.
debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>>919     fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
920         let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
921         let vm = self.debug_held_vms.swap_remove(pos);
922         Some(vm)
923     }
924 }
925 
926 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
927 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
928 /// Android is up.
next_cid() -> Result<Cid>929 fn next_cid() -> Result<Cid> {
930     let next = if let Some(val) = system_properties::read(SYSPROP_LAST_CID)? {
931         if let Ok(num) = val.parse::<u32>() {
932             num.checked_add(1).ok_or_else(|| anyhow!("run out of CID"))?
933         } else {
934             error!("Invalid last CID {}. Using {}", &val, FIRST_GUEST_CID);
935             FIRST_GUEST_CID
936         }
937     } else {
938         // First VM since the boot
939         FIRST_GUEST_CID
940     };
941     // Persist the last value for next use
942     let str_val = format!("{}", next);
943     system_properties::write(SYSPROP_LAST_CID, &str_val)?;
944     Ok(next)
945 }
946 
947 /// Gets the `VirtualMachineState` of the given `VmInstance`.
get_state(instance: &VmInstance) -> VirtualMachineState948 fn get_state(instance: &VmInstance) -> VirtualMachineState {
949     match &*instance.vm_state.lock().unwrap() {
950         VmState::NotStarted { .. } => VirtualMachineState::NOT_STARTED,
951         VmState::Running { .. } => match instance.payload_state() {
952             PayloadState::Starting => VirtualMachineState::STARTING,
953             PayloadState::Started => VirtualMachineState::STARTED,
954             PayloadState::Ready => VirtualMachineState::READY,
955             PayloadState::Finished => VirtualMachineState::FINISHED,
956         },
957         VmState::Dead => VirtualMachineState::DEAD,
958         VmState::Failed => VirtualMachineState::DEAD,
959     }
960 }
961 
962 /// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file.
clone_file(file: &ParcelFileDescriptor) -> Result<File, Status>963 fn clone_file(file: &ParcelFileDescriptor) -> Result<File, Status> {
964     file.as_ref().try_clone().map_err(|e| {
965         new_binder_exception(
966             ExceptionCode::BAD_PARCELABLE,
967             format!("Failed to clone File from ParcelFileDescriptor: {}", e),
968         )
969     })
970 }
971 
972 /// Converts an `&Option<ParcelFileDescriptor>` to an `Option<File>` by cloning the file.
maybe_clone_file(file: &Option<ParcelFileDescriptor>) -> Result<Option<File>, Status>973 fn maybe_clone_file(file: &Option<ParcelFileDescriptor>) -> Result<Option<File>, Status> {
974     file.as_ref().map(clone_file).transpose()
975 }
976 
977 /// Converts a `VsockStream` to a `ParcelFileDescriptor`.
vsock_stream_to_pfd(stream: VsockStream) -> ParcelFileDescriptor978 fn vsock_stream_to_pfd(stream: VsockStream) -> ParcelFileDescriptor {
979     // SAFETY: ownership is transferred from stream to f
980     let f = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
981     ParcelFileDescriptor::new(f)
982 }
983 
984 /// Parses the platform version requirement string.
parse_platform_version_req(s: &str) -> Result<VersionReq, Status>985 fn parse_platform_version_req(s: &str) -> Result<VersionReq, Status> {
986     VersionReq::parse(s).map_err(|e| {
987         new_binder_exception(
988             ExceptionCode::BAD_PARCELABLE,
989             format!("Invalid platform version requirement {}: {}", s, e),
990         )
991     })
992 }
993 
994 /// Simple utility for referencing Borrowed or Owned. Similar to std::borrow::Cow, but
995 /// it doesn't require that T implements Clone.
996 enum BorrowedOrOwned<'a, T> {
997     Borrowed(&'a T),
998     Owned(T),
999 }
1000 
1001 impl<'a, T> AsRef<T> for BorrowedOrOwned<'a, T> {
as_ref(&self) -> &T1002     fn as_ref(&self) -> &T {
1003         match self {
1004             Self::Borrowed(b) => b,
1005             Self::Owned(o) => o,
1006         }
1007     }
1008 }
1009 
1010 /// Implementation of `IVirtualMachineService`, the entry point of the AIDL service.
1011 #[derive(Debug, Default)]
1012 struct VirtualMachineService {
1013     state: Arc<Mutex<State>>,
1014     cid: Cid,
1015 }
1016 
1017 impl Interface for VirtualMachineService {}
1018 
1019 impl IVirtualMachineService for VirtualMachineService {
notifyPayloadStarted(&self) -> binder::Result<()>1020     fn notifyPayloadStarted(&self) -> binder::Result<()> {
1021         let cid = self.cid;
1022         if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
1023             info!("VM having CID {} started payload", cid);
1024             vm.update_payload_state(PayloadState::Started)
1025                 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
1026             let stream = vm.stream.lock().unwrap().take();
1027             vm.callbacks.notify_payload_started(cid, stream);
1028             Ok(())
1029         } else {
1030             error!("notifyPayloadStarted is called from an unknown CID {}", cid);
1031             Err(new_binder_exception(
1032                 ExceptionCode::SERVICE_SPECIFIC,
1033                 format!("cannot find a VM with CID {}", cid),
1034             ))
1035         }
1036     }
1037 
notifyPayloadReady(&self) -> binder::Result<()>1038     fn notifyPayloadReady(&self) -> binder::Result<()> {
1039         let cid = self.cid;
1040         if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
1041             info!("VM having CID {} payload is ready", cid);
1042             vm.update_payload_state(PayloadState::Ready)
1043                 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
1044             vm.callbacks.notify_payload_ready(cid);
1045             Ok(())
1046         } else {
1047             error!("notifyPayloadReady is called from an unknown CID {}", cid);
1048             Err(new_binder_exception(
1049                 ExceptionCode::SERVICE_SPECIFIC,
1050                 format!("cannot find a VM with CID {}", cid),
1051             ))
1052         }
1053     }
1054 
notifyPayloadFinished(&self, exit_code: i32) -> binder::Result<()>1055     fn notifyPayloadFinished(&self, exit_code: i32) -> binder::Result<()> {
1056         let cid = self.cid;
1057         if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
1058             info!("VM having CID {} finished payload", cid);
1059             vm.update_payload_state(PayloadState::Finished)
1060                 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
1061             vm.callbacks.notify_payload_finished(cid, exit_code);
1062             Ok(())
1063         } else {
1064             error!("notifyPayloadFinished is called from an unknown CID {}", cid);
1065             Err(new_binder_exception(
1066                 ExceptionCode::SERVICE_SPECIFIC,
1067                 format!("cannot find a VM with CID {}", cid),
1068             ))
1069         }
1070     }
1071 
notifyError(&self, error_code: i32, message: &str) -> binder::Result<()>1072     fn notifyError(&self, error_code: i32, message: &str) -> binder::Result<()> {
1073         let cid = self.cid;
1074         if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
1075             info!("VM having CID {} encountered an error", cid);
1076             vm.update_payload_state(PayloadState::Finished)
1077                 .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))?;
1078             vm.callbacks.notify_error(cid, error_code, message);
1079             Ok(())
1080         } else {
1081             error!("notifyPayloadStarted is called from an unknown CID {}", cid);
1082             Err(new_binder_exception(
1083                 ExceptionCode::SERVICE_SPECIFIC,
1084                 format!("cannot find a VM with CID {}", cid),
1085             ))
1086         }
1087     }
1088 }
1089 
1090 impl VirtualMachineService {
1091     // SAFETY: Service ownership is held by state, and the binder objects are threadsafe.
factory( cid: Cid, context: *mut raw::c_void, ) -> *mut binder_rpc_unstable_bindgen::AIBinder1092     pub unsafe extern "C" fn factory(
1093         cid: Cid,
1094         context: *mut raw::c_void,
1095     ) -> *mut binder_rpc_unstable_bindgen::AIBinder {
1096         let state_ptr = context as *mut Arc<Mutex<State>>;
1097         let state = state_ptr.as_ref().unwrap();
1098         if let Some(vm) = state.lock().unwrap().get_vm(cid) {
1099             let mut vm_service = vm.vm_service.lock().unwrap();
1100             let service = vm_service.get_or_insert_with(|| Self::new_binder(state.clone(), cid));
1101             service.as_binder().as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder
1102         } else {
1103             error!("connection from cid={} is not from a guest VM", cid);
1104             null_mut()
1105         }
1106     }
1107 
new_binder(state: Arc<Mutex<State>>, cid: Cid) -> Strong<dyn IVirtualMachineService>1108     fn new_binder(state: Arc<Mutex<State>>, cid: Cid) -> Strong<dyn IVirtualMachineService> {
1109         BnVirtualMachineService::new_binder(
1110             VirtualMachineService { state, cid },
1111             BinderFeatures::default(),
1112         )
1113     }
1114 }
1115