• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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::cell::RefCell;
6 use std::collections::BTreeMap;
7 use std::marker::PhantomPinned;
8 use std::os::raw::c_void;
9 use std::pin::Pin;
10 use std::ptr::null_mut;
11 use std::rc::Rc;
12 
13 use anyhow::bail;
14 use anyhow::Context;
15 use anyhow::Result;
16 use base::debug;
17 use base::error;
18 use base::info;
19 use linux_input_sys::virtio_input_event;
20 #[cfg(feature = "kiwi")]
21 use vm_control::ServiceSendToGpu;
22 use winapi::shared::minwindef::LRESULT;
23 use winapi::shared::windef::HWND;
24 use winapi::um::winuser::*;
25 
26 use super::window::MessagePacket;
27 use super::window::Window;
28 use super::window_message_processor::*;
29 use super::ObjectId;
30 use crate::EventDevice;
31 use crate::EventDeviceKind;
32 
33 /// The pointer to dispatcher will be stored with HWND using `SetPropW()` with the following name.
34 pub(crate) const DISPATCHER_PROPERTY_NAME: &str = "PROP_WND_MSG_DISPATCHER";
35 
36 /// This class is used to dispatch display events to the guest device.
37 #[derive(Clone)]
38 pub struct DisplayEventDispatcher {
39     event_devices: Rc<RefCell<BTreeMap<ObjectId, EventDevice>>>,
40 }
41 
42 impl DisplayEventDispatcher {
new() -> Self43     pub fn new() -> Self {
44         Self {
45             event_devices: Default::default(),
46         }
47     }
48 
dispatch(&self, events: &[virtio_input_event], device_type: EventDeviceKind)49     pub fn dispatch(&self, events: &[virtio_input_event], device_type: EventDeviceKind) {
50         for event_device in self
51             .event_devices
52             .borrow_mut()
53             .values_mut()
54             .filter(|event_device| event_device.kind() == device_type)
55         {
56             if let Err(e) = event_device.send_report(events.iter().cloned()) {
57                 error!("Failed to send events to event device: {}", e);
58             }
59         }
60     }
61 
import_event_device(&mut self, event_device_id: ObjectId, event_device: EventDevice)62     fn import_event_device(&mut self, event_device_id: ObjectId, event_device: EventDevice) {
63         info!("Importing {:?} (ID: {:?})", event_device, event_device_id);
64         self.event_devices
65             .borrow_mut()
66             .insert(event_device_id, event_device);
67     }
68 }
69 
70 /// This class is used for dispatching thread and window messages. It should be created before any
71 /// other threads start to post messages to the WndProc thread, and before the WndProc thread enters
72 /// the window message loop. Once all windows tracked by it are destroyed, it will signal exiting
73 /// the message loop and then it can be dropped.
74 pub(crate) struct WindowMessageDispatcher<T: HandleWindowMessage> {
75     message_processor: Option<WindowMessageProcessor<T>>,
76     display_event_dispatcher: DisplayEventDispatcher,
77     // The dispatcher is pinned so that its address in the memory won't change, and it is always
78     // safe to use the pointer to it stored in the window.
79     _pinned_marker: PhantomPinned,
80 }
81 
82 impl<T: HandleWindowMessage> WindowMessageDispatcher<T> {
83     /// This function should only be called once from the WndProc thread. It will take the ownership
84     /// of the `Window` object, and drop it before the underlying window is completely gone.
85     /// TODO(b/238680252): This should be good enough for supporting multi-windowing, but we should
86     /// revisit it if we also want to manage some child windows of the crosvm window.
create(window: Window) -> Result<Pin<Box<Self>>>87     pub fn create(window: Window) -> Result<Pin<Box<Self>>> {
88         let mut dispatcher = Box::pin(Self {
89             message_processor: Default::default(),
90             display_event_dispatcher: DisplayEventDispatcher::new(),
91             _pinned_marker: PhantomPinned,
92         });
93         dispatcher
94             .as_mut()
95             .create_message_processor(window)
96             .context("When creating WindowMessageDispatcher")?;
97         Ok(dispatcher)
98     }
99 
process_thread_message(self: Pin<&mut Self>, packet: &MessagePacket)100     pub fn process_thread_message(self: Pin<&mut Self>, packet: &MessagePacket) {
101         // Safe because we won't move the dispatcher out of it.
102         unsafe {
103             self.get_unchecked_mut()
104                 .process_thread_message_internal(packet);
105         }
106     }
107 
108     /// Returns `Some` if the message is processed by the targeted window.
dispatch_window_message( &mut self, hwnd: HWND, packet: &MessagePacket, ) -> Option<LRESULT>109     pub fn dispatch_window_message(
110         &mut self,
111         hwnd: HWND,
112         packet: &MessagePacket,
113     ) -> Option<LRESULT> {
114         if let Some(processor) = &mut self.message_processor {
115             if processor.window().is_same_window(hwnd) {
116                 let ret = processor.process_message(packet);
117                 // `WM_NCDESTROY` is sent at the end of the window destruction, and is the last
118                 // message the window will receive. Drop the message processor so that associated
119                 // resources can be cleaned up before the window is completely gone.
120                 if packet.msg == WM_NCDESTROY {
121                     if let Err(e) = Self::remove_pointer_from_window(processor.window()) {
122                         error!("{:?}", e);
123                     }
124                     self.message_processor = None;
125                     Self::request_exit_message_loop();
126                 }
127                 return Some(ret);
128             }
129         }
130         None
131     }
132 
create_message_processor(self: Pin<&mut Self>, window: Window) -> Result<()>133     fn create_message_processor(self: Pin<&mut Self>, window: Window) -> Result<()> {
134         if !window.is_valid() {
135             bail!("Window handle is invalid!");
136         }
137         Self::store_pointer_in_window(&*self, &window)?;
138         // Safe because we won't move the dispatcher out of it, and the dispatcher is aware of the
139         // lifecycle of the window.
140         unsafe {
141             self.get_unchecked_mut()
142                 .message_processor
143                 .replace(WindowMessageProcessor::<T>::new(window));
144         }
145         Ok(())
146     }
147 
process_thread_message_internal(&mut self, packet: &MessagePacket)148     fn process_thread_message_internal(&mut self, packet: &MessagePacket) {
149         let MessagePacket {
150             msg,
151             w_param,
152             l_param,
153         } = *packet;
154         match msg {
155             #[cfg(feature = "kiwi")]
156             WM_USER_HANDLE_SERVICE_MESSAGE_INTERNAL => {
157                 // Safe because the sender gives up the ownership and expects the receiver to
158                 // destruct the message.
159                 let message = unsafe { Box::from_raw(l_param as *mut ServiceSendToGpu) };
160                 match &mut self.message_processor {
161                     Some(processor) => processor.handle_service_message(&*message),
162                     None => error!(
163                         "Cannot handle service message because there is no message processor!"
164                     ),
165                 }
166             }
167             WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL => {
168                 // Safe because the sender gives up the ownership and expects the receiver to
169                 // destruct the message.
170                 let message = unsafe { Box::from_raw(l_param as *mut DisplaySendToWndProc<T>) };
171                 self.handle_display_message(*message);
172             }
173             WM_USER_WNDPROC_THREAD_DROP_KILL_WINDOW_INTERNAL => match &self.message_processor {
174                 Some(processor) => {
175                     debug!("Destroying window on WndProc thread drop");
176                     if let Err(e) = processor.window().destroy() {
177                         error!(
178                             "Failed to destroy window when dropping WndProc thread: {:?}",
179                             e
180                         );
181                     }
182                 }
183                 None => debug!("No window to destroy on WndProc thread drop"),
184             },
185             // Safe because we are processing a message targeting this thread.
186             _ => unsafe {
187                 DefWindowProcW(null_mut(), msg, w_param, l_param);
188             },
189         }
190     }
191 
handle_display_message(&mut self, message: DisplaySendToWndProc<T>)192     fn handle_display_message(&mut self, message: DisplaySendToWndProc<T>) {
193         match message {
194             DisplaySendToWndProc::CreateSurface { function, callback } => {
195                 callback(self.create_message_handler(function));
196             }
197             DisplaySendToWndProc::ImportEventDevice {
198                 event_device_id,
199                 event_device,
200             } => {
201                 self.display_event_dispatcher
202                     .import_event_device(event_device_id, event_device);
203             }
204         }
205     }
206 
207     /// Returns true if the window message handler is created successfully.
create_message_handler( &mut self, create_handler_func: CreateMessageHandlerFunction<T>, ) -> bool208     fn create_message_handler(
209         &mut self,
210         create_handler_func: CreateMessageHandlerFunction<T>,
211     ) -> bool {
212         match &mut self.message_processor {
213             Some(processor) => match processor
214                 .create_message_handler(create_handler_func, self.display_event_dispatcher.clone())
215             {
216                 Ok(_) => return true,
217                 Err(e) => error!("Failed to create message handler: {:?}", e),
218             },
219             None => {
220                 error!("Cannot create message handler because there is no message processor!")
221             }
222         }
223         false
224     }
225 
store_pointer_in_window(pointer: *const Self, window: &Window) -> Result<()>226     fn store_pointer_in_window(pointer: *const Self, window: &Window) -> Result<()> {
227         window
228             .set_property(DISPATCHER_PROPERTY_NAME, pointer as *mut c_void)
229             .context("When storing message dispatcher pointer")
230     }
231 
232     /// When the window is being destroyed, we must remove all entries added to the property list
233     /// before `WM_NCDESTROY` returns.
remove_pointer_from_window(window: &Window) -> Result<()>234     fn remove_pointer_from_window(window: &Window) -> Result<()> {
235         window
236             .remove_property(DISPATCHER_PROPERTY_NAME)
237             .context("When removing message dispatcher pointer")
238     }
239 
request_exit_message_loop()240     fn request_exit_message_loop() {
241         info!("Posting WM_QUIT");
242         // Safe because it will always succeed.
243         unsafe {
244             PostQuitMessage(0);
245         }
246     }
247 }
248