1 // Copyright 2025 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 //! Tests running an early VM
16
17 use android_system_virtualizationservice::{
18 aidl::android::system::virtualizationservice::{
19 IVirtualizationService::IVirtualizationService, VirtualMachineConfig::VirtualMachineConfig,
20 VirtualMachineRawConfig::VirtualMachineRawConfig,
21 },
22 binder::{ParcelFileDescriptor, ProcessState, Strong},
23 };
24 use anyhow::{Context, Result};
25 use clap::Parser;
26 use log::info;
27 use std::fs::File;
28 use std::path::PathBuf;
29
30 use service_vm_comm::{Request, Response, VmType};
31 use service_vm_manager::ServiceVm;
32 use vmclient::VmInstance;
33
34 const VM_MEMORY_MB: i32 = 16;
35
36 #[derive(Parser)]
37 /// Collection of CLI for avf_early_vm_test_rialto
38 pub struct Args {
39 /// Path to the Rialto kernel image.
40 #[arg(long)]
41 kernel: PathBuf,
42
43 /// Whether the VM is protected or not.
44 #[arg(long)]
45 protected: bool,
46 }
47
get_service() -> Result<Strong<dyn IVirtualizationService>>48 fn get_service() -> Result<Strong<dyn IVirtualizationService>> {
49 let virtmgr = vmclient::VirtualizationService::new_early()
50 .context("Failed to spawn VirtualizationService")?;
51 virtmgr.connect().context("Failed to connect to VirtualizationService")
52 }
53
main() -> Result<()>54 fn main() -> Result<()> {
55 if std::env::consts::ARCH != "aarch64" {
56 info!("{} not supported. skipping test", std::env::consts::ARCH);
57 return Ok(());
58 }
59
60 if !cfg!(early_vm_enabled) {
61 info!("early VM disabled. skipping test");
62 return Ok(());
63 }
64
65 let args = Args::parse();
66
67 if args.protected {
68 if !hypervisor_props::is_protected_vm_supported()? {
69 info!("pVMs are not supported on device. skipping test");
70 return Ok(());
71 }
72 } else if !hypervisor_props::is_vm_supported()? {
73 info!("non-pVMs are not supported on device. skipping test");
74 return Ok(());
75 }
76
77 let service = get_service()?;
78 let kernel =
79 File::open(&args.kernel).with_context(|| format!("Failed to open {:?}", &args.kernel))?;
80 let kernel = ParcelFileDescriptor::new(kernel);
81
82 let vm_config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
83 name: "avf_early_vm_test_launcher".to_owned(),
84 kernel: Some(kernel),
85 protectedVm: args.protected,
86 memoryMib: VM_MEMORY_MB,
87 platformVersion: "~1.0".to_owned(),
88 ..Default::default()
89 });
90
91 let vm_instance = VmInstance::create(
92 service.as_ref(),
93 &vm_config,
94 // console_in, console_out, and log will be redirected to the kernel log by virtmgr
95 None, // console_in
96 None, // console_out
97 None, // log
98 None, // dump_dt
99 )
100 .context("Failed to create VM")?;
101
102 ProcessState::start_thread_pool();
103
104 let vm_type = if args.protected { VmType::ProtectedVm } else { VmType::NonProtectedVm };
105 let mut vm_service = ServiceVm::start_vm(vm_instance, vm_type)?;
106
107 let request_data = vec![1, 2, 3, 4, 5];
108 let reversed_data = vec![5, 4, 3, 2, 1];
109 let response = vm_service
110 .process_request(Request::Reverse(request_data))
111 .context("Failed to process request")?;
112 assert_eq!(Response::Reverse(reversed_data), response);
113
114 Ok(())
115 }
116