blob: ef973d1535500fd73d8e18b47046ce3f2b0a1f0d [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
Andrew Walbranf6bf6862021-05-21 12:41:13 +000015//! Implementation of the AIDL interface of the VirtualizationService.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000016
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000017use crate::crosvm::VmInstance;
18use crate::{Cid, FIRST_GUEST_CID};
Andrew Walbranf6bf6862021-05-21 12:41:13 +000019use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
20use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachine::{
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000021 BnVirtualMachine, IVirtualMachine,
22};
Andrew Walbranf6bf6862021-05-21 12:41:13 +000023use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachineCallback::IVirtualMachineCallback;
24use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineConfig::VirtualMachineConfig;
25use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
26use android_system_virtualizationservice::binder::{
Andrew Walbran4de28782021-04-13 14:51:43 +000027 self, BinderFeatures, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
Andrew Walbrana89fc132021-03-17 17:08:36 +000028};
Andrew Walbrandae07162021-03-12 17:05:20 +000029use log::{debug, error};
Andrew Walbran320b5602021-03-04 16:11:12 +000030use std::sync::{Arc, Mutex, Weak};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000031
Andrew Walbranf6bf6862021-05-21 12:41:13 +000032pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000033
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 Walbranf6bf6862021-05-21 12:41:13 +000038/// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000039#[derive(Debug, Default)]
Andrew Walbranf6bf6862021-05-21 12:41:13 +000040pub struct VirtualizationService {
Andrew Walbran9c01baa2021-03-08 18:23:50 +000041 state: Mutex<State>,
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000042}
43
Andrew Walbranf6bf6862021-05-21 12:41:13 +000044impl Interface for VirtualizationService {}
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000045
Andrew Walbranf6bf6862021-05-21 12:41:13 +000046impl IVirtualizationService for VirtualizationService {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000047 /// 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,
Andrew Walbran3a5a9212021-05-04 17:09:08 +000052 config: &VirtualMachineConfig,
Andrew Walbrana89fc132021-03-17 17:08:36 +000053 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();
Andrew Walbrana89fc132021-03-17 17:08:36 +000056 let log_fd = log_fd
57 .map(|fd| fd.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR))
58 .transpose()?;
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000059 let requester_uid = ThreadState::get_calling_uid();
60 let requester_sid = ThreadState::with_calling_sid(|sid| {
Andrew Walbran02034492021-04-13 15:05:07 +000061 if let Some(sid) = sid {
62 match sid.to_str() {
63 Ok(sid) => Ok(sid.to_owned()),
64 Err(e) => {
65 error!("SID was not valid UTF-8: {:?}", e);
66 Err(StatusCode::BAD_VALUE)
67 }
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000068 }
Andrew Walbran02034492021-04-13 15:05:07 +000069 } else {
70 error!("Missing SID on startVm");
71 Err(StatusCode::UNKNOWN_ERROR)
72 }
73 })?;
74 let requester_debug_pid = ThreadState::get_calling_pid();
Andrew Walbrandae07162021-03-12 17:05:20 +000075 let cid = state.allocate_cid()?;
Andrew Walbran3a5a9212021-05-04 17:09:08 +000076 let instance = VmInstance::start(
77 config,
Andrew Walbran02034492021-04-13 15:05:07 +000078 cid,
79 log_fd,
80 requester_uid,
81 requester_sid,
82 requester_debug_pid,
Andrew Walbran3a5a9212021-05-04 17:09:08 +000083 )
84 .map_err(|e| {
85 error!("Failed to start VM with config {:?}: {:?}", config, e);
86 StatusCode::UNKNOWN_ERROR
87 })?;
Andrew Walbran320b5602021-03-04 16:11:12 +000088 state.add_vm(Arc::downgrade(&instance));
89 Ok(VirtualMachine::create(instance))
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000090 }
Andrew Walbran320b5602021-03-04 16:11:12 +000091
92 /// Get a list of all currently running VMs. This method is only intended for debug purposes,
93 /// and as such is only permitted from the shell user.
94 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
95 if !debug_access_allowed() {
96 return Err(StatusCode::PERMISSION_DENIED.into());
97 }
98
99 let state = &mut *self.state.lock().unwrap();
100 let vms = state.vms();
Andrew Walbranf6a1eb92021-04-01 11:16:02 +0000101 let cids = vms
102 .into_iter()
103 .map(|vm| VirtualMachineDebugInfo {
104 cid: vm.cid as i32,
Andrew Walbran1ef19ae2021-04-07 11:31:57 +0000105 requesterUid: vm.requester_uid as i32,
106 requesterSid: vm.requester_sid.clone(),
Andrew Walbran02034492021-04-13 15:05:07 +0000107 requesterPid: vm.requester_debug_pid,
Andrew Walbrandae07162021-03-12 17:05:20 +0000108 running: vm.running(),
Andrew Walbranf6a1eb92021-04-01 11:16:02 +0000109 })
110 .collect();
Andrew Walbran320b5602021-03-04 16:11:12 +0000111 Ok(cids)
112 }
David Brazdil3c2ddef2021-03-18 13:09:57 +0000113
Andrew Walbranf6bf6862021-05-21 12:41:13 +0000114 /// Hold a strong reference to a VM in VirtualizationService. This method is only intended for
115 /// debug purposes, and as such is only permitted from the shell user.
Andrei Homescu1415c132021-03-24 02:39:55 +0000116 fn debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()> {
David Brazdil3c2ddef2021-03-18 13:09:57 +0000117 if !debug_access_allowed() {
118 return Err(StatusCode::PERMISSION_DENIED.into());
119 }
120
David Brazdil3c2ddef2021-03-18 13:09:57 +0000121 let state = &mut *self.state.lock().unwrap();
Andrei Homescu1415c132021-03-24 02:39:55 +0000122 state.debug_hold_vm(vmref.clone());
David Brazdil3c2ddef2021-03-18 13:09:57 +0000123 Ok(())
124 }
125
Andrew Walbranf6bf6862021-05-21 12:41:13 +0000126 /// Drop reference to a VM that is being held by VirtualizationService. Returns the reference if
127 /// the VM was found and None otherwise. This method is only intended for debug purposes, and as
128 /// such is only permitted from the shell user.
David Brazdil3c2ddef2021-03-18 13:09:57 +0000129 fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> {
130 if !debug_access_allowed() {
131 return Err(StatusCode::PERMISSION_DENIED.into());
132 }
133
134 let state = &mut *self.state.lock().unwrap();
135 Ok(state.debug_drop_vm(cid))
136 }
Andrew Walbran320b5602021-03-04 16:11:12 +0000137}
138
139/// Check whether the caller of the current Binder method is allowed to call debug methods.
140fn debug_access_allowed() -> bool {
141 let uid = ThreadState::get_calling_uid();
142 log::trace!("Debug method call from UID {}.", uid);
143 DEBUG_ALLOWED_UIDS.contains(&uid)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000144}
145
146/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
147#[derive(Debug)]
148struct VirtualMachine {
149 instance: Arc<VmInstance>,
150}
151
152impl VirtualMachine {
153 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
154 let binder = VirtualMachine { instance };
Andrew Walbran4de28782021-04-13 14:51:43 +0000155 BnVirtualMachine::new_binder(binder, BinderFeatures::default())
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000156 }
157}
158
159impl Interface for VirtualMachine {}
160
161impl IVirtualMachine for VirtualMachine {
162 fn getCid(&self) -> binder::Result<i32> {
163 Ok(self.instance.cid as i32)
164 }
Andrew Walbrandae07162021-03-12 17:05:20 +0000165
166 fn isRunning(&self) -> binder::Result<bool> {
167 Ok(self.instance.running())
168 }
169
170 fn registerCallback(
171 &self,
172 callback: &Strong<dyn IVirtualMachineCallback>,
173 ) -> binder::Result<()> {
174 // TODO: Should this give an error if the VM is already dead?
175 self.instance.callbacks.add(callback.clone());
176 Ok(())
177 }
178}
179
180impl Drop for VirtualMachine {
181 fn drop(&mut self) {
182 debug!("Dropping {:?}", self);
183 self.instance.kill();
184 }
185}
186
187/// A set of Binders to be called back in response to various events on the VM, such as when it
188/// dies.
189#[derive(Debug, Default)]
190pub struct VirtualMachineCallbacks(Mutex<Vec<Strong<dyn IVirtualMachineCallback>>>);
191
192impl VirtualMachineCallbacks {
193 /// Call all registered callbacks to say that the VM has died.
194 pub fn callback_on_died(&self, cid: Cid) {
195 let callbacks = &*self.0.lock().unwrap();
196 for callback in callbacks {
197 if let Err(e) = callback.onDied(cid as i32) {
198 error!("Error calling callback: {}", e);
199 }
200 }
201 }
202
203 /// Add a new callback to the set.
204 fn add(&self, callback: Strong<dyn IVirtualMachineCallback>) {
205 self.0.lock().unwrap().push(callback);
206 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000207}
208
Andrew Walbranf6bf6862021-05-21 12:41:13 +0000209/// The mutable state of the VirtualizationService. There should only be one instance of this
210/// struct.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000211#[derive(Debug)]
212struct State {
Andrew Walbran320b5602021-03-04 16:11:12 +0000213 /// The next available unused CID.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000214 next_cid: Cid,
Andrew Walbran320b5602021-03-04 16:11:12 +0000215
216 /// The VMs which have been started. When VMs are started a weak reference is added to this list
217 /// while a strong reference is returned to the caller over Binder. Once all copies of the
218 /// Binder client are dropped the weak reference here will become invalid, and will be removed
219 /// from the list opportunistically the next time `add_vm` is called.
220 vms: Vec<Weak<VmInstance>>,
David Brazdil3c2ddef2021-03-18 13:09:57 +0000221
222 /// Vector of strong VM references held on behalf of users that cannot hold them themselves.
223 /// This is only used for debugging purposes.
224 debug_held_vms: Vec<Strong<dyn IVirtualMachine>>,
Andrew Walbran320b5602021-03-04 16:11:12 +0000225}
226
227impl State {
Andrew Walbrandae07162021-03-12 17:05:20 +0000228 /// Get a list of VMs which still have Binder references to them.
Andrew Walbran320b5602021-03-04 16:11:12 +0000229 fn vms(&self) -> Vec<Arc<VmInstance>> {
230 // Attempt to upgrade the weak pointers to strong pointers.
231 self.vms.iter().filter_map(Weak::upgrade).collect()
232 }
233
234 /// Add a new VM to the list.
235 fn add_vm(&mut self, vm: Weak<VmInstance>) {
236 // Garbage collect any entries from the stored list which no longer exist.
237 self.vms.retain(|vm| vm.strong_count() > 0);
238
239 // Actually add the new VM.
240 self.vms.push(vm);
241 }
David Brazdil3c2ddef2021-03-18 13:09:57 +0000242
243 /// Store a strong VM reference.
244 fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
245 self.debug_held_vms.push(vm);
246 }
247
248 /// Retrieve and remove a strong VM reference.
249 fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
250 let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
251 Some(self.debug_held_vms.swap_remove(pos))
252 }
Andrew Walbrandae07162021-03-12 17:05:20 +0000253
254 /// Get the next available CID, or an error if we have run out.
255 fn allocate_cid(&mut self) -> binder::Result<Cid> {
256 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
257 let cid = self.next_cid;
258 self.next_cid = self.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
259 Ok(cid)
260 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000261}
262
263impl Default for State {
264 fn default() -> Self {
David Brazdil3c2ddef2021-03-18 13:09:57 +0000265 State { next_cid: FIRST_GUEST_CID, vms: vec![], debug_held_vms: vec![] }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000266 }
267}