• 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::any::type_name;
6 use std::any::TypeId;
7 use std::collections::btree_map::Entry;
8 use std::collections::BTreeMap;
9 use std::collections::HashMap;
10 use std::mem;
11 use std::os::windows::io::RawHandle;
12 use std::pin::Pin;
13 use std::ptr::null_mut;
14 use std::rc::Rc;
15 use std::sync::atomic::AtomicI32;
16 use std::sync::atomic::Ordering;
17 use std::sync::mpsc::channel;
18 use std::sync::mpsc::Sender;
19 use std::sync::Arc;
20 use std::thread::Builder as ThreadBuilder;
21 use std::thread::JoinHandle;
22 
23 use anyhow::anyhow;
24 use anyhow::bail;
25 use anyhow::Context;
26 use anyhow::Result;
27 use base::error;
28 use base::info;
29 use base::warn;
30 use base::AsRawDescriptor;
31 use base::Event;
32 use base::ReadNotifier;
33 use base::Tube;
34 use euclid::size2;
35 use serde::Deserialize;
36 use serde::Serialize;
37 use sync::Mutex;
38 #[cfg(feature = "kiwi")]
39 use vm_control::ServiceSendToGpu;
40 use win_util::syscall_bail;
41 use win_util::win32_wide_string;
42 use winapi::shared::minwindef::DWORD;
43 use winapi::shared::minwindef::FALSE;
44 use winapi::shared::minwindef::LPARAM;
45 use winapi::shared::minwindef::LRESULT;
46 use winapi::shared::minwindef::UINT;
47 use winapi::shared::minwindef::WPARAM;
48 use winapi::shared::windef::HWND;
49 use winapi::um::winbase::INFINITE;
50 use winapi::um::winbase::WAIT_OBJECT_0;
51 use winapi::um::winnt::MAXIMUM_WAIT_OBJECTS;
52 use winapi::um::winuser::*;
53 
54 use super::window::get_current_module_handle;
55 use super::window::GuiWindow;
56 use super::window::MessageOnlyWindow;
57 use super::window::MessagePacket;
58 use super::window_message_dispatcher::WindowMessageDispatcher;
59 use super::window_message_dispatcher::DISPATCHER_PROPERTY_NAME;
60 use super::window_message_processor::*;
61 
62 // The default app icon id, which is defined in crosvm-manifest.rc.
63 const APP_ICON_ID: u16 = 1;
64 
65 #[derive(Debug)]
66 enum MessageLoopState {
67     /// The initial state.
68     NotStarted = 0,
69     /// The loop is running normally.
70     Running,
71     /// The loop has ended normally.
72     ExitedNormally,
73     /// The loop never started because errors occurred.
74     EarlyTerminatedWithError,
75     /// The loop has ended because errors occurred.
76     ExitedWithError,
77 }
78 
79 #[derive(Copy, Clone, PartialEq)]
80 enum Token {
81     MessagePump,
82     ServiceMessage,
83 }
84 
85 /// A context that can wait on both the thread-specific message queue and the given handles.
86 struct MsgWaitContext {
87     triggers: HashMap<RawHandle, Token>,
88     raw_handles: Vec<RawHandle>,
89 }
90 
91 impl MsgWaitContext {
new() -> Self92     pub fn new() -> Self {
93         Self {
94             triggers: HashMap::new(),
95             raw_handles: Vec::new(),
96         }
97     }
98 
99     /// Note that since there is no handle associated with `Token::MessagePump`, this token will be
100     /// used internally by `MsgWaitContext` and the caller should never use it.
add(&mut self, handle: &dyn AsRawDescriptor, token: Token) -> Result<()>101     pub fn add(&mut self, handle: &dyn AsRawDescriptor, token: Token) -> Result<()> {
102         if token == Token::MessagePump {
103             bail!("Token::MessagePump is reserved!");
104         }
105         if self.raw_handles.len() == MAXIMUM_WAIT_OBJECTS as usize {
106             bail!("Number of raw handles exceeding MAXIMUM_WAIT_OBJECTS!");
107         }
108 
109         let raw_descriptor = handle.as_raw_descriptor();
110         if self.triggers.contains_key(&raw_descriptor) {
111             bail!("The handle has already been registered in MsgWaitContext!")
112         }
113 
114         self.triggers.insert(raw_descriptor, token);
115         self.raw_handles.push(raw_descriptor);
116         Ok(())
117     }
118 
119     /// Blocks the thread until there is any new message available on the message queue, or if any
120     /// of the given handles is signaled, and returns the associated token.
121     ///
122     /// If multiple handles are signaled, this will return the token associated with the one that
123     /// was first added to this context.
124     ///
125     /// # Safety
126     ///
127     /// Caller is responsible for ensuring that the handles are still valid.
wait(&self) -> Result<Token>128     pub unsafe fn wait(&self) -> Result<Token> {
129         let num_handles = self.raw_handles.len();
130         // Safe because the caller is required to guarantee that the handles are valid, and failures
131         // are handled below.
132         let result = MsgWaitForMultipleObjects(
133             num_handles as DWORD,
134             self.raw_handles.as_ptr(),
135             /* fWaitAll= */ FALSE,
136             INFINITE,
137             QS_ALLINPUT,
138         );
139         match (result - WAIT_OBJECT_0) as usize {
140             // At least one of the handles has been signaled.
141             index if index < num_handles => Ok(self.triggers[&self.raw_handles[index]]),
142             // At least one message is available at the message queue.
143             index if index == num_handles => Ok(Token::MessagePump),
144             // Invalid cases. This is most likely a `WAIT_FAILED`, but anything not matched by the
145             // above is an error case.
146             _ => syscall_bail!(format!(
147                 "MsgWaitForMultipleObjects() unexpectedly returned {}",
148                 result
149             )),
150         }
151     }
152 }
153 
154 trait RegisterWindowClass: 'static {
155     // Only for debug purpose. Not required to be unique across different implementors.
156     const CLASS_NAME_PREFIX: &'static str = "";
register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()>157     fn register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()>;
158 }
159 
160 impl RegisterWindowClass for GuiWindow {
161     const CLASS_NAME_PREFIX: &'static str = "CROSVM";
162 
register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()>163     fn register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()> {
164         let hinstance = get_current_module_handle();
165         // If we fail to load any UI element below, use NULL to let the system use the default UI
166         // rather than crash.
167         let hicon = Self::load_custom_icon(hinstance, APP_ICON_ID).unwrap_or(null_mut());
168         let hcursor = Self::load_system_cursor(IDC_ARROW).unwrap_or(null_mut());
169         let hbrush_background = Self::create_opaque_black_brush().unwrap_or(null_mut());
170         let class_name = win32_wide_string(class_name);
171         let window_class = WNDCLASSEXW {
172             cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
173             style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
174             lpfnWndProc: wnd_proc,
175             cbClsExtra: 0,
176             cbWndExtra: 0,
177             hInstance: hinstance,
178             hIcon: hicon,
179             hCursor: hcursor,
180             hbrBackground: hbrush_background,
181             lpszMenuName: null_mut(),
182             lpszClassName: class_name.as_ptr(),
183             hIconSm: hicon,
184         };
185 
186         // SAFETY:
187         // Safe because we know the lifetime of `window_class`, and we handle failures below.
188         if unsafe { RegisterClassExW(&window_class) } == 0 {
189             syscall_bail!("Failed to call RegisterClassExW()");
190         }
191         Ok(())
192     }
193 }
194 
195 impl RegisterWindowClass for MessageOnlyWindow {
196     const CLASS_NAME_PREFIX: &'static str = "THREAD_MESSAGE_ROUTER";
197 
register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()>198     fn register_window_class(class_name: &str, wnd_proc: WNDPROC) -> Result<()> {
199         let hinstance = get_current_module_handle();
200         let class_name = win32_wide_string(class_name);
201         let window_class = WNDCLASSEXW {
202             cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
203             style: 0,
204             lpfnWndProc: wnd_proc,
205             cbClsExtra: 0,
206             cbWndExtra: 0,
207             hInstance: hinstance,
208             hIcon: null_mut(),
209             hCursor: null_mut(),
210             hbrBackground: null_mut(),
211             lpszMenuName: null_mut(),
212             lpszClassName: class_name.as_ptr(),
213             hIconSm: null_mut(),
214         };
215 
216         // SAFETY:
217         // Safe because we know the lifetime of `window_class`, and we handle failures below.
218         if unsafe { RegisterClassExW(&window_class) } == 0 {
219             syscall_bail!("Failed to call RegisterClassExW()");
220         }
221         Ok(())
222     }
223 }
224 
225 /// This class runs the WndProc thread, and provides helper functions for other threads to
226 /// communicate with it.
227 pub struct WindowProcedureThread {
228     thread: Option<JoinHandle<()>>,
229     message_router_handle: HWND,
230     message_loop_state: Option<Arc<AtomicI32>>,
231     close_requested_event: Event,
232 }
233 
234 impl WindowProcedureThread {
builder() -> WindowProcedureThreadBuilder235     pub fn builder() -> WindowProcedureThreadBuilder {
236         // We don't implement Default for WindowProcedureThreadBuilder so that the builder function
237         // is the only way to create WindowProcedureThreadBuilder.
238         WindowProcedureThreadBuilder {
239             max_num_windows: 1,
240             display_tube: None,
241             #[cfg(feature = "kiwi")]
242             ime_tube: None,
243         }
244     }
245 
start_thread(max_num_windows: u32, gpu_main_display_tube: Option<Tube>) -> Result<Self>246     fn start_thread(max_num_windows: u32, gpu_main_display_tube: Option<Tube>) -> Result<Self> {
247         let (message_router_handle_sender, message_router_handle_receiver) = channel();
248         let message_loop_state = Arc::new(AtomicI32::new(MessageLoopState::NotStarted as i32));
249         let close_requested_event = Event::new().unwrap();
250 
251         let message_loop_state_clone = Arc::clone(&message_loop_state);
252         let close_requested_event_clone = close_requested_event
253             .try_clone()
254             .map_err(|e| anyhow!("Failed to clone close_requested_event: {}", e))?;
255 
256         let thread = match ThreadBuilder::new()
257             .name("gpu_display_wndproc".into())
258             .spawn(move || {
259                 match close_requested_event_clone.try_clone() {
260                     Ok(close_requested_event) => Self::run_message_loop(
261                         max_num_windows,
262                         message_router_handle_sender,
263                         message_loop_state_clone,
264                         gpu_main_display_tube,
265                         close_requested_event,
266                     ),
267                     Err(e) => error!("Failed to clone close_requested_event: {}", e),
268                 }
269                 // The close requested event should have been signaled at this point, unless we hit
270                 // some edge cases, e.g. the WndProc thread terminates unexpectedly during startup.
271                 // We want to make sure it is signaled in all cases.
272                 if let Err(e) = close_requested_event_clone.signal() {
273                     error!("Failed to signal close requested event: {}", e);
274                 }
275             }) {
276             Ok(thread) => thread,
277             Err(e) => bail!("Failed to spawn WndProc thread: {}", e),
278         };
279 
280         match message_router_handle_receiver.recv() {
281             Ok(message_router_handle_res) => match message_router_handle_res {
282                 Ok(message_router_handle) => Ok(Self {
283                     thread: Some(thread),
284                     message_router_handle: message_router_handle as HWND,
285                     message_loop_state: Some(message_loop_state),
286                     close_requested_event,
287                 }),
288                 Err(e) => bail!("WndProc internal failure: {:?}", e),
289             },
290             Err(e) => bail!("Failed to receive WndProc thread ID: {}", e),
291         }
292     }
293 
try_clone_close_requested_event(&self) -> Result<Event>294     pub fn try_clone_close_requested_event(&self) -> Result<Event> {
295         self.close_requested_event
296             .try_clone()
297             .map_err(|e| anyhow!("Failed to clone close_requested_event: {}", e))
298     }
299 
post_display_command(&self, message: DisplaySendToWndProc) -> Result<()>300     pub fn post_display_command(&self, message: DisplaySendToWndProc) -> Result<()> {
301         self.post_message_to_thread_carrying_object(
302             WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL,
303             message,
304         )
305         .context("When posting DisplaySendToWndProc message")
306     }
307 
308     /// Calls `PostMessageW()` internally.
post_message_to_thread(&self, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> Result<()>309     fn post_message_to_thread(&self, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> Result<()> {
310         if !self.is_message_loop_running() {
311             bail!("Cannot post message to WndProc thread because message loop is not running!");
312         }
313         // SAFETY:
314         // Safe because the message loop is still running.
315         if unsafe { PostMessageW(self.message_router_handle, msg, w_param, l_param) } == 0 {
316             syscall_bail!("Failed to call PostMessageW()");
317         }
318         Ok(())
319     }
320 
321     /// Calls `PostMessageW()` internally. This is a common pattern, where we send a pointer to
322     /// the given object as the lParam. The receiver is responsible for destructing the object.
post_message_to_thread_carrying_object<U>(&self, msg: UINT, object: U) -> Result<()>323     fn post_message_to_thread_carrying_object<U>(&self, msg: UINT, object: U) -> Result<()> {
324         let mut boxed_object = Box::new(object);
325         self.post_message_to_thread(
326             msg,
327             /* w_param= */ 0,
328             &mut *boxed_object as *mut U as LPARAM,
329         )
330         .map(|_| {
331             // If successful, the receiver will be responsible for destructing the object.
332             std::mem::forget(boxed_object);
333         })
334     }
335 
run_message_loop( max_num_windows: u32, message_router_handle_sender: Sender<Result<u32>>, message_loop_state: Arc<AtomicI32>, gpu_main_display_tube: Option<Tube>, close_requested_event: Event, )336     fn run_message_loop(
337         max_num_windows: u32,
338         message_router_handle_sender: Sender<Result<u32>>,
339         message_loop_state: Arc<AtomicI32>,
340         gpu_main_display_tube: Option<Tube>,
341         close_requested_event: Event,
342     ) {
343         let gpu_main_display_tube = gpu_main_display_tube.map(Rc::new);
344         // SAFETY:
345         // Safe because the dispatcher will take care of the lifetime of the `MessageOnlyWindow` and
346         // `GuiWindow` objects.
347         match unsafe { Self::create_windows(max_num_windows) }.and_then(
348             |(message_router_window, gui_windows)| {
349                 WindowMessageDispatcher::new(
350                     message_router_window,
351                     gui_windows,
352                     gpu_main_display_tube.clone(),
353                     close_requested_event,
354                 )
355             },
356         ) {
357             Ok(dispatcher) => {
358                 info!("WndProc thread entering message loop");
359                 message_loop_state.store(MessageLoopState::Running as i32, Ordering::SeqCst);
360 
361                 let message_router_handle =
362                     // SAFETY:
363                     // Safe because we won't use the handle unless the message loop is still running.
364                     unsafe { dispatcher.message_router_handle().unwrap_or(null_mut()) };
365                 // HWND cannot be sent cross threads, so we cast it to u32 first.
366                 if let Err(e) = message_router_handle_sender.send(Ok(message_router_handle as u32))
367                 {
368                     error!("Failed to send message router handle: {}", e);
369                 }
370 
371                 let exit_state = Self::run_message_loop_body(dispatcher, gpu_main_display_tube);
372                 message_loop_state.store(exit_state as i32, Ordering::SeqCst);
373             }
374             Err(e) => {
375                 error!("WndProc thread didn't enter message loop: {:?}", e);
376                 message_loop_state.store(
377                     MessageLoopState::EarlyTerminatedWithError as i32,
378                     Ordering::SeqCst,
379                 );
380                 if let Err(e) = message_router_handle_sender.send(Err(e)) {
381                     error!("Failed to report message loop early termination: {}", e)
382                 }
383             }
384         }
385     }
386 
run_message_loop_body( #[cfg_attr(not(feature = "kiwi"), allow(unused_variables, unused_mut))] mut message_dispatcher: Pin<Box<WindowMessageDispatcher>>, gpu_main_display_tube: Option<Rc<Tube>>, ) -> MessageLoopState387     fn run_message_loop_body(
388         #[cfg_attr(not(feature = "kiwi"), allow(unused_variables, unused_mut))]
389         mut message_dispatcher: Pin<Box<WindowMessageDispatcher>>,
390         gpu_main_display_tube: Option<Rc<Tube>>,
391     ) -> MessageLoopState {
392         let mut msg_wait_ctx = MsgWaitContext::new();
393         if let Some(tube) = &gpu_main_display_tube {
394             if let Err(e) = msg_wait_ctx.add(tube.get_read_notifier(), Token::ServiceMessage) {
395                 error!(
396                     "Failed to add service message read notifier to MsgWaitContext: {:?}",
397                     e
398                 );
399                 return MessageLoopState::EarlyTerminatedWithError;
400             }
401         }
402 
403         loop {
404             // SAFETY:
405             // Safe because the lifetime of handles are at least as long as the function call.
406             match unsafe { msg_wait_ctx.wait() } {
407                 Ok(token) => match token {
408                     Token::MessagePump => {
409                         if !Self::retrieve_and_dispatch_messages() {
410                             info!("WndProc thread exiting message loop normally");
411                             return MessageLoopState::ExitedNormally;
412                         }
413                     }
414                     Token::ServiceMessage => Self::read_and_dispatch_service_message(
415                         &mut message_dispatcher,
416                         // We never use this token if `gpu_main_display_tube` is None, so
417                         // `expect()` should always succeed.
418                         gpu_main_display_tube
419                             .as_ref()
420                             .expect("Service message tube is None"),
421                     ),
422                 },
423                 Err(e) => {
424                     error!(
425                         "WndProc thread exiting message loop because of error: {:?}",
426                         e
427                     );
428                     return MessageLoopState::ExitedWithError;
429                 }
430             }
431         }
432     }
433 
434     /// Retrieves and dispatches all messages in the queue, and returns whether the message loop
435     /// should continue running.
retrieve_and_dispatch_messages() -> bool436     fn retrieve_and_dispatch_messages() -> bool {
437         // Since `MsgWaitForMultipleObjects()` returns only when there is a new event in the queue,
438         // if we call `MsgWaitForMultipleObjects()` again without draining the queue, it will ignore
439         // existing events and will not return immediately. Hence, we need to keep calling
440         // `PeekMessageW()` with `PM_REMOVE` until the queue is drained before returning.
441         // https://devblogs.microsoft.com/oldnewthing/20050217-00/?p=36423
442         // Alternatively we could use `MsgWaitForMultipleObjectsEx()` with the `MWMO_INPUTAVAILABLE`
443         // flag, which will always return if there is any message in the queue, no matter that is a
444         // new message or not. However, we found that it may also return when there is no message at
445         // all, so we slightly prefer `MsgWaitForMultipleObjects()`.
446         loop {
447             // Safe because if `message` is initialized, we will call `assume_init()` to extract the
448             // value, which will get dropped eventually.
449             let mut message = mem::MaybeUninit::uninit();
450             // SAFETY:
451             // Safe because `message` lives at least as long as the function call.
452             if unsafe {
453                 PeekMessageW(
454                     message.as_mut_ptr(),
455                     /* hWnd= */ null_mut(),
456                     /* wMsgFilterMin= */ 0,
457                     /* wMsgFilterMax= */ 0,
458                     PM_REMOVE,
459                 ) == 0
460             } {
461                 // No more message in the queue.
462                 return true;
463             }
464 
465             // SAFETY:
466             // Safe because `PeekMessageW()` has populated `message`.
467             unsafe {
468                 let new_message = message.assume_init();
469                 if new_message.message == WM_QUIT {
470                     return false;
471                 }
472                 TranslateMessage(&new_message);
473                 DispatchMessageW(&new_message);
474             }
475         }
476     }
477 
478     #[cfg(feature = "kiwi")]
read_and_dispatch_service_message( message_dispatcher: &mut Pin<Box<WindowMessageDispatcher>>, gpu_main_display_tube: &Tube, )479     fn read_and_dispatch_service_message(
480         message_dispatcher: &mut Pin<Box<WindowMessageDispatcher>>,
481         gpu_main_display_tube: &Tube,
482     ) {
483         match gpu_main_display_tube.recv::<ServiceSendToGpu>() {
484             Ok(message) => message_dispatcher.as_mut().process_service_message(message),
485             Err(e) => {
486                 error!("Failed to receive service message through the tube: {}", e)
487             }
488         }
489     }
490 
491     #[cfg(not(feature = "kiwi"))]
read_and_dispatch_service_message( _: &mut Pin<Box<WindowMessageDispatcher>>, _gpu_main_display_tube: &Tube, )492     fn read_and_dispatch_service_message(
493         _: &mut Pin<Box<WindowMessageDispatcher>>,
494         _gpu_main_display_tube: &Tube,
495     ) {
496     }
497 
is_message_loop_running(&self) -> bool498     fn is_message_loop_running(&self) -> bool {
499         self.message_loop_state.as_ref().map_or(false, |state| {
500             state.load(Ordering::SeqCst) == MessageLoopState::Running as i32
501         })
502     }
503 
504     /// Normally the WndProc thread should still be running when the `WindowProcedureThread` struct
505     /// is dropped, and this function will post a message to notify that thread to destroy all
506     /// windows and release all resources. If the WndProc thread has encountered fatal errors and
507     /// has already terminated, we don't need to post this message anymore.
signal_exit_message_loop_if_needed(&self)508     fn signal_exit_message_loop_if_needed(&self) {
509         if !self.is_message_loop_running() {
510             return;
511         }
512 
513         info!("WndProc thread is still in message loop before dropping. Signaling shutting down");
514         if let Err(e) = self.post_message_to_thread(
515             WM_USER_SHUTDOWN_WNDPROC_THREAD_INTERNAL,
516             /* w_param */ 0,
517             /* l_param */ 0,
518         ) {
519             error!("Failed to signal WndProc thread to shut down: {:?}", e);
520         }
521     }
522 
523     /// Checks if the message loop has exited normally. This should be called after joining with the
524     /// WndProc thread.
check_message_loop_final_state(&mut self)525     fn check_message_loop_final_state(&mut self) {
526         match Arc::try_unwrap(self.message_loop_state.take().unwrap()) {
527             Ok(state) => {
528                 let state = state.into_inner();
529                 if state == MessageLoopState::ExitedNormally as i32 {
530                     info!("WndProc thread exited gracefully");
531                 } else {
532                     warn!("WndProc thread exited with message loop state: {:?}", state);
533                 }
534             }
535             Err(e) => error!(
536                 "WndProc thread exited but message loop state retrieval failed: {:?}",
537                 e
538             ),
539         }
540     }
541 
542     /// # Safety
543     /// The owner of the returned window objects is responsible for dropping them before we finish
544     /// processing `WM_NCDESTROY`, because the window handle will become invalid afterwards.
create_windows(max_num_windows: u32) -> Result<(MessageOnlyWindow, Vec<GuiWindow>)>545     unsafe fn create_windows(max_num_windows: u32) -> Result<(MessageOnlyWindow, Vec<GuiWindow>)> {
546         let message_router_window = MessageOnlyWindow::new(
547             /* class_name */
548             Self::get_window_class_name::<MessageOnlyWindow>()
549                 .with_context(|| {
550                     format!(
551                         "retrieve the window class name for MessageOnlyWindow of {}.",
552                         type_name::<Self>()
553                     )
554                 })?
555                 .as_str(),
556             /* title */ "ThreadMessageRouter",
557         )?;
558         // Gfxstream window is a child window of crosvm window. Without WS_CLIPCHILDREN, the parent
559         // window may use the background brush to clear the gfxstream window client area when
560         // drawing occurs. This caused the screen flickering issue during resizing.
561         // See b/197786842 for details.
562         let mut gui_windows = Vec::with_capacity(max_num_windows as usize);
563         for scanout_id in 0..max_num_windows {
564             gui_windows.push(GuiWindow::new(
565                 scanout_id,
566                 /* class_name */
567                 Self::get_window_class_name::<GuiWindow>()
568                     .with_context(|| {
569                         format!(
570                             "retrieve the window class name for GuiWindow of {}",
571                             type_name::<Self>()
572                         )
573                     })?
574                     .as_str(),
575                 /* title */ Self::get_window_title().as_str(),
576                 /* dw_style */ WS_POPUP | WS_CLIPCHILDREN,
577                 // The window size and style can be adjusted later when `Surface` is created.
578                 &size2(1, 1),
579             )?);
580         }
581         Ok((message_router_window, gui_windows))
582     }
583 
wnd_proc( hwnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM, ) -> LRESULT584     unsafe extern "system" fn wnd_proc(
585         hwnd: HWND,
586         msg: UINT,
587         w_param: WPARAM,
588         l_param: LPARAM,
589     ) -> LRESULT {
590         let dispatcher_ptr = GetPropW(hwnd, win32_wide_string(DISPATCHER_PROPERTY_NAME).as_ptr())
591             as *mut WindowMessageDispatcher;
592         if let Some(dispatcher) = dispatcher_ptr.as_mut() {
593             if let Some(ret) =
594                 dispatcher.dispatch_window_message(hwnd, &MessagePacket::new(msg, w_param, l_param))
595             {
596                 return ret;
597             }
598         }
599         DefWindowProcW(hwnd, msg, w_param, l_param)
600     }
601 
602     /// U + T decides one window class. For the same combination of U + T, the same window class
603     /// name will be returned. This function also registers the Window class if it is not registered
604     /// through this function yet.
get_window_class_name<T: RegisterWindowClass>() -> Result<String>605     fn get_window_class_name<T: RegisterWindowClass>() -> Result<String> {
606         static WINDOW_CLASS_NAMES: Mutex<BTreeMap<TypeId, String>> = Mutex::new(BTreeMap::new());
607         let mut window_class_names = WINDOW_CLASS_NAMES.lock();
608         let id = window_class_names.len();
609         let entry = window_class_names.entry(TypeId::of::<T>());
610         let entry = match entry {
611             Entry::Occupied(entry) => return Ok(entry.get().clone()),
612             Entry::Vacant(entry) => entry,
613         };
614         // We are generating a different class name everytime we reach this line, so the name
615         // shouldn't collide with any window classes registered through this function. The
616         // underscore here is important. If we just use `"{}{}"`, we may collide for prefix = "" and
617         // prefix = "1".
618         let window_class_name = format!("{}_{}", T::CLASS_NAME_PREFIX, id);
619         T::register_window_class(&window_class_name, Some(Self::wnd_proc)).with_context(|| {
620             format!(
621                 "Failed to register the window class for ({}, {}), with name {}.",
622                 type_name::<Self>(),
623                 type_name::<T>(),
624                 window_class_name
625             )
626         })?;
627         entry.insert(window_class_name.clone());
628         Ok(window_class_name)
629     }
630 
get_window_title() -> String631     fn get_window_title() -> String {
632         "crosvm".to_string()
633     }
634 }
635 
636 impl Drop for WindowProcedureThread {
drop(&mut self)637     fn drop(&mut self) {
638         self.signal_exit_message_loop_if_needed();
639         match self.thread.take().unwrap().join() {
640             Ok(_) => self.check_message_loop_final_state(),
641             Err(e) => error!("Failed to join with WndProc thread: {:?}", e),
642         }
643     }
644 }
645 
646 // SAFETY:
647 // Since `WindowProcedureThread` does not hold anything that cannot be transferred between threads,
648 // we can implement `Send` for it.
649 unsafe impl Send for WindowProcedureThread {}
650 
651 #[derive(Deserialize, Serialize)]
652 pub struct WindowProcedureThreadBuilder {
653     max_num_windows: u32,
654     display_tube: Option<Tube>,
655     #[cfg(feature = "kiwi")]
656     ime_tube: Option<Tube>,
657 }
658 
659 impl WindowProcedureThreadBuilder {
set_max_num_windows(&mut self, max_num_windows: u32) -> &mut Self660     pub fn set_max_num_windows(&mut self, max_num_windows: u32) -> &mut Self {
661         self.max_num_windows = max_num_windows;
662         self
663     }
664 
set_display_tube(&mut self, display_tube: Option<Tube>) -> &mut Self665     pub fn set_display_tube(&mut self, display_tube: Option<Tube>) -> &mut Self {
666         self.display_tube = display_tube;
667         self
668     }
669 
670     #[cfg(feature = "kiwi")]
set_ime_tube(&mut self, ime_tube: Option<Tube>) -> &mut Self671     pub fn set_ime_tube(&mut self, ime_tube: Option<Tube>) -> &mut Self {
672         self.ime_tube = ime_tube;
673         self
674     }
675 
676     /// This function creates the window procedure thread and windows.
677     ///
678     /// We have seen third-party DLLs hooking into window creation. They may have deep call stack,
679     /// and they may not be well tested against late window creation, which may lead to stack
680     /// overflow. Hence, this should be called as early as possible when the VM is booting.
start_thread(self) -> Result<WindowProcedureThread>681     pub fn start_thread(self) -> Result<WindowProcedureThread> {
682         cfg_if::cfg_if! {
683             if #[cfg(feature = "kiwi")] {
684                 let ime_tube = self
685                     .ime_tube
686                     .ok_or_else(|| anyhow!("The ime tube is not set."))?;
687                 WindowProcedureThread::start_thread(
688                     self.max_num_windows,
689                     self.display_tube,
690                     ime_tube,
691                 )
692             } else {
693                 WindowProcedureThread::start_thread(self.max_num_windows, None)
694             }
695         }
696     }
697 }
698 
699 #[cfg(test)]
700 mod tests {
701     use super::*;
702 
703     #[test]
error_on_adding_reserved_token_to_context()704     fn error_on_adding_reserved_token_to_context() {
705         let mut ctx = MsgWaitContext::new();
706         let event = Event::new().unwrap();
707         assert!(ctx.add(&event, Token::MessagePump).is_err());
708     }
709 
710     #[test]
error_on_adding_duplicated_handle_to_context()711     fn error_on_adding_duplicated_handle_to_context() {
712         let mut ctx = MsgWaitContext::new();
713         let event = Event::new().unwrap();
714         assert!(ctx.add(&event, Token::ServiceMessage).is_ok());
715         assert!(ctx.add(&event, Token::ServiceMessage).is_err());
716     }
717 
718     #[test]
window_procedure_window_class_name_should_include_class_name_prefix()719     fn window_procedure_window_class_name_should_include_class_name_prefix() {
720         const PREFIX: &str = "test-window-class-prefix";
721         struct TestWindow;
722         impl RegisterWindowClass for TestWindow {
723             const CLASS_NAME_PREFIX: &'static str = PREFIX;
724             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
725                 Ok(())
726             }
727         }
728 
729         let name = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
730         assert!(
731             name.starts_with(PREFIX),
732             "The class name {} should start with {}.",
733             name,
734             PREFIX
735         );
736     }
737 
738     #[test]
window_procedure_with_same_types_should_return_same_name()739     fn window_procedure_with_same_types_should_return_same_name() {
740         struct TestWindow;
741         impl RegisterWindowClass for TestWindow {
742             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
743                 Ok(())
744             }
745         }
746 
747         let name1 = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
748         let name2 = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
749         assert_eq!(name1, name2);
750     }
751 
752     #[test]
window_procedure_with_different_types_should_return_different_names()753     fn window_procedure_with_different_types_should_return_different_names() {
754         struct TestWindow1;
755         impl RegisterWindowClass for TestWindow1 {
756             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
757                 Ok(())
758             }
759         }
760         struct TestWindow2;
761         impl RegisterWindowClass for TestWindow2 {
762             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
763                 Ok(())
764             }
765         }
766 
767         let name1 = WindowProcedureThread::get_window_class_name::<TestWindow1>().unwrap();
768         let name2 = WindowProcedureThread::get_window_class_name::<TestWindow2>().unwrap();
769         assert_ne!(name1, name2);
770     }
771 }
772