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