xref: /aosp_15_r20/external/crosvm/devices/src/usb/backend/device_provider.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::HashMap;
6 use std::fs::File;
7 use std::mem;
8 use std::sync::Arc;
9 use std::time::Duration;
10 
11 use anyhow::Context;
12 use base::error;
13 use base::AsRawDescriptor;
14 use base::EventType;
15 use base::RawDescriptor;
16 use base::Tube;
17 use sync::Mutex;
18 use vm_control::UsbControlAttachedDevice;
19 use vm_control::UsbControlCommand;
20 use vm_control::UsbControlResult;
21 use vm_control::USB_CONTROL_MAX_PORTS;
22 
23 use crate::usb::backend::device::BackendDevice;
24 use crate::usb::backend::device::DeviceState;
25 use crate::usb::backend::error::Error;
26 use crate::usb::backend::error::Result;
27 use crate::usb::backend::fido_backend::fido_provider::attach_security_key;
28 use crate::usb::backend::host_backend::host_backend_device_provider::attach_host_backend_device;
29 use crate::usb::xhci::usb_hub::UsbHub;
30 use crate::usb::xhci::xhci_backend_device::XhciBackendDevice;
31 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
32 use crate::utils::AsyncJobQueue;
33 use crate::utils::EventHandler;
34 use crate::utils::EventLoop;
35 use crate::utils::FailHandle;
36 
37 const SOCKET_TIMEOUT_MS: u64 = 2000;
38 
39 /// Device provider is an xhci backend device provider that provides generic semantics to handle
40 /// various types of backend devices and connects them to the xhci layer.
41 pub enum DeviceProvider {
42     // The provider is created but not yet started.
43     Created { control_tube: Mutex<Tube> },
44     // The provider is started on an event loop.
45     Started { inner: Arc<ProviderInner> },
46     // The provider has failed.
47     Failed,
48 }
49 
50 impl DeviceProvider {
new() -> Result<(Tube, DeviceProvider)>51     pub fn new() -> Result<(Tube, DeviceProvider)> {
52         let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?;
53         control_tube
54             .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
55             .map_err(Error::SetupControlTube)?;
56         control_tube
57             .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
58             .map_err(Error::SetupControlTube)?;
59 
60         let provider = DeviceProvider::Created {
61             control_tube: Mutex::new(child_tube),
62         };
63         Ok((control_tube, provider))
64     }
65 
start_helper( &mut self, fail_handle: Arc<dyn FailHandle>, event_loop: Arc<EventLoop>, hub: Arc<UsbHub>, ) -> Result<()>66     fn start_helper(
67         &mut self,
68         fail_handle: Arc<dyn FailHandle>,
69         event_loop: Arc<EventLoop>,
70         hub: Arc<UsbHub>,
71     ) -> Result<()> {
72         match mem::replace(self, DeviceProvider::Failed) {
73             DeviceProvider::Created { control_tube } => {
74                 let job_queue =
75                     AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
76                 let inner = Arc::new(ProviderInner::new(
77                     fail_handle,
78                     job_queue,
79                     event_loop.clone(),
80                     control_tube,
81                     hub,
82                 ));
83                 let handler: Arc<dyn EventHandler> = inner.clone();
84                 event_loop
85                     .add_event(
86                         &*inner.control_tube.lock(),
87                         EventType::Read,
88                         Arc::downgrade(&handler),
89                     )
90                     .map_err(Error::AddToEventLoop)?;
91                 *self = DeviceProvider::Started { inner };
92                 Ok(())
93             }
94             DeviceProvider::Started { .. } => {
95                 error!("Usb device provider has already started");
96                 Err(Error::BadBackendProviderState)
97             }
98             DeviceProvider::Failed => {
99                 error!("Usb device provider has already failed");
100                 Err(Error::BadBackendProviderState)
101             }
102         }
103     }
104 }
105 
106 impl XhciBackendDeviceProvider for DeviceProvider {
start( &mut self, fail_handle: Arc<dyn FailHandle>, event_loop: Arc<EventLoop>, hub: Arc<UsbHub>, ) -> Result<()>107     fn start(
108         &mut self,
109         fail_handle: Arc<dyn FailHandle>,
110         event_loop: Arc<EventLoop>,
111         hub: Arc<UsbHub>,
112     ) -> Result<()> {
113         self.start_helper(fail_handle, event_loop, hub)
114     }
115 
keep_rds(&self) -> Vec<RawDescriptor>116     fn keep_rds(&self) -> Vec<RawDescriptor> {
117         match self {
118             DeviceProvider::Created { control_tube } => {
119                 vec![control_tube.lock().as_raw_descriptor()]
120             }
121             _ => {
122                 error!("Trying to get keepfds when DeviceProvider is not in created state");
123                 vec![]
124             }
125         }
126     }
127 }
128 
129 /// ProviderInner listens to control socket.
130 pub struct ProviderInner {
131     fail_handle: Arc<dyn FailHandle>,
132     job_queue: Arc<AsyncJobQueue>,
133     event_loop: Arc<EventLoop>,
134     control_tube: Mutex<Tube>,
135     usb_hub: Arc<UsbHub>,
136 
137     // Map of USB hub port number to per-device context.
138     devices: Mutex<HashMap<u8, DeviceContext>>,
139 }
140 
141 struct DeviceContext {
142     event_handler: Arc<dyn EventHandler>,
143     device: Arc<Mutex<dyn BackendDevice>>,
144 }
145 
146 impl ProviderInner {
new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, event_loop: Arc<EventLoop>, control_tube: Mutex<Tube>, usb_hub: Arc<UsbHub>, ) -> ProviderInner147     fn new(
148         fail_handle: Arc<dyn FailHandle>,
149         job_queue: Arc<AsyncJobQueue>,
150         event_loop: Arc<EventLoop>,
151         control_tube: Mutex<Tube>,
152         usb_hub: Arc<UsbHub>,
153     ) -> ProviderInner {
154         ProviderInner {
155             fail_handle,
156             job_queue,
157             event_loop,
158             control_tube,
159             usb_hub,
160             devices: Mutex::new(HashMap::new()),
161         }
162     }
163 
handle_attach_device(&self, usb_file: File) -> UsbControlResult164     fn handle_attach_device(&self, usb_file: File) -> UsbControlResult {
165         let (host_device, event_handler) = match attach_host_backend_device(
166             usb_file,
167             DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
168         ) {
169             Ok((host_device, event_handler)) => (host_device, event_handler),
170             Err(e) => {
171                 error!("could not construct USB device from the given file: {}", e);
172                 return UsbControlResult::NoSuchDevice;
173             }
174         };
175 
176         if let Err(e) = self.event_loop.add_event(
177             &*host_device.lock(),
178             EventType::ReadWrite,
179             Arc::downgrade(&event_handler),
180         ) {
181             error!("failed to add USB device to event handler: {}", e);
182             return UsbControlResult::FailedToOpenDevice;
183         }
184 
185         // Resetting the device is used to make sure it is in a known state, but it may
186         // still function if the reset fails.
187         if let Err(e) = host_device.lock().reset() {
188             error!("failed to reset device after attach: {:?}", e);
189         }
190 
191         let device_ctx = DeviceContext {
192             event_handler,
193             device: host_device.clone(),
194         };
195 
196         let port = self.usb_hub.connect_backend(host_device);
197         match port {
198             Ok(port) => {
199                 self.devices.lock().insert(port, device_ctx);
200                 UsbControlResult::Ok { port }
201             }
202             Err(e) => {
203                 error!("failed to connect device to hub: {}", e);
204                 UsbControlResult::NoAvailablePort
205             }
206         }
207     }
208 
handle_detach_device(&self, port: u8) -> UsbControlResult209     fn handle_detach_device(&self, port: u8) -> UsbControlResult {
210         match self.usb_hub.disconnect_port(port) {
211             Ok(()) => {
212                 if let Some(device_ctx) = self.devices.lock().remove(&port) {
213                     let _ = device_ctx.event_handler.on_event();
214 
215                     if let Err(e) = device_ctx
216                         .device
217                         .lock()
218                         .detach_event_handler(&self.event_loop)
219                     {
220                         error!(
221                             "failed to remove poll change handler from event loop: {}",
222                             e
223                         );
224                     }
225                 }
226                 UsbControlResult::Ok { port }
227             }
228             Err(e) => {
229                 error!("failed to disconnect device from port {}: {}", port, e);
230                 UsbControlResult::NoSuchDevice
231             }
232         }
233     }
234 
handle_attach_security_key(&self, hidraw: File) -> UsbControlResult235     fn handle_attach_security_key(&self, hidraw: File) -> UsbControlResult {
236         let (fido_device, event_handler) = match attach_security_key(
237             hidraw,
238             self.event_loop.clone(),
239             DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
240         ) {
241             Ok((fido_device, event_handler)) => (fido_device, event_handler),
242             Err(e) => {
243                 error!(
244                     "could not create a virtual fido device from the given file: {}",
245                     e
246                 );
247                 return UsbControlResult::NoSuchDevice;
248             }
249         };
250 
251         if let Err(e) = self.event_loop.add_event(
252             &*fido_device.lock(),
253             EventType::Read,
254             Arc::downgrade(&event_handler),
255         ) {
256             error!("failed to add fido device to event handler: {}", e);
257             return UsbControlResult::FailedToOpenDevice;
258         }
259 
260         let device_ctx = DeviceContext {
261             event_handler,
262             device: fido_device.clone(),
263         };
264 
265         // Reset the device to make sure it's in a usable state.
266         // Resetting it also stops polling on the FD, since we only poll when there is an active
267         // transaction.
268         if let Err(e) = fido_device.lock().reset() {
269             error!("failed to reset fido device after attach: {:?}", e);
270         }
271 
272         let port = self.usb_hub.connect_backend(fido_device);
273         match port {
274             Ok(port) => {
275                 self.devices.lock().insert(port, device_ctx);
276                 UsbControlResult::Ok { port }
277             }
278             Err(e) => {
279                 error!("failed to connect device to hub: {}", e);
280                 UsbControlResult::NoAvailablePort
281             }
282         }
283     }
284 
handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult285     fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
286         let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
287         for (result_index, &port_id) in ports.iter().enumerate() {
288             match self.usb_hub.get_port(port_id).and_then(|p| {
289                 p.backend_device()
290                     .as_ref()
291                     .map(|d| d.lock())
292                     .map(|d| (d.get_vid(), d.get_pid()))
293             }) {
294                 Some((vendor_id, product_id)) => {
295                     devices[result_index] = UsbControlAttachedDevice {
296                         port: port_id,
297                         vendor_id,
298                         product_id,
299                     }
300                 }
301                 None => continue,
302             }
303         }
304         UsbControlResult::Devices(devices)
305     }
306 
on_event_helper(&self) -> Result<()>307     fn on_event_helper(&self) -> Result<()> {
308         let tube = self.control_tube.lock();
309         let cmd = tube.recv().map_err(Error::ReadControlTube)?;
310         let result = match cmd {
311             UsbControlCommand::AttachDevice { file } => self.handle_attach_device(file),
312             UsbControlCommand::AttachSecurityKey { file } => self.handle_attach_security_key(file),
313             UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
314             UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
315         };
316         tube.send(&result).map_err(Error::WriteControlTube)?;
317         Ok(())
318     }
319 }
320 
321 impl EventHandler for ProviderInner {
on_event(&self) -> anyhow::Result<()>322     fn on_event(&self) -> anyhow::Result<()> {
323         self.on_event_helper()
324             .context("host backend device provider failed")
325     }
326 }
327