blob: ff8ab301e2185dc7b209182fa2f8a87e8766aa5f [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};
David Brazdil3c2ddef2021-03-18 13:09:57 +000020use ::binder::FromIBinder; // TODO(dbrazdil): remove once b/182890877 is fixed
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000021use android_system_virtmanager::aidl::android::system::virtmanager::IVirtManager::IVirtManager;
22use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachine::{
23 BnVirtualMachine, IVirtualMachine,
24};
Andrew Walbran320b5602021-03-04 16:11:12 +000025use android_system_virtmanager::aidl::android::system::virtmanager::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
Andrew Walbrana89fc132021-03-17 17:08:36 +000026use android_system_virtmanager::binder::{
27 self, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
28};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000029use log::error;
Andrew Walbrana89fc132021-03-17 17:08:36 +000030use std::fs::File;
Andrew Walbran320b5602021-03-04 16:11:12 +000031use std::sync::{Arc, Mutex, Weak};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000032
33pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
34
Andrew Walbran320b5602021-03-04 16:11:12 +000035// TODO(qwandor): Use PermissionController once it is available to Rust.
36/// Only processes running with one of these UIDs are allowed to call debug methods.
37const DEBUG_ALLOWED_UIDS: [u32; 2] = [0, 2000];
38
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000039/// Implementation of `IVirtManager`, the entry point of the AIDL service.
40#[derive(Debug, Default)]
41pub struct VirtManager {
Andrew Walbran9c01baa2021-03-08 18:23:50 +000042 state: Mutex<State>,
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000043}
44
45impl Interface for VirtManager {}
46
47impl IVirtManager for VirtManager {
48 /// Create and start a new VM with the given configuration, assigning it the next available CID.
49 ///
50 /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client.
Andrew Walbrana89fc132021-03-17 17:08:36 +000051 fn startVm(
52 &self,
Andrew Walbran06b5f5c2021-03-31 12:34:13 +000053 config_fd: &ParcelFileDescriptor,
Andrew Walbrana89fc132021-03-17 17:08:36 +000054 log_fd: Option<&ParcelFileDescriptor>,
55 ) -> binder::Result<Strong<dyn IVirtualMachine>> {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000056 let state = &mut *self.state.lock().unwrap();
57 let cid = state.next_cid;
Andrew Walbrana89fc132021-03-17 17:08:36 +000058 let log_fd = log_fd
59 .map(|fd| fd.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR))
60 .transpose()?;
Andrew Walbran06b5f5c2021-03-31 12:34:13 +000061 let instance = Arc::new(start_vm(config_fd.as_ref(), cid, log_fd)?);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000062 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
63 state.next_cid = state.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
Andrew Walbran320b5602021-03-04 16:11:12 +000064 state.add_vm(Arc::downgrade(&instance));
65 Ok(VirtualMachine::create(instance))
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000066 }
Andrew Walbran320b5602021-03-04 16:11:12 +000067
68 /// Get a list of all currently running VMs. This method is only intended for debug purposes,
69 /// and as such is only permitted from the shell user.
70 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
71 if !debug_access_allowed() {
72 return Err(StatusCode::PERMISSION_DENIED.into());
73 }
74
75 let state = &mut *self.state.lock().unwrap();
76 let vms = state.vms();
Andrew Walbran06b5f5c2021-03-31 12:34:13 +000077 let cids =
78 vms.into_iter().map(|vm| VirtualMachineDebugInfo { cid: vm.cid as i32 }).collect();
Andrew Walbran320b5602021-03-04 16:11:12 +000079 Ok(cids)
80 }
David Brazdil3c2ddef2021-03-18 13:09:57 +000081
82 /// Hold a strong reference to a VM in Virt Manager. This method is only intended for debug
83 /// purposes, and as such is only permitted from the shell user.
84 fn debugHoldVmRef(&self, vmref: &dyn IVirtualMachine) -> binder::Result<()> {
85 if !debug_access_allowed() {
86 return Err(StatusCode::PERMISSION_DENIED.into());
87 }
88
89 // Workaround for b/182890877.
90 let vm: Strong<dyn IVirtualMachine> = FromIBinder::try_from(vmref.as_binder()).unwrap();
91
92 let state = &mut *self.state.lock().unwrap();
93 state.debug_hold_vm(vm);
94 Ok(())
95 }
96
97 /// Drop reference to a VM that is being held by Virt Manager. Returns the reference if VM was
98 /// found and None otherwise. This method is only intended for debug purposes, and as such is
99 /// only permitted from the shell user.
100 fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> {
101 if !debug_access_allowed() {
102 return Err(StatusCode::PERMISSION_DENIED.into());
103 }
104
105 let state = &mut *self.state.lock().unwrap();
106 Ok(state.debug_drop_vm(cid))
107 }
Andrew Walbran320b5602021-03-04 16:11:12 +0000108}
109
110/// Check whether the caller of the current Binder method is allowed to call debug methods.
111fn debug_access_allowed() -> bool {
112 let uid = ThreadState::get_calling_uid();
113 log::trace!("Debug method call from UID {}.", uid);
114 DEBUG_ALLOWED_UIDS.contains(&uid)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000115}
116
117/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
118#[derive(Debug)]
119struct VirtualMachine {
120 instance: Arc<VmInstance>,
121}
122
123impl VirtualMachine {
124 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
125 let binder = VirtualMachine { instance };
126 BnVirtualMachine::new_binder(binder)
127 }
128}
129
130impl Interface for VirtualMachine {}
131
132impl IVirtualMachine for VirtualMachine {
133 fn getCid(&self) -> binder::Result<i32> {
134 Ok(self.instance.cid as i32)
135 }
136}
137
138/// The mutable state of the Virt Manager. There should only be one instance of this struct.
139#[derive(Debug)]
140struct State {
Andrew Walbran320b5602021-03-04 16:11:12 +0000141 /// The next available unused CID.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000142 next_cid: Cid,
Andrew Walbran320b5602021-03-04 16:11:12 +0000143
144 /// The VMs which have been started. When VMs are started a weak reference is added to this list
145 /// while a strong reference is returned to the caller over Binder. Once all copies of the
146 /// Binder client are dropped the weak reference here will become invalid, and will be removed
147 /// from the list opportunistically the next time `add_vm` is called.
148 vms: Vec<Weak<VmInstance>>,
David Brazdil3c2ddef2021-03-18 13:09:57 +0000149
150 /// Vector of strong VM references held on behalf of users that cannot hold them themselves.
151 /// This is only used for debugging purposes.
152 debug_held_vms: Vec<Strong<dyn IVirtualMachine>>,
Andrew Walbran320b5602021-03-04 16:11:12 +0000153}
154
155impl State {
156 /// Get a list of VMs which are currently running.
157 fn vms(&self) -> Vec<Arc<VmInstance>> {
158 // Attempt to upgrade the weak pointers to strong pointers.
159 self.vms.iter().filter_map(Weak::upgrade).collect()
160 }
161
162 /// Add a new VM to the list.
163 fn add_vm(&mut self, vm: Weak<VmInstance>) {
164 // Garbage collect any entries from the stored list which no longer exist.
165 self.vms.retain(|vm| vm.strong_count() > 0);
166
167 // Actually add the new VM.
168 self.vms.push(vm);
169 }
David Brazdil3c2ddef2021-03-18 13:09:57 +0000170
171 /// Store a strong VM reference.
172 fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
173 self.debug_held_vms.push(vm);
174 }
175
176 /// Retrieve and remove a strong VM reference.
177 fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
178 let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
179 Some(self.debug_held_vms.swap_remove(pos))
180 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000181}
182
183impl Default for State {
184 fn default() -> Self {
David Brazdil3c2ddef2021-03-18 13:09:57 +0000185 State { next_cid: FIRST_GUEST_CID, vms: vec![], debug_held_vms: vec![] }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000186 }
187}
188
189/// Start a new VM instance from the given VM config filename. This assumes the VM is not already
190/// running.
Andrew Walbran06b5f5c2021-03-31 12:34:13 +0000191fn start_vm(config_file: &File, cid: Cid, log_fd: Option<File>) -> binder::Result<VmInstance> {
192 let config = VmConfig::load(config_file).map_err(|e| {
193 error!("Failed to load VM config from {:?}: {:?}", config_file, e);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000194 StatusCode::BAD_VALUE
195 })?;
Andrew Walbran06b5f5c2021-03-31 12:34:13 +0000196 Ok(VmInstance::start(&config, cid, log_fd).map_err(|e| {
197 error!("Failed to start VM from {:?}: {:?}", config_file, e);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000198 StatusCode::UNKNOWN_ERROR
199 })?)
200}