blob: 5a1744fbcb1da0e6d8b69e935305a91228520224 [file] [log] [blame]
Alice Wangc206b9b2023-08-28 14:13:51 +00001// Copyright 2023, 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//! Service VM.
16
17use android_system_virtualizationservice::{
18 aidl::android::system::virtualizationservice::{
19 CpuTopology::CpuTopology, DiskImage::DiskImage,
20 IVirtualizationService::IVirtualizationService, Partition::Partition,
21 PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
22 VirtualMachineRawConfig::VirtualMachineRawConfig,
23 },
24 binder::ParcelFileDescriptor,
25};
26use anyhow::{Context, Result};
27use log::info;
28use std::fs::{File, OpenOptions};
29use std::path::Path;
30use vmclient::VmInstance;
31
32const VIRT_DATA_DIR: &str = "/data/misc/apexdata/com.android.virt";
33const RIALTO_PATH: &str = "/apex/com.android.virt/etc/rialto.bin";
34const INSTANCE_IMG_NAME: &str = "service_vm_instance.img";
35const INSTANCE_IMG_SIZE_BYTES: i64 = 1 << 20; // 1MB
36const MEMORY_MB: i32 = 300;
37
38/// Starts the service VM and returns its instance.
39/// The same instance image is used for different VMs.
40/// TODO(b/278858244): Allow only one service VM running at each time.
41pub fn start() -> Result<VmInstance> {
42 let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn VirtMgr")?;
43 let service = virtmgr.connect().context("Failed to connect to VirtMgr")?;
44 info!("Connected to VirtMgr for service VM");
45
46 let vm = vm_instance(service.as_ref())?;
47
48 vm.start().context("Failed to start service VM")?;
49 info!("Service VM started");
50 Ok(vm)
51}
52
53fn vm_instance(service: &dyn IVirtualizationService) -> Result<VmInstance> {
54 let instance_img = instance_img(service)?;
55 let writable_partitions = vec![Partition {
56 label: "vm-instance".to_owned(),
57 image: Some(instance_img),
58 writable: true,
59 }];
60 let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
61 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
62 name: String::from("Service VM"),
63 bootloader: Some(ParcelFileDescriptor::new(rialto)),
64 disks: vec![DiskImage { image: None, partitions: writable_partitions, writable: true }],
65 protectedVm: true,
66 memoryMib: MEMORY_MB,
67 cpuTopology: CpuTopology::ONE_CPU,
68 platformVersion: "~1.0".to_string(),
69 gdbPort: 0, // No gdb
70 ..Default::default()
71 });
72 let console_out = None;
73 let console_in = None;
74 let log = None;
75 let callback = None;
76 VmInstance::create(service, &config, console_out, console_in, log, callback)
77 .context("Failed to create service VM")
78}
79
80fn instance_img(service: &dyn IVirtualizationService) -> Result<ParcelFileDescriptor> {
81 let instance_img_path = Path::new(VIRT_DATA_DIR).join(INSTANCE_IMG_NAME);
82 if instance_img_path.exists() {
83 // TODO(b/298174584): Try to recover if the service VM is triggered by rkpd.
84 return Ok(OpenOptions::new()
85 .read(true)
86 .write(true)
87 .open(instance_img_path)
88 .map(ParcelFileDescriptor::new)?);
89 }
90 let instance_img = OpenOptions::new()
91 .create(true)
92 .read(true)
93 .write(true)
94 .open(instance_img_path)
95 .map(ParcelFileDescriptor::new)?;
96 service.initializeWritablePartition(
97 &instance_img,
98 INSTANCE_IMG_SIZE_BYTES,
99 PartitionType::ANDROID_VM_INSTANCE,
100 )?;
101 Ok(instance_img)
102}