xref: /aosp_15_r20/external/crosvm/gpu_display/src/gpu_display_win/window_procedure_thread.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 = 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             .context("Failed to spawn WndProc thread")?;
277 
278         match message_router_handle_receiver.recv() {
279             Ok(message_router_handle_res) => match message_router_handle_res {
280                 Ok(message_router_handle) => Ok(Self {
281                     thread: Some(thread),
282                     message_router_handle: message_router_handle as HWND,
283                     message_loop_state: Some(message_loop_state),
284                     close_requested_event,
285                 }),
286                 Err(e) => bail!("WndProc internal failure: {:?}", e),
287             },
288             Err(e) => bail!("Failed to receive WndProc thread ID: {}", e),
289         }
290     }
291 
try_clone_close_requested_event(&self) -> Result<Event>292     pub fn try_clone_close_requested_event(&self) -> Result<Event> {
293         self.close_requested_event
294             .try_clone()
295             .map_err(|e| anyhow!("Failed to clone close_requested_event: {}", e))
296     }
297 
post_display_command(&self, message: DisplaySendToWndProc) -> Result<()>298     pub fn post_display_command(&self, message: DisplaySendToWndProc) -> Result<()> {
299         self.post_message_to_thread_carrying_object(
300             WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL,
301             message,
302         )
303         .context("When posting DisplaySendToWndProc message")
304     }
305 
306     /// Calls `PostMessageW()` internally.
post_message_to_thread(&self, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> Result<()>307     fn post_message_to_thread(&self, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> Result<()> {
308         if !self.is_message_loop_running() {
309             bail!("Cannot post message to WndProc thread because message loop is not running!");
310         }
311         // SAFETY:
312         // Safe because the message loop is still running.
313         if unsafe { PostMessageW(self.message_router_handle, msg, w_param, l_param) } == 0 {
314             syscall_bail!("Failed to call PostMessageW()");
315         }
316         Ok(())
317     }
318 
319     /// Calls `PostMessageW()` internally. This is a common pattern, where we send a pointer to
320     /// 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<()>321     fn post_message_to_thread_carrying_object<U>(&self, msg: UINT, object: U) -> Result<()> {
322         let mut boxed_object = Box::new(object);
323         self.post_message_to_thread(
324             msg,
325             /* w_param= */ 0,
326             &mut *boxed_object as *mut U as LPARAM,
327         )
328         .map(|_| {
329             // If successful, the receiver will be responsible for destructing the object.
330             std::mem::forget(boxed_object);
331         })
332     }
333 
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, )334     fn run_message_loop(
335         max_num_windows: u32,
336         message_router_handle_sender: Sender<Result<u32>>,
337         message_loop_state: Arc<AtomicI32>,
338         gpu_main_display_tube: Option<Tube>,
339         close_requested_event: Event,
340     ) {
341         let gpu_main_display_tube = gpu_main_display_tube.map(Rc::new);
342         // SAFETY:
343         // Safe because the dispatcher will take care of the lifetime of the `MessageOnlyWindow` and
344         // `GuiWindow` objects.
345         match unsafe { Self::create_windows(max_num_windows) }.and_then(
346             |(message_router_window, gui_windows)| {
347                 WindowMessageDispatcher::new(
348                     message_router_window,
349                     gui_windows,
350                     gpu_main_display_tube.clone(),
351                     close_requested_event,
352                 )
353             },
354         ) {
355             Ok(dispatcher) => {
356                 info!("WndProc thread entering message loop");
357                 message_loop_state.store(MessageLoopState::Running as i32, Ordering::SeqCst);
358 
359                 let message_router_handle =
360                     // SAFETY:
361                     // Safe because we won't use the handle unless the message loop is still running.
362                     unsafe { dispatcher.message_router_handle().unwrap_or(null_mut()) };
363                 // HWND cannot be sent cross threads, so we cast it to u32 first.
364                 if let Err(e) = message_router_handle_sender.send(Ok(message_router_handle as u32))
365                 {
366                     error!("Failed to send message router handle: {}", e);
367                 }
368 
369                 let exit_state = Self::run_message_loop_body(dispatcher, gpu_main_display_tube);
370                 message_loop_state.store(exit_state as i32, Ordering::SeqCst);
371             }
372             Err(e) => {
373                 error!("WndProc thread didn't enter message loop: {:?}", e);
374                 message_loop_state.store(
375                     MessageLoopState::EarlyTerminatedWithError as i32,
376                     Ordering::SeqCst,
377                 );
378                 if let Err(e) = message_router_handle_sender.send(Err(e)) {
379                     error!("Failed to report message loop early termination: {}", e)
380                 }
381             }
382         }
383     }
384 
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>>, ) -> MessageLoopState385     fn run_message_loop_body(
386         #[cfg_attr(not(feature = "kiwi"), allow(unused_variables, unused_mut))]
387         mut message_dispatcher: Pin<Box<WindowMessageDispatcher>>,
388         gpu_main_display_tube: Option<Rc<Tube>>,
389     ) -> MessageLoopState {
390         let mut msg_wait_ctx = MsgWaitContext::new();
391         if let Some(tube) = &gpu_main_display_tube {
392             if let Err(e) = msg_wait_ctx.add(tube.get_read_notifier(), Token::ServiceMessage) {
393                 error!(
394                     "Failed to add service message read notifier to MsgWaitContext: {:?}",
395                     e
396                 );
397                 return MessageLoopState::EarlyTerminatedWithError;
398             }
399         }
400 
401         loop {
402             // SAFETY:
403             // Safe because the lifetime of handles are at least as long as the function call.
404             match unsafe { msg_wait_ctx.wait() } {
405                 Ok(token) => match token {
406                     Token::MessagePump => {
407                         if !Self::retrieve_and_dispatch_messages() {
408                             info!("WndProc thread exiting message loop normally");
409                             return MessageLoopState::ExitedNormally;
410                         }
411                     }
412                     Token::ServiceMessage => Self::read_and_dispatch_service_message(
413                         &mut message_dispatcher,
414                         // We never use this token if `gpu_main_display_tube` is None, so
415                         // `expect()` should always succeed.
416                         gpu_main_display_tube
417                             .as_ref()
418                             .expect("Service message tube is None"),
419                     ),
420                 },
421                 Err(e) => {
422                     error!(
423                         "WndProc thread exiting message loop because of error: {:?}",
424                         e
425                     );
426                     return MessageLoopState::ExitedWithError;
427                 }
428             }
429         }
430     }
431 
432     /// Retrieves and dispatches all messages in the queue, and returns whether the message loop
433     /// should continue running.
retrieve_and_dispatch_messages() -> bool434     fn retrieve_and_dispatch_messages() -> bool {
435         // Since `MsgWaitForMultipleObjects()` returns only when there is a new event in the queue,
436         // if we call `MsgWaitForMultipleObjects()` again without draining the queue, it will ignore
437         // existing events and will not return immediately. Hence, we need to keep calling
438         // `PeekMessageW()` with `PM_REMOVE` until the queue is drained before returning.
439         // https://devblogs.microsoft.com/oldnewthing/20050217-00/?p=36423
440         // Alternatively we could use `MsgWaitForMultipleObjectsEx()` with the `MWMO_INPUTAVAILABLE`
441         // flag, which will always return if there is any message in the queue, no matter that is a
442         // new message or not. However, we found that it may also return when there is no message at
443         // all, so we slightly prefer `MsgWaitForMultipleObjects()`.
444         loop {
445             // Safe because if `message` is initialized, we will call `assume_init()` to extract the
446             // value, which will get dropped eventually.
447             let mut message = mem::MaybeUninit::uninit();
448             // SAFETY:
449             // Safe because `message` lives at least as long as the function call.
450             if unsafe {
451                 PeekMessageW(
452                     message.as_mut_ptr(),
453                     /* hWnd= */ null_mut(),
454                     /* wMsgFilterMin= */ 0,
455                     /* wMsgFilterMax= */ 0,
456                     PM_REMOVE,
457                 ) == 0
458             } {
459                 // No more message in the queue.
460                 return true;
461             }
462 
463             // SAFETY:
464             // Safe because `PeekMessageW()` has populated `message`.
465             unsafe {
466                 let new_message = message.assume_init();
467                 if new_message.message == WM_QUIT {
468                     return false;
469                 }
470                 TranslateMessage(&new_message);
471                 DispatchMessageW(&new_message);
472             }
473         }
474     }
475 
476     #[cfg(feature = "kiwi")]
read_and_dispatch_service_message( message_dispatcher: &mut Pin<Box<WindowMessageDispatcher>>, gpu_main_display_tube: &Tube, )477     fn read_and_dispatch_service_message(
478         message_dispatcher: &mut Pin<Box<WindowMessageDispatcher>>,
479         gpu_main_display_tube: &Tube,
480     ) {
481         match gpu_main_display_tube.recv::<ServiceSendToGpu>() {
482             Ok(message) => message_dispatcher.as_mut().process_service_message(message),
483             Err(e) => {
484                 error!("Failed to receive service message through the tube: {}", e)
485             }
486         }
487     }
488 
489     #[cfg(not(feature = "kiwi"))]
read_and_dispatch_service_message( _: &mut Pin<Box<WindowMessageDispatcher>>, _gpu_main_display_tube: &Tube, )490     fn read_and_dispatch_service_message(
491         _: &mut Pin<Box<WindowMessageDispatcher>>,
492         _gpu_main_display_tube: &Tube,
493     ) {
494     }
495 
is_message_loop_running(&self) -> bool496     fn is_message_loop_running(&self) -> bool {
497         self.message_loop_state.as_ref().map_or(false, |state| {
498             state.load(Ordering::SeqCst) == MessageLoopState::Running as i32
499         })
500     }
501 
502     /// Normally the WndProc thread should still be running when the `WindowProcedureThread` struct
503     /// is dropped, and this function will post a message to notify that thread to destroy all
504     /// windows and release all resources. If the WndProc thread has encountered fatal errors and
505     /// has already terminated, we don't need to post this message anymore.
signal_exit_message_loop_if_needed(&self)506     fn signal_exit_message_loop_if_needed(&self) {
507         if !self.is_message_loop_running() {
508             return;
509         }
510 
511         info!("WndProc thread is still in message loop before dropping. Signaling shutting down");
512         if let Err(e) = self.post_message_to_thread(
513             WM_USER_SHUTDOWN_WNDPROC_THREAD_INTERNAL,
514             /* w_param */ 0,
515             /* l_param */ 0,
516         ) {
517             error!("Failed to signal WndProc thread to shut down: {:?}", e);
518         }
519     }
520 
521     /// Checks if the message loop has exited normally. This should be called after joining with the
522     /// WndProc thread.
check_message_loop_final_state(&mut self)523     fn check_message_loop_final_state(&mut self) {
524         match Arc::try_unwrap(self.message_loop_state.take().unwrap()) {
525             Ok(state) => {
526                 let state = state.into_inner();
527                 if state == MessageLoopState::ExitedNormally as i32 {
528                     info!("WndProc thread exited gracefully");
529                 } else {
530                     warn!("WndProc thread exited with message loop state: {:?}", state);
531                 }
532             }
533             Err(e) => error!(
534                 "WndProc thread exited but message loop state retrieval failed: {:?}",
535                 e
536             ),
537         }
538     }
539 
540     /// # Safety
541     /// The owner of the returned window objects is responsible for dropping them before we finish
542     /// processing `WM_NCDESTROY`, because the window handle will become invalid afterwards.
create_windows(max_num_windows: u32) -> Result<(MessageOnlyWindow, Vec<GuiWindow>)>543     unsafe fn create_windows(max_num_windows: u32) -> Result<(MessageOnlyWindow, Vec<GuiWindow>)> {
544         let message_router_window = MessageOnlyWindow::new(
545             /* class_name */
546             Self::get_window_class_name::<MessageOnlyWindow>()
547                 .with_context(|| {
548                     format!(
549                         "retrieve the window class name for MessageOnlyWindow of {}.",
550                         type_name::<Self>()
551                     )
552                 })?
553                 .as_str(),
554             /* title */ "ThreadMessageRouter",
555         )?;
556         // Gfxstream window is a child window of crosvm window. Without WS_CLIPCHILDREN, the parent
557         // window may use the background brush to clear the gfxstream window client area when
558         // drawing occurs. This caused the screen flickering issue during resizing.
559         // See b/197786842 for details.
560         let mut gui_windows = Vec::with_capacity(max_num_windows as usize);
561         for scanout_id in 0..max_num_windows {
562             gui_windows.push(GuiWindow::new(
563                 scanout_id,
564                 /* class_name */
565                 Self::get_window_class_name::<GuiWindow>()
566                     .with_context(|| {
567                         format!(
568                             "retrieve the window class name for GuiWindow of {}",
569                             type_name::<Self>()
570                         )
571                     })?
572                     .as_str(),
573                 /* title */ Self::get_window_title().as_str(),
574                 /* dw_style */ WS_POPUP | WS_CLIPCHILDREN,
575                 // The window size and style can be adjusted later when `Surface` is created.
576                 &size2(1, 1),
577             )?);
578         }
579         Ok((message_router_window, gui_windows))
580     }
581 
wnd_proc( hwnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM, ) -> LRESULT582     unsafe extern "system" fn wnd_proc(
583         hwnd: HWND,
584         msg: UINT,
585         w_param: WPARAM,
586         l_param: LPARAM,
587     ) -> LRESULT {
588         let dispatcher_ptr = GetPropW(hwnd, win32_wide_string(DISPATCHER_PROPERTY_NAME).as_ptr())
589             as *mut WindowMessageDispatcher;
590         if let Some(dispatcher) = dispatcher_ptr.as_mut() {
591             if let Some(ret) =
592                 dispatcher.dispatch_window_message(hwnd, &MessagePacket::new(msg, w_param, l_param))
593             {
594                 return ret;
595             }
596         }
597         DefWindowProcW(hwnd, msg, w_param, l_param)
598     }
599 
600     /// U + T decides one window class. For the same combination of U + T, the same window class
601     /// name will be returned. This function also registers the Window class if it is not registered
602     /// through this function yet.
get_window_class_name<T: RegisterWindowClass>() -> Result<String>603     fn get_window_class_name<T: RegisterWindowClass>() -> Result<String> {
604         static WINDOW_CLASS_NAMES: Mutex<BTreeMap<TypeId, String>> = Mutex::new(BTreeMap::new());
605         let mut window_class_names = WINDOW_CLASS_NAMES.lock();
606         let id = window_class_names.len();
607         let entry = window_class_names.entry(TypeId::of::<T>());
608         let entry = match entry {
609             Entry::Occupied(entry) => return Ok(entry.get().clone()),
610             Entry::Vacant(entry) => entry,
611         };
612         // We are generating a different class name everytime we reach this line, so the name
613         // shouldn't collide with any window classes registered through this function. The
614         // underscore here is important. If we just use `"{}{}"`, we may collide for prefix = "" and
615         // prefix = "1".
616         let window_class_name = format!("{}_{}", T::CLASS_NAME_PREFIX, id);
617         T::register_window_class(&window_class_name, Some(Self::wnd_proc)).with_context(|| {
618             format!(
619                 "Failed to register the window class for ({}, {}), with name {}.",
620                 type_name::<Self>(),
621                 type_name::<T>(),
622                 window_class_name
623             )
624         })?;
625         entry.insert(window_class_name.clone());
626         Ok(window_class_name)
627     }
628 
get_window_title() -> String629     fn get_window_title() -> String {
630         "crosvm".to_string()
631     }
632 }
633 
634 impl Drop for WindowProcedureThread {
drop(&mut self)635     fn drop(&mut self) {
636         self.signal_exit_message_loop_if_needed();
637         match self.thread.take().unwrap().join() {
638             Ok(_) => self.check_message_loop_final_state(),
639             Err(e) => error!("Failed to join with WndProc thread: {:?}", e),
640         }
641     }
642 }
643 
644 // SAFETY:
645 // Since `WindowProcedureThread` does not hold anything that cannot be transferred between threads,
646 // we can implement `Send` for it.
647 unsafe impl Send for WindowProcedureThread {}
648 
649 #[derive(Deserialize, Serialize)]
650 pub struct WindowProcedureThreadBuilder {
651     max_num_windows: u32,
652     display_tube: Option<Tube>,
653     #[cfg(feature = "kiwi")]
654     ime_tube: Option<Tube>,
655 }
656 
657 impl WindowProcedureThreadBuilder {
set_max_num_windows(&mut self, max_num_windows: u32) -> &mut Self658     pub fn set_max_num_windows(&mut self, max_num_windows: u32) -> &mut Self {
659         self.max_num_windows = max_num_windows;
660         self
661     }
662 
set_display_tube(&mut self, display_tube: Option<Tube>) -> &mut Self663     pub fn set_display_tube(&mut self, display_tube: Option<Tube>) -> &mut Self {
664         self.display_tube = display_tube;
665         self
666     }
667 
668     #[cfg(feature = "kiwi")]
set_ime_tube(&mut self, ime_tube: Option<Tube>) -> &mut Self669     pub fn set_ime_tube(&mut self, ime_tube: Option<Tube>) -> &mut Self {
670         self.ime_tube = ime_tube;
671         self
672     }
673 
674     /// This function creates the window procedure thread and windows.
675     ///
676     /// We have seen third-party DLLs hooking into window creation. They may have deep call stack,
677     /// and they may not be well tested against late window creation, which may lead to stack
678     /// overflow. Hence, this should be called as early as possible when the VM is booting.
start_thread(self) -> Result<WindowProcedureThread>679     pub fn start_thread(self) -> Result<WindowProcedureThread> {
680         cfg_if::cfg_if! {
681             if #[cfg(feature = "kiwi")] {
682                 let ime_tube = self
683                     .ime_tube
684                     .ok_or_else(|| anyhow!("The ime tube is not set."))?;
685                 WindowProcedureThread::start_thread(
686                     self.max_num_windows,
687                     self.display_tube,
688                     ime_tube,
689                 )
690             } else {
691                 WindowProcedureThread::start_thread(self.max_num_windows, None)
692             }
693         }
694     }
695 }
696 
697 #[cfg(test)]
698 mod tests {
699     use super::*;
700 
701     #[test]
error_on_adding_reserved_token_to_context()702     fn error_on_adding_reserved_token_to_context() {
703         let mut ctx = MsgWaitContext::new();
704         let event = Event::new().unwrap();
705         assert!(ctx.add(&event, Token::MessagePump).is_err());
706     }
707 
708     #[test]
error_on_adding_duplicated_handle_to_context()709     fn error_on_adding_duplicated_handle_to_context() {
710         let mut ctx = MsgWaitContext::new();
711         let event = Event::new().unwrap();
712         assert!(ctx.add(&event, Token::ServiceMessage).is_ok());
713         assert!(ctx.add(&event, Token::ServiceMessage).is_err());
714     }
715 
716     #[test]
window_procedure_window_class_name_should_include_class_name_prefix()717     fn window_procedure_window_class_name_should_include_class_name_prefix() {
718         const PREFIX: &str = "test-window-class-prefix";
719         struct TestWindow;
720         impl RegisterWindowClass for TestWindow {
721             const CLASS_NAME_PREFIX: &'static str = PREFIX;
722             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
723                 Ok(())
724             }
725         }
726 
727         let name = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
728         assert!(
729             name.starts_with(PREFIX),
730             "The class name {} should start with {}.",
731             name,
732             PREFIX
733         );
734     }
735 
736     #[test]
window_procedure_with_same_types_should_return_same_name()737     fn window_procedure_with_same_types_should_return_same_name() {
738         struct TestWindow;
739         impl RegisterWindowClass for TestWindow {
740             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
741                 Ok(())
742             }
743         }
744 
745         let name1 = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
746         let name2 = WindowProcedureThread::get_window_class_name::<TestWindow>().unwrap();
747         assert_eq!(name1, name2);
748     }
749 
750     #[test]
window_procedure_with_different_types_should_return_different_names()751     fn window_procedure_with_different_types_should_return_different_names() {
752         struct TestWindow1;
753         impl RegisterWindowClass for TestWindow1 {
754             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
755                 Ok(())
756             }
757         }
758         struct TestWindow2;
759         impl RegisterWindowClass for TestWindow2 {
760             fn register_window_class(_class_name: &str, _wnd_proc: WNDPROC) -> Result<()> {
761                 Ok(())
762             }
763         }
764 
765         let name1 = WindowProcedureThread::get_window_class_name::<TestWindow1>().unwrap();
766         let name2 = WindowProcedureThread::get_window_class_name::<TestWindow2>().unwrap();
767         assert_ne!(name1, name2);
768     }
769 }
770