blob: b7595a9057c33903fd02983338c096175425abd4 [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;
25use android_system_virtmanager::binder::{self, Interface, StatusCode, Strong, ThreadState};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000026use log::error;
Andrew Walbran320b5602021-03-04 16:11:12 +000027use std::sync::{Arc, Mutex, Weak};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000028
29pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
30
Andrew Walbran320b5602021-03-04 16:11:12 +000031// TODO(qwandor): Use PermissionController once it is available to Rust.
32/// Only processes running with one of these UIDs are allowed to call debug methods.
33const DEBUG_ALLOWED_UIDS: [u32; 2] = [0, 2000];
34
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000035/// Implementation of `IVirtManager`, the entry point of the AIDL service.
36#[derive(Debug, Default)]
37pub struct VirtManager {
Andrew Walbran9c01baa2021-03-08 18:23:50 +000038 state: Mutex<State>,
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000039}
40
41impl Interface for VirtManager {}
42
43impl IVirtManager for VirtManager {
44 /// Create and start a new VM with the given configuration, assigning it the next available CID.
45 ///
46 /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client.
47 fn startVm(&self, config_path: &str) -> binder::Result<Strong<dyn IVirtualMachine>> {
48 let state = &mut *self.state.lock().unwrap();
49 let cid = state.next_cid;
Andrew Walbran320b5602021-03-04 16:11:12 +000050 let instance = Arc::new(start_vm(config_path, cid)?);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000051 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
52 state.next_cid = state.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
Andrew Walbran320b5602021-03-04 16:11:12 +000053 state.add_vm(Arc::downgrade(&instance));
54 Ok(VirtualMachine::create(instance))
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000055 }
Andrew Walbran320b5602021-03-04 16:11:12 +000056
57 /// Get a list of all currently running VMs. This method is only intended for debug purposes,
58 /// and as such is only permitted from the shell user.
59 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
60 if !debug_access_allowed() {
61 return Err(StatusCode::PERMISSION_DENIED.into());
62 }
63
64 let state = &mut *self.state.lock().unwrap();
65 let vms = state.vms();
66 let cids = vms
67 .into_iter()
68 .map(|vm| VirtualMachineDebugInfo {
69 cid: vm.cid as i32,
70 configPath: vm.config_path.clone(),
71 })
72 .collect();
73 Ok(cids)
74 }
75}
76
77/// Check whether the caller of the current Binder method is allowed to call debug methods.
78fn debug_access_allowed() -> bool {
79 let uid = ThreadState::get_calling_uid();
80 log::trace!("Debug method call from UID {}.", uid);
81 DEBUG_ALLOWED_UIDS.contains(&uid)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000082}
83
84/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
85#[derive(Debug)]
86struct VirtualMachine {
87 instance: Arc<VmInstance>,
88}
89
90impl VirtualMachine {
91 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
92 let binder = VirtualMachine { instance };
93 BnVirtualMachine::new_binder(binder)
94 }
95}
96
97impl Interface for VirtualMachine {}
98
99impl IVirtualMachine for VirtualMachine {
100 fn getCid(&self) -> binder::Result<i32> {
101 Ok(self.instance.cid as i32)
102 }
103}
104
105/// The mutable state of the Virt Manager. There should only be one instance of this struct.
106#[derive(Debug)]
107struct State {
Andrew Walbran320b5602021-03-04 16:11:12 +0000108 /// The next available unused CID.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000109 next_cid: Cid,
Andrew Walbran320b5602021-03-04 16:11:12 +0000110
111 /// The VMs which have been started. When VMs are started a weak reference is added to this list
112 /// while a strong reference is returned to the caller over Binder. Once all copies of the
113 /// Binder client are dropped the weak reference here will become invalid, and will be removed
114 /// from the list opportunistically the next time `add_vm` is called.
115 vms: Vec<Weak<VmInstance>>,
116}
117
118impl State {
119 /// Get a list of VMs which are currently running.
120 fn vms(&self) -> Vec<Arc<VmInstance>> {
121 // Attempt to upgrade the weak pointers to strong pointers.
122 self.vms.iter().filter_map(Weak::upgrade).collect()
123 }
124
125 /// Add a new VM to the list.
126 fn add_vm(&mut self, vm: Weak<VmInstance>) {
127 // Garbage collect any entries from the stored list which no longer exist.
128 self.vms.retain(|vm| vm.strong_count() > 0);
129
130 // Actually add the new VM.
131 self.vms.push(vm);
132 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000133}
134
135impl Default for State {
136 fn default() -> Self {
Andrew Walbran320b5602021-03-04 16:11:12 +0000137 State { next_cid: FIRST_GUEST_CID, vms: vec![] }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000138 }
139}
140
141/// Start a new VM instance from the given VM config filename. This assumes the VM is not already
142/// running.
143fn start_vm(config_path: &str, cid: Cid) -> binder::Result<VmInstance> {
Andrew Walbrana2f8c232021-03-11 11:46:53 +0000144 let config = VmConfig::load(config_path).map_err(|e| {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000145 error!("Failed to load VM config {}: {:?}", config_path, e);
146 StatusCode::BAD_VALUE
147 })?;
Andrew Walbran320b5602021-03-04 16:11:12 +0000148 Ok(VmInstance::start(&config, cid, config_path).map_err(|e| {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000149 error!("Failed to start VM {}: {:?}", config_path, e);
150 StatusCode::UNKNOWN_ERROR
151 })?)
152}