blob: 810505177a9c3c05c68a98f1f58e481eb459c78e [file] [log] [blame]
Andrew Walbrand6dce6f2021-03-05 16:39:08 +00001// 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 Virt Manager.
16
Andrew Walbrana2f8c232021-03-11 11:46:53 +000017use crate::config::VmConfig;
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000018use crate::crosvm::VmInstance;
19use crate::{Cid, FIRST_GUEST_CID};
20use android_system_virtmanager::aidl::android::system::virtmanager::IVirtManager::IVirtManager;
21use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachine::{
22 BnVirtualMachine, IVirtualMachine,
23};
Andrew Walbran320b5602021-03-04 16:11:12 +000024use android_system_virtmanager::aidl::android::system::virtmanager::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
Andrew Walbrana89fc132021-03-17 17:08:36 +000025use android_system_virtmanager::binder::{
26 self, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
27};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000028use log::error;
Andrew Walbrana89fc132021-03-17 17:08:36 +000029use std::fs::File;
Andrew Walbran320b5602021-03-04 16:11:12 +000030use std::sync::{Arc, Mutex, Weak};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000031
32pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
33
Andrew Walbran320b5602021-03-04 16:11:12 +000034// TODO(qwandor): Use PermissionController once it is available to Rust.
35/// Only processes running with one of these UIDs are allowed to call debug methods.
36const DEBUG_ALLOWED_UIDS: [u32; 2] = [0, 2000];
37
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000038/// Implementation of `IVirtManager`, the entry point of the AIDL service.
39#[derive(Debug, Default)]
40pub struct VirtManager {
Andrew Walbran9c01baa2021-03-08 18:23:50 +000041 state: Mutex<State>,
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000042}
43
44impl Interface for VirtManager {}
45
46impl IVirtManager for VirtManager {
47 /// Create and start a new VM with the given configuration, assigning it the next available CID.
48 ///
49 /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client.
Andrew Walbrana89fc132021-03-17 17:08:36 +000050 fn startVm(
51 &self,
52 config_path: &str,
53 log_fd: Option<&ParcelFileDescriptor>,
54 ) -> binder::Result<Strong<dyn IVirtualMachine>> {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000055 let state = &mut *self.state.lock().unwrap();
56 let cid = state.next_cid;
Andrew Walbrana89fc132021-03-17 17:08:36 +000057 let log_fd = log_fd
58 .map(|fd| fd.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR))
59 .transpose()?;
60 let instance = Arc::new(start_vm(config_path, cid, log_fd)?);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000061 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
62 state.next_cid = state.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
Andrew Walbran320b5602021-03-04 16:11:12 +000063 state.add_vm(Arc::downgrade(&instance));
64 Ok(VirtualMachine::create(instance))
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000065 }
Andrew Walbran320b5602021-03-04 16:11:12 +000066
67 /// Get a list of all currently running VMs. This method is only intended for debug purposes,
68 /// and as such is only permitted from the shell user.
69 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
70 if !debug_access_allowed() {
71 return Err(StatusCode::PERMISSION_DENIED.into());
72 }
73
74 let state = &mut *self.state.lock().unwrap();
75 let vms = state.vms();
76 let cids = vms
77 .into_iter()
78 .map(|vm| VirtualMachineDebugInfo {
79 cid: vm.cid as i32,
80 configPath: vm.config_path.clone(),
81 })
82 .collect();
83 Ok(cids)
84 }
85}
86
87/// Check whether the caller of the current Binder method is allowed to call debug methods.
88fn debug_access_allowed() -> bool {
89 let uid = ThreadState::get_calling_uid();
90 log::trace!("Debug method call from UID {}.", uid);
91 DEBUG_ALLOWED_UIDS.contains(&uid)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000092}
93
94/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
95#[derive(Debug)]
96struct VirtualMachine {
97 instance: Arc<VmInstance>,
98}
99
100impl VirtualMachine {
101 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
102 let binder = VirtualMachine { instance };
103 BnVirtualMachine::new_binder(binder)
104 }
105}
106
107impl Interface for VirtualMachine {}
108
109impl IVirtualMachine for VirtualMachine {
110 fn getCid(&self) -> binder::Result<i32> {
111 Ok(self.instance.cid as i32)
112 }
113}
114
115/// The mutable state of the Virt Manager. There should only be one instance of this struct.
116#[derive(Debug)]
117struct State {
Andrew Walbran320b5602021-03-04 16:11:12 +0000118 /// The next available unused CID.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000119 next_cid: Cid,
Andrew Walbran320b5602021-03-04 16:11:12 +0000120
121 /// The VMs which have been started. When VMs are started a weak reference is added to this list
122 /// while a strong reference is returned to the caller over Binder. Once all copies of the
123 /// Binder client are dropped the weak reference here will become invalid, and will be removed
124 /// from the list opportunistically the next time `add_vm` is called.
125 vms: Vec<Weak<VmInstance>>,
126}
127
128impl State {
129 /// Get a list of VMs which are currently running.
130 fn vms(&self) -> Vec<Arc<VmInstance>> {
131 // Attempt to upgrade the weak pointers to strong pointers.
132 self.vms.iter().filter_map(Weak::upgrade).collect()
133 }
134
135 /// Add a new VM to the list.
136 fn add_vm(&mut self, vm: Weak<VmInstance>) {
137 // Garbage collect any entries from the stored list which no longer exist.
138 self.vms.retain(|vm| vm.strong_count() > 0);
139
140 // Actually add the new VM.
141 self.vms.push(vm);
142 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000143}
144
145impl Default for State {
146 fn default() -> Self {
Andrew Walbran320b5602021-03-04 16:11:12 +0000147 State { next_cid: FIRST_GUEST_CID, vms: vec![] }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000148 }
149}
150
151/// Start a new VM instance from the given VM config filename. This assumes the VM is not already
152/// running.
Andrew Walbrana89fc132021-03-17 17:08:36 +0000153fn start_vm(config_path: &str, cid: Cid, log_fd: Option<File>) -> binder::Result<VmInstance> {
Andrew Walbrana2f8c232021-03-11 11:46:53 +0000154 let config = VmConfig::load(config_path).map_err(|e| {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000155 error!("Failed to load VM config {}: {:?}", config_path, e);
156 StatusCode::BAD_VALUE
157 })?;
Andrew Walbrana89fc132021-03-17 17:08:36 +0000158 Ok(VmInstance::start(&config, cid, config_path, log_fd).map_err(|e| {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000159 error!("Failed to start VM {}: {:?}", config_path, e);
160 StatusCode::UNKNOWN_ERROR
161 })?)
162}