utilize EventDevices to make virtio-input devices

BUG=chromium:1023975
TEST=./build_test

Change-Id: I10267e535d4d1dae90b2b5f30db046c388791a16
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1930409
Reviewed-by: Zach Reizner <zachr@chromium.org>
Commit-Queue: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/linux.rs b/src/linux.rs
index a9a3445..57b3ef5 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -28,6 +28,8 @@
 use libc::{self, c_int, gid_t, uid_t};
 
 use audio_streams::DummyStreamSource;
+#[cfg(feature = "gpu")]
+use devices::virtio::EventDevice;
 use devices::virtio::{self, VirtioDevice};
 use devices::{
     self, HostBackendDeviceProvider, PciDevice, VfioDevice, VfioPciDevice, VirtioPciDevice,
@@ -456,7 +458,7 @@
 }
 
 fn create_single_touch_device(cfg: &Config, single_touch_spec: &TouchDeviceOption) -> DeviceResult {
-    let socket = create_input_socket(&single_touch_spec.path).map_err(|e| {
+    let socket = single_touch_spec.path.into_unix_stream().map_err(|e| {
         error!("failed configuring virtio single touch: {:?}", e);
         e
     })?;
@@ -470,7 +472,7 @@
 }
 
 fn create_trackpad_device(cfg: &Config, trackpad_spec: &TouchDeviceOption) -> DeviceResult {
-    let socket = create_input_socket(&trackpad_spec.path).map_err(|e| {
+    let socket = trackpad_spec.path.into_unix_stream().map_err(|e| {
         error!("failed configuring virtio trackpad: {}", e);
         e
     })?;
@@ -484,8 +486,8 @@
     })
 }
 
-fn create_mouse_device(cfg: &Config, mouse_socket: &Path) -> DeviceResult {
-    let socket = create_input_socket(&mouse_socket).map_err(|e| {
+fn create_mouse_device<T: IntoUnixStream>(cfg: &Config, mouse_socket: T) -> DeviceResult {
+    let socket = mouse_socket.into_unix_stream().map_err(|e| {
         error!("failed configuring virtio mouse: {}", e);
         e
     })?;
@@ -498,8 +500,8 @@
     })
 }
 
-fn create_keyboard_device(cfg: &Config, keyboard_socket: &Path) -> DeviceResult {
-    let socket = create_input_socket(&keyboard_socket).map_err(|e| {
+fn create_keyboard_device<T: IntoUnixStream>(cfg: &Config, keyboard_socket: T) -> DeviceResult {
+    let socket = keyboard_socket.into_unix_stream().map_err(|e| {
         error!("failed configuring virtio keyboard: {}", e);
         e
     })?;
@@ -589,6 +591,7 @@
     gpu_sockets: Vec<virtio::resource_bridge::ResourceResponseSocket>,
     wayland_socket_path: Option<PathBuf>,
     x_display: Option<String>,
+    event_devices: Vec<EventDevice>,
 ) -> DeviceResult {
     let jailed_wayland_path = Path::new("/wayland-0");
 
@@ -615,6 +618,7 @@
         gpu_sockets,
         display_backends,
         cfg.gpu_parameters.as_ref().unwrap(),
+        event_devices,
     );
 
     let jail = match simple_jail(&cfg, "gpu_device.policy")? {
@@ -986,6 +990,31 @@
     #[cfg(feature = "gpu")]
     {
         if cfg.gpu_parameters.is_some() {
+            let mut event_devices = Vec::new();
+            if cfg.display_window_mouse {
+                let (event_device_socket, virtio_dev_socket) =
+                    UnixStream::pair().map_err(Error::CreateSocket)?;
+                // TODO(nkgold): the width/height here should match the display's height/width. When
+                // those settings are available as CLI options, we should use the CLI options here
+                // as well.
+                let dev = virtio::new_single_touch(virtio_dev_socket, 1280, 1024)
+                    .map_err(Error::InputDeviceNew)?;
+                devs.push(VirtioDeviceStub {
+                    dev: Box::new(dev),
+                    jail: simple_jail(&cfg, "input_device.policy")?,
+                });
+                event_devices.push(EventDevice::touchscreen(event_device_socket));
+            }
+            if cfg.display_window_keyboard {
+                let (event_device_socket, virtio_dev_socket) =
+                    UnixStream::pair().map_err(Error::CreateSocket)?;
+                let dev = virtio::new_keyboard(virtio_dev_socket).map_err(Error::InputDeviceNew)?;
+                devs.push(VirtioDeviceStub {
+                    dev: Box::new(dev),
+                    jail: simple_jail(&cfg, "input_device.policy")?,
+                });
+                event_devices.push(EventDevice::keyboard(event_device_socket));
+            }
             devs.push(create_gpu_device(
                 cfg,
                 _exit_evt,
@@ -993,6 +1022,7 @@
                 resource_bridges,
                 cfg.wayland_socket_path.clone(),
                 cfg.x_display.clone(),
+                event_devices,
             )?);
         }
     }
@@ -1160,12 +1190,29 @@
     validate_raw_fd(raw_fd).map_err(Error::ValidateRawFd)
 }
 
-fn create_input_socket(path: &Path) -> Result<UnixStream> {
-    if path.parent() == Some(Path::new("/proc/self/fd")) {
-        // Safe because we will validate |raw_fd|.
-        unsafe { Ok(UnixStream::from_raw_fd(raw_fd_from_path(path)?)) }
-    } else {
-        UnixStream::connect(path).map_err(Error::InputEventsOpen)
+trait IntoUnixStream {
+    fn into_unix_stream(self) -> Result<UnixStream>;
+}
+
+impl<'a> IntoUnixStream for &'a Path {
+    fn into_unix_stream(self) -> Result<UnixStream> {
+        if self.parent() == Some(Path::new("/proc/self/fd")) {
+            // Safe because we will validate |raw_fd|.
+            unsafe { Ok(UnixStream::from_raw_fd(raw_fd_from_path(self)?)) }
+        } else {
+            UnixStream::connect(self).map_err(Error::InputEventsOpen)
+        }
+    }
+}
+impl<'a> IntoUnixStream for &'a PathBuf {
+    fn into_unix_stream(self) -> Result<UnixStream> {
+        self.as_path().into_unix_stream()
+    }
+}
+
+impl IntoUnixStream for UnixStream {
+    fn into_unix_stream(self) -> Result<UnixStream> {
+        Ok(self)
     }
 }