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