1use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::cmp::max;
7use std::rc::{Rc, Weak};
8use std::sync::Arc;
9use std::time::Duration;
10
11use background_hang_monitor::HangMonitorRegister;
12use base::generic_channel::{GenericCallback, GenericSender, RoutedReceiver};
13pub use base::id::WebViewId;
14use base::id::{PipelineNamespace, PipelineNamespaceId};
15#[cfg(feature = "bluetooth")]
16use bluetooth::BluetoothThreadFactory;
17#[cfg(feature = "bluetooth")]
18use bluetooth_traits::BluetoothRequest;
19#[cfg(all(
20 not(target_os = "windows"),
21 not(target_os = "ios"),
22 not(target_os = "android"),
23 not(target_arch = "arm"),
24 not(target_arch = "aarch64"),
25 not(target_env = "ohos"),
26))]
27use constellation::content_process_sandbox_profile;
28use constellation::{
29 Constellation, FromEmbedderLogger, FromScriptLogger, InitialConstellationState,
30 NewScriptEventLoopProcessInfo, UnprivilegedContent,
31};
32use constellation_traits::{EmbedderToConstellationMessage, ScriptToConstellationSender};
33use crossbeam_channel::{Receiver, Sender, unbounded};
34pub use embedder_traits::*;
35use env_logger::Builder as EnvLoggerBuilder;
36use fonts::SystemFontService;
37#[cfg(all(
38 not(target_os = "windows"),
39 not(target_os = "ios"),
40 not(target_os = "android"),
41 not(target_arch = "arm"),
42 not(target_arch = "aarch64"),
43 not(target_env = "ohos"),
44))]
45use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
46use ipc_channel::ipc::{self, IpcSender};
47use layout::LayoutFactoryImpl;
48use layout_api::ScriptThreadFactory;
49use log::{Log, Metadata, Record, debug, warn};
50use media::{GlApi, NativeDisplay, WindowGLContext};
51use net::embedder::NetToEmbedderMsg;
52use net::image_cache::ImageCacheFactoryImpl;
53use net::protocols::ProtocolRegistry;
54use net::resource_thread::new_resource_threads;
55use net_traits::{ResourceThreads, exit_fetch_thread, start_fetch_thread};
56use paint::{InitialPaintState, Paint};
57pub use paint_api::rendering_context::RenderingContext;
58use paint_api::{CrossProcessPaintApi, PaintMessage, PaintProxy};
59use profile::{mem as profile_mem, system_reporter, time as profile_time};
60use profile_traits::mem::{MemoryReportResult, ProfilerMsg, Reporter};
61use profile_traits::{mem, time};
62use rustc_hash::FxHashMap;
63use script::{JSEngineSetup, ServiceWorkerManager};
64use servo_config::opts::Opts;
65use servo_config::prefs::{PrefValue, Preferences};
66use servo_config::{opts, pref, prefs};
67use servo_geometry::{
68 DeviceIndependentIntRect, convert_rect_to_css_pixel, convert_size_to_css_pixel,
69};
70use servo_media::ServoMedia;
71use servo_media::player::context::GlContext;
72use storage::new_storage_threads;
73use storage_traits::StorageThreads;
74use style::global_style_data::StyleThreadPool;
75
76use crate::clipboard_delegate::StringRequest;
77#[cfg(feature = "gamepad")]
78use crate::gamepad_provider::{GamepadHapticEffectRequest, GamepadHapticEffectRequestType};
79use crate::javascript_evaluator::JavaScriptEvaluator;
80use crate::network_manager::NetworkManager;
81use crate::proxies::ConstellationProxy;
82use crate::responders::ServoErrorChannel;
83use crate::servo_delegate::{DefaultServoDelegate, ServoDelegate, ServoError};
84use crate::site_data_manager::SiteDataManager;
85use crate::webview::{MINIMUM_WEBVIEW_SIZE, WebView, WebViewInner};
86use crate::webview_delegate::{
87 AllowOrDenyRequest, AuthenticationRequest, EmbedderControl, FilePicker, NavigationRequest,
88 PermissionRequest, ProtocolHandlerRegistration, WebResourceLoad,
89};
90
91#[cfg(feature = "media-gstreamer")]
92mod media_platform {
93 use servo_media_gstreamer::GStreamerBackend;
94
95 use super::ServoMedia;
96
97 #[cfg(any(windows, target_os = "macos"))]
98 pub fn init() {
99 ServoMedia::init_with_backend(|| {
100 let mut plugin_dir = std::env::current_exe().unwrap();
101 plugin_dir.pop();
102
103 if cfg!(target_os = "macos") {
104 plugin_dir.push("lib");
105 }
106
107 let plugin_list = crate::gstreamer_plugins::gstreamer_plugins();
108 match GStreamerBackend::init_with_plugins(plugin_dir, &plugin_list) {
109 Ok(b) => b,
110 Err(e) => {
111 log::error!("Error initializing GStreamer: {:?}", e);
112 std::process::exit(1);
113 },
114 }
115 });
116 }
117
118 #[cfg(not(any(windows, target_os = "macos")))]
119 pub fn init() {
120 ServoMedia::init::<GStreamerBackend>();
121 }
122}
123
124#[cfg(not(feature = "media-gstreamer"))]
125mod media_platform {
126 use super::ServoMedia;
127 pub fn init() {
128 ServoMedia::init::<servo_media_dummy::DummyBackend>();
129 }
130}
131
132enum Message {
133 FromNet(NetToEmbedderMsg),
134 FromUnknown(EmbedderMsg),
135}
136
137struct ServoInner {
138 delegate: RefCell<Rc<dyn ServoDelegate>>,
139 paint: Rc<RefCell<Paint>>,
140 constellation_proxy: ConstellationProxy,
141 embedder_receiver: Receiver<EmbedderMsg>,
142 net_embedder_receiver: Receiver<NetToEmbedderMsg>,
143 network_manager: Rc<RefCell<NetworkManager>>,
144 site_data_manager: Rc<RefCell<SiteDataManager>>,
145 javascript_evaluator: Rc<RefCell<JavaScriptEvaluator>>,
148 shutdown_state: Rc<Cell<ShutdownState>>,
151 webviews: RefCell<FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>>,
156 servo_errors: ServoErrorChannel,
157 _js_engine_setup: Option<JSEngineSetup>,
161}
162
163impl ServoInner {
164 fn get_webview_handle(&self, id: WebViewId) -> Option<WebView> {
165 self.webviews
166 .borrow()
167 .get(&id)
168 .and_then(WebView::from_weak_handle)
169 }
170
171 fn spin_event_loop(&self) -> bool {
172 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
173 return false;
174 }
175
176 {
177 let paint = self.paint.borrow();
178 let mut messages = Vec::new();
179 while let Ok(message) = paint.receiver().try_recv() {
180 match message {
181 Ok(message) => messages.push(message),
182 Err(error) => {
183 warn!("Router deserialization error: {error}. Ignoring this PaintMessage.")
184 },
185 }
186 }
187 paint.handle_messages(messages);
188 }
189
190 while let Some(message) = self.receive_one_message() {
192 match message {
193 Message::FromUnknown(message) => self.handle_embedder_message(message),
194 Message::FromNet(message) => self.handle_net_embedder_message(message),
195 }
196 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
197 break;
198 }
199 }
200
201 if self.constellation_proxy.disconnected() {
202 self.delegate
203 .borrow()
204 .notify_error(ServoError::LostConnectionWithBackend);
205 }
206
207 self.paint.borrow_mut().perform_updates();
208 self.send_new_frame_ready_messages();
209 self.handle_delegate_errors();
210 self.clean_up_destroyed_webview_handles();
211
212 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
213 return false;
214 }
215
216 true
217 }
218
219 fn receive_one_message(&self) -> Option<Message> {
220 let mut select = crossbeam_channel::Select::new();
221 let embedder_receiver_index = select.recv(&self.embedder_receiver);
222 let net_embedder_receiver_index = select.recv(&self.net_embedder_receiver);
223 let Ok(operation) = select.try_select() else {
224 return None;
225 };
226 let index = operation.index();
227 if index == embedder_receiver_index {
228 let Ok(message) = operation.recv(&self.embedder_receiver) else {
229 return None;
230 };
231 Some(Message::FromUnknown(message))
232 } else if index == net_embedder_receiver_index {
233 let Ok(message) = operation.recv(&self.net_embedder_receiver) else {
234 return None;
235 };
236 Some(Message::FromNet(message))
237 } else {
238 log::error!("No select operation registered for {index:?}");
239 None
240 }
241 }
242
243 fn send_new_frame_ready_messages(&self) {
244 let webviews_needing_repaint = self.paint.borrow().webviews_needing_repaint();
245
246 for webview in webviews_needing_repaint
247 .iter()
248 .filter_map(|webview_id| self.get_webview_handle(*webview_id))
249 {
250 webview.delegate().notify_new_frame_ready(webview);
251 }
252 }
253
254 fn handle_delegate_errors(&self) {
255 while let Some(error) = self.servo_errors.try_recv() {
256 self.delegate.borrow().notify_error(error);
257 }
258 }
259
260 fn clean_up_destroyed_webview_handles(&self) {
261 self.webviews
266 .borrow_mut()
267 .retain(|_webview_id, webview| webview.strong_count() > 0);
268 }
269
270 fn finish_shutting_down(&self) {
271 debug!("Servo received message that Constellation shutdown is complete");
272 self.shutdown_state.set(ShutdownState::FinishedShuttingDown);
273 self.paint.borrow_mut().finish_shutting_down();
274 }
275
276 fn handle_net_embedder_message(&self, message: NetToEmbedderMsg) {
277 match message {
278 NetToEmbedderMsg::SelectFiles(control_id, file_picker_request, response_sender) => {
279 if file_picker_request.accept_current_paths_for_testing {
280 let _ = response_sender.send(Some(file_picker_request.current_paths));
281 return;
282 }
283 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
284 webview.delegate().show_embedder_control(
285 webview,
286 EmbedderControl::FilePicker(FilePicker {
287 id: control_id,
288 file_picker_request,
289 response_sender: Some(response_sender),
290 }),
291 );
292 }
293 },
294 NetToEmbedderMsg::WebResourceRequested(
295 webview_id,
296 web_resource_request,
297 response_sender,
298 ) => {
299 if let Some(webview) =
300 webview_id.and_then(|webview_id| self.get_webview_handle(webview_id))
301 {
302 let web_resource_load = WebResourceLoad::new(
303 web_resource_request,
304 response_sender,
305 self.servo_errors.sender(),
306 );
307 webview
308 .delegate()
309 .load_web_resource(webview, web_resource_load);
310 } else {
311 let web_resource_load = WebResourceLoad::new(
312 web_resource_request,
313 response_sender,
314 self.servo_errors.sender(),
315 );
316 self.delegate.borrow().load_web_resource(web_resource_load);
317 }
318 },
319 NetToEmbedderMsg::RequestAuthentication(
320 webview_id,
321 url,
322 for_proxy,
323 response_sender,
324 ) => {
325 if let Some(webview) = self.get_webview_handle(webview_id) {
326 let authentication_request = AuthenticationRequest::new(
327 url.into_url(),
328 for_proxy,
329 response_sender,
330 self.servo_errors.sender(),
331 );
332 webview
333 .delegate()
334 .request_authentication(webview, authentication_request);
335 }
336 },
337 }
338 }
339
340 fn handle_embedder_message(&self, message: EmbedderMsg) {
341 match message {
342 EmbedderMsg::ShutdownComplete => self.finish_shutting_down(),
343 EmbedderMsg::Status(webview_id, status_text) => {
344 if let Some(webview) = self.get_webview_handle(webview_id) {
345 webview.set_status_text(status_text);
346 }
347 },
348 EmbedderMsg::ChangePageTitle(webview_id, title) => {
349 if let Some(webview) = self.get_webview_handle(webview_id) {
350 webview.set_page_title(title);
351 }
352 },
353 EmbedderMsg::MoveTo(webview_id, position) => {
354 if let Some(webview) = self.get_webview_handle(webview_id) {
355 webview.delegate().request_move_to(webview, position);
356 }
357 },
358 EmbedderMsg::ResizeTo(webview_id, size) => {
359 if let Some(webview) = self.get_webview_handle(webview_id) {
360 webview
361 .delegate()
362 .request_resize_to(webview, size.max(MINIMUM_WEBVIEW_SIZE));
363 }
364 },
365 EmbedderMsg::ShowSimpleDialog(webview_id, simple_dialog) => {
366 if let Some(webview) = self.get_webview_handle(webview_id) {
367 webview.delegate().show_embedder_control(
368 webview,
369 EmbedderControl::SimpleDialog(simple_dialog.into()),
370 );
371 }
372 },
373 EmbedderMsg::AllowNavigationRequest(webview_id, pipeline_id, servo_url) => {
374 if let Some(webview) = self.get_webview_handle(webview_id) {
375 let request = NavigationRequest {
376 url: servo_url.into_url(),
377 pipeline_id,
378 constellation_proxy: self.constellation_proxy.clone(),
379 response_sent: false,
380 };
381 webview.delegate().request_navigation(webview, request);
382 }
383 },
384 EmbedderMsg::AllowProtocolHandlerRequest(
385 webview_id,
386 registration_update,
387 response_sender,
388 ) => {
389 if let Some(webview) = self.get_webview_handle(webview_id) {
390 let ProtocolHandlerUpdateRegistration {
391 scheme,
392 url,
393 register_or_unregister,
394 } = registration_update;
395 let protocol_handler_registration = ProtocolHandlerRegistration {
396 scheme,
397 url: url.into_url(),
398 register_or_unregister,
399 };
400 let allow_deny_request = AllowOrDenyRequest::new(
401 response_sender,
402 AllowOrDeny::Deny,
403 self.servo_errors.sender(),
404 );
405 webview.delegate().request_protocol_handler(
406 webview,
407 protocol_handler_registration,
408 allow_deny_request,
409 );
410 }
411 },
412 EmbedderMsg::AllowOpeningWebView(webview_id, response_sender) => {
413 if let Some(webview) = self.get_webview_handle(webview_id) {
414 webview.request_create_new(response_sender);
415 }
416 },
417 EmbedderMsg::WebViewClosed(webview_id) => {
418 if let Some(webview) = self.get_webview_handle(webview_id) {
419 webview.delegate().notify_closed(webview);
420 }
421 },
422 EmbedderMsg::WebViewFocused(webview_id, focus_result) => {
423 if focus_result {
424 for id in self.webviews.borrow().keys() {
425 if let Some(webview) = self.get_webview_handle(*id) {
426 let focused = webview.id() == webview_id;
427 webview.set_focused(focused);
428 }
429 }
430 }
431 },
432 EmbedderMsg::WebViewBlurred => {
433 for id in self.webviews.borrow().keys() {
434 if let Some(webview) = self.get_webview_handle(*id) {
435 webview.set_focused(false);
436 }
437 }
438 },
439 EmbedderMsg::AllowUnload(webview_id, response_sender) => {
440 if let Some(webview) = self.get_webview_handle(webview_id) {
441 let request = AllowOrDenyRequest::new(
442 response_sender,
443 AllowOrDeny::Allow,
444 self.servo_errors.sender(),
445 );
446 webview.delegate().request_unload(webview, request);
447 }
448 },
449 EmbedderMsg::FinishJavaScriptEvaluation(evaluation_id, result) => {
450 self.javascript_evaluator
451 .borrow_mut()
452 .finish_evaluation(evaluation_id, result);
453 },
454 EmbedderMsg::InputEventsHandled(webview_id, event_outcomes) => {
455 let webview = self.get_webview_handle(webview_id);
456 for InputEventOutcome {
457 id: input_event_id,
458 result,
459 } in event_outcomes
460 {
461 self.paint.borrow_mut().notify_input_event_handled(
462 webview_id,
463 input_event_id,
464 result,
465 );
466 if let Some(ref webview) = webview {
467 webview.delegate().notify_input_event_handled(
468 webview.clone(),
469 input_event_id,
470 result,
471 );
472 }
473 }
474 },
475 EmbedderMsg::ClearClipboard(webview_id) => {
476 if let Some(webview) = self.get_webview_handle(webview_id) {
477 webview.clipboard_delegate().clear(webview);
478 }
479 },
480 EmbedderMsg::GetClipboardText(webview_id, result_sender) => {
481 if let Some(webview) = self.get_webview_handle(webview_id) {
482 webview
483 .clipboard_delegate()
484 .get_text(webview, StringRequest::from(result_sender));
485 }
486 },
487 EmbedderMsg::SetClipboardText(webview_id, string) => {
488 if let Some(webview) = self.get_webview_handle(webview_id) {
489 webview.clipboard_delegate().set_text(webview, string);
490 }
491 },
492 EmbedderMsg::SetCursor(webview_id, cursor) => {
493 if let Some(webview) = self.get_webview_handle(webview_id) {
494 webview.set_cursor(cursor);
495 }
496 },
497 EmbedderMsg::NewFavicon(webview_id, image) => {
498 if let Some(webview) = self.get_webview_handle(webview_id) {
499 webview.set_favicon(image);
500 }
501 },
502 EmbedderMsg::NotifyLoadStatusChanged(webview_id, load_status) => {
503 if let Some(webview) = self.get_webview_handle(webview_id) {
504 webview.set_load_status(load_status);
505 }
506 },
507 EmbedderMsg::HistoryTraversalComplete(webview_id, traversal_id) => {
508 if let Some(webview) = self.get_webview_handle(webview_id) {
509 webview
510 .delegate()
511 .notify_traversal_complete(webview.clone(), traversal_id);
512 }
513 },
514 EmbedderMsg::HistoryChanged(webview_id, new_back_forward_list, current_list_index) => {
515 if let Some(webview) = self.get_webview_handle(webview_id) {
516 webview.set_history(new_back_forward_list, current_list_index);
517 }
518 },
519 EmbedderMsg::NotifyFullscreenStateChanged(webview_id, fullscreen) => {
520 if let Some(webview) = self.get_webview_handle(webview_id) {
521 webview
522 .delegate()
523 .notify_fullscreen_state_changed(webview, fullscreen);
524 }
525 },
526 EmbedderMsg::Panic(webview_id, reason, backtrace) => {
527 if let Some(webview) = self.get_webview_handle(webview_id) {
528 webview
529 .delegate()
530 .notify_crashed(webview, reason, backtrace);
531 }
532 },
533 EmbedderMsg::GetSelectedBluetoothDevice(webview_id, items, response_sender) => {
534 if let Some(webview) = self.get_webview_handle(webview_id) {
535 webview.delegate().show_bluetooth_device_dialog(
536 webview,
537 items,
538 response_sender,
539 );
540 }
541 },
542 EmbedderMsg::PromptPermission(webview_id, requested_feature, response_sender) => {
543 if let Some(webview) = self.get_webview_handle(webview_id) {
544 let permission_request = PermissionRequest {
545 requested_feature,
546 allow_deny_request: AllowOrDenyRequest::new(
547 response_sender,
548 AllowOrDeny::Deny,
549 self.servo_errors.sender(),
550 ),
551 };
552 webview
553 .delegate()
554 .request_permission(webview, permission_request);
555 }
556 },
557 EmbedderMsg::ReportProfile(_items) => {},
558 EmbedderMsg::MediaSessionEvent(webview_id, media_session_event) => {
559 if let Some(webview) = self.get_webview_handle(webview_id) {
560 webview
561 .delegate()
562 .notify_media_session_event(webview, media_session_event);
563 }
564 },
565 EmbedderMsg::OnDevtoolsStarted(port, token) => match port {
566 Ok(port) => self
567 .delegate
568 .borrow()
569 .notify_devtools_server_started(port, token),
570 Err(()) => self
571 .delegate
572 .borrow()
573 .notify_error(ServoError::DevtoolsFailedToStart),
574 },
575 EmbedderMsg::RequestDevtoolsConnection(response_sender) => {
576 self.delegate
577 .borrow()
578 .request_devtools_connection(AllowOrDenyRequest::new(
579 response_sender,
580 AllowOrDeny::Deny,
581 self.servo_errors.sender(),
582 ));
583 },
584 #[cfg(feature = "gamepad")]
585 EmbedderMsg::PlayGamepadHapticEffect(
586 webview_id,
587 gamepad_index,
588 gamepad_haptic_effect_type,
589 callback,
590 ) => {
591 if let Some(webview) = self.get_webview_handle(webview_id) {
592 let request = GamepadHapticEffectRequest::new(
593 gamepad_index,
594 GamepadHapticEffectRequestType::Play(gamepad_haptic_effect_type),
595 Box::new(move |success| {
596 callback
597 .send(success)
598 .expect("Could not send message via callback")
599 }),
600 );
601 webview
602 .gamepad_provider()
603 .handle_haptic_effect_request(request);
604 }
605 },
606 #[cfg(feature = "gamepad")]
607 EmbedderMsg::StopGamepadHapticEffect(webview_id, gamepad_index, callback) => {
608 if let Some(webview) = self.get_webview_handle(webview_id) {
609 let request = GamepadHapticEffectRequest::new(
610 gamepad_index,
611 GamepadHapticEffectRequestType::Stop,
612 Box::new(move |success| {
613 callback
614 .send(success)
615 .expect("Could not send message via callback")
616 }),
617 );
618 webview
619 .gamepad_provider()
620 .handle_haptic_effect_request(request);
621 }
622 },
623 EmbedderMsg::ShowNotification(webview_id, notification) => {
624 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
625 Some(webview) => webview.delegate().show_notification(webview, notification),
626 None => self.delegate.borrow().show_notification(notification),
627 }
628 },
629 EmbedderMsg::ShowConsoleApiMessage(webview_id, level, message) => {
630 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
631 Some(webview) => webview
632 .delegate()
633 .show_console_message(webview, level, message),
634 None => self.delegate.borrow().show_console_message(level, message),
635 }
636 },
637 EmbedderMsg::ShowEmbedderControl(control_id, position, embedder_control_request) => {
638 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
639 webview.show_embedder_control(control_id, position, embedder_control_request);
640 }
641 },
642 EmbedderMsg::HideEmbedderControl(control_id) => {
643 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
644 webview
645 .delegate()
646 .hide_embedder_control(webview, control_id);
647 }
648 },
649 EmbedderMsg::GetWindowRect(webview_id, response_sender) => {
650 let window_rect = || {
651 let Some(webview) = self.get_webview_handle(webview_id) else {
652 return DeviceIndependentIntRect::default();
653 };
654 let hidpi_scale_factor = webview.hidpi_scale_factor();
655 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
656 return DeviceIndependentIntRect::default();
657 };
658
659 convert_rect_to_css_pixel(screen_geometry.window_rect, hidpi_scale_factor)
660 };
661
662 if let Err(error) = response_sender.send(window_rect()) {
663 warn!("Failed to respond to GetWindowRect: {error}");
664 }
665 },
666 EmbedderMsg::GetScreenMetrics(webview_id, response_sender) => {
667 let screen_metrics = || {
668 let Some(webview) = self.get_webview_handle(webview_id) else {
669 return ScreenMetrics::default();
670 };
671 let hidpi_scale_factor = webview.hidpi_scale_factor();
672 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
673 return ScreenMetrics::default();
674 };
675
676 ScreenMetrics {
677 screen_size: convert_size_to_css_pixel(
678 screen_geometry.size,
679 hidpi_scale_factor,
680 ),
681 available_size: convert_size_to_css_pixel(
682 screen_geometry.available_size,
683 hidpi_scale_factor,
684 ),
685 }
686 };
687 if let Err(error) = response_sender.send(screen_metrics()) {
688 warn!("Failed to respond to GetScreenMetrics: {error}");
689 }
690 },
691 EmbedderMsg::AccessibilityTreeUpdate(webview_id, tree_update) => {
692 if let Some(webview) = self.get_webview_handle(webview_id) {
693 webview
694 .delegate()
695 .notify_accessibility_tree_update(webview, tree_update);
696 }
697 },
698 }
699 }
700}
701
702impl Drop for ServoInner {
703 fn drop(&mut self) {
704 self.constellation_proxy
705 .send(EmbedderToConstellationMessage::Exit);
706 self.shutdown_state.set(ShutdownState::ShuttingDown);
707 while self.spin_event_loop() {
708 std::thread::sleep(Duration::from_micros(500));
709 }
710 }
711}
712
713#[derive(Clone)]
722pub struct Servo(Rc<ServoInner>);
723
724impl Servo {
725 #[servo_tracing::instrument(skip(builder))]
726 fn new(builder: ServoBuilder) -> Self {
727 let opts = builder.opts.map(|opts| *opts);
729 opts::initialize_options(opts.unwrap_or_default());
730 let opts = opts::get();
731
732 let preferences = builder.preferences.map(|opts| *opts);
735 servo_config::prefs::set(preferences.unwrap_or_default());
736
737 use std::sync::atomic::Ordering;
738
739 style::context::DEFAULT_DISABLE_STYLE_SHARING_CACHE.store(
740 !pref!(layout_style_sharing_cache_enabled),
741 Ordering::Relaxed,
742 );
743 style::context::DEFAULT_DUMP_STYLE_STATISTICS
744 .store(opts.debug.style_statistics, Ordering::Relaxed);
745
746 if !opts.multiprocess {
747 media_platform::init();
748 }
749
750 PipelineNamespace::install(PipelineNamespaceId(0));
752
753 let event_loop_waker = builder.event_loop_waker;
758 let (paint_proxy, paint_receiver) = create_paint_channel(event_loop_waker.clone());
759 let (constellation_proxy, embedder_to_constellation_receiver) = ConstellationProxy::new();
760 let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone());
761 let (net_embedder_proxy, net_embedder_receiver) =
762 create_generic_embedder_channel::<NetToEmbedderMsg>(event_loop_waker.clone());
763 let time_profiler_chan = profile_time::Profiler::create(
764 &opts.time_profiling,
765 opts.time_profiler_trace_path.clone(),
766 );
767 let mem_profiler_chan = profile_mem::Profiler::create();
768
769 let devtools_sender = if pref!(devtools_server_enabled) {
770 Some(devtools::start_server(
771 embedder_proxy.clone(),
772 mem_profiler_chan.clone(),
773 ))
774 } else {
775 None
776 };
777
778 let js_engine_setup = if !opts.multiprocess {
781 Some(script::init())
782 } else {
783 None
784 };
785
786 let mut protocols = ProtocolRegistry::with_internal_protocols();
789 protocols.merge(builder.protocol_registry);
790
791 let shutdown_state = Rc::new(Cell::new(ShutdownState::NotShuttingDown));
794 let paint = Paint::new(InitialPaintState {
795 paint_proxy: paint_proxy.clone(),
796 receiver: paint_receiver,
797 embedder_to_constellation_sender: constellation_proxy.sender(),
798 time_profiler_chan: time_profiler_chan.clone(),
799 mem_profiler_chan: mem_profiler_chan.clone(),
800 shutdown_state: shutdown_state.clone(),
801 event_loop_waker,
802 #[cfg(feature = "webxr")]
803 webxr_registry: builder.webxr_registry,
804 });
805
806 let protocols = Arc::new(protocols);
807 let (public_resource_threads, private_resource_threads, async_runtime) =
808 new_resource_threads(
809 devtools_sender.clone(),
810 time_profiler_chan.clone(),
811 mem_profiler_chan.clone(),
812 net_embedder_proxy,
813 opts.config_dir.clone(),
814 opts.certificate_path.clone(),
815 opts.ignore_certificate_errors,
816 protocols.clone(),
817 );
818
819 let (private_storage_threads, public_storage_threads) =
820 new_storage_threads(mem_profiler_chan.clone(), opts.config_dir.clone());
821
822 create_constellation(
823 embedder_to_constellation_receiver,
824 &paint.borrow(),
825 embedder_proxy,
826 paint_proxy,
827 time_profiler_chan,
828 mem_profiler_chan,
829 devtools_sender,
830 protocols,
831 public_resource_threads.clone(),
832 private_resource_threads.clone(),
833 async_runtime,
834 public_storage_threads.clone(),
835 private_storage_threads.clone(),
836 );
837
838 if opts::get().multiprocess {
839 prefs::add_observer(Box::new(constellation_proxy.clone()));
840 }
841
842 Servo(Rc::new(ServoInner {
843 delegate: RefCell::new(Rc::new(DefaultServoDelegate)),
844 paint,
845 network_manager: Rc::new(RefCell::new(NetworkManager::new(
846 public_resource_threads.clone(),
847 private_resource_threads.clone(),
848 ))),
849 site_data_manager: Rc::new(RefCell::new(SiteDataManager::new(
850 public_resource_threads,
851 private_resource_threads,
852 public_storage_threads,
853 private_storage_threads,
854 ))),
855 javascript_evaluator: Rc::new(RefCell::new(JavaScriptEvaluator::new(
856 constellation_proxy.clone(),
857 ))),
858 constellation_proxy,
859 embedder_receiver,
860 net_embedder_receiver,
861 shutdown_state,
862 webviews: Default::default(),
863 servo_errors: ServoErrorChannel::default(),
864 _js_engine_setup: js_engine_setup,
865 }))
866 }
867
868 pub fn delegate(&self) -> Rc<dyn ServoDelegate> {
869 self.0.delegate.borrow().clone()
870 }
871
872 pub fn set_delegate(&self, delegate: Rc<dyn ServoDelegate>) {
873 *self.0.delegate.borrow_mut() = delegate;
874 }
875
876 pub fn initialize_gl_accelerated_media(display: NativeDisplay, api: GlApi, context: GlContext) {
879 WindowGLContext::initialize(display, api, context)
880 }
881
882 pub fn spin_event_loop(&self) {
888 self.0.spin_event_loop();
889 }
890
891 pub fn setup_logging(&self) {
892 let constellation_chan = self.0.constellation_proxy.sender();
893 let env = env_logger::Env::default();
894 let env_logger = EnvLoggerBuilder::from_env(env).build();
895 let con_logger = FromEmbedderLogger::new(constellation_chan);
896
897 let filter = max(env_logger.filter(), con_logger.filter());
898 let logger = BothLogger(env_logger, con_logger);
899
900 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
901 log::set_max_level(filter);
902 }
903
904 pub fn create_memory_report(&self, snd: GenericCallback<MemoryReportResult>) {
905 self.0
906 .constellation_proxy
907 .send(EmbedderToConstellationMessage::CreateMemoryReport(snd));
908 }
909
910 pub fn execute_webdriver_command(&self, command: WebDriverCommandMsg) {
911 self.0
912 .constellation_proxy
913 .send(EmbedderToConstellationMessage::WebDriverCommand(command));
914 }
915
916 pub fn set_preference(&self, name: &str, value: PrefValue) {
917 let mut preferences = prefs::get().clone();
918 preferences.set_value(name, value);
919 prefs::set(preferences);
920 }
921
922 pub fn network_manager<'a>(&'a self) -> Ref<'a, NetworkManager> {
923 self.0.network_manager.borrow()
924 }
925
926 pub fn site_data_manager<'a>(&'a self) -> Ref<'a, SiteDataManager> {
927 self.0.site_data_manager.borrow()
928 }
929
930 pub fn set_accessibility_active(&self, active: bool) {
931 self.0
932 .constellation_proxy
933 .send(EmbedderToConstellationMessage::SetAccessibilityActive(
934 active,
935 ));
936 }
937
938 pub(crate) fn paint<'a>(&'a self) -> Ref<'a, Paint> {
939 self.0.paint.borrow()
940 }
941
942 pub(crate) fn paint_mut<'a>(&'a self) -> RefMut<'a, Paint> {
943 self.0.paint.borrow_mut()
944 }
945
946 pub(crate) fn webviews_mut<'a>(
947 &'a self,
948 ) -> RefMut<'a, FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>> {
949 self.0.webviews.borrow_mut()
950 }
951
952 pub(crate) fn constellation_proxy(&self) -> &ConstellationProxy {
953 &self.0.constellation_proxy
954 }
955
956 pub(crate) fn javascript_evaluator_mut<'a>(&'a self) -> RefMut<'a, JavaScriptEvaluator> {
957 self.0.javascript_evaluator.borrow_mut()
958 }
959}
960
961fn create_embedder_channel(
962 event_loop_waker: Box<dyn EventLoopWaker>,
963) -> (EmbedderProxy, Receiver<EmbedderMsg>) {
964 let (sender, receiver) = unbounded();
965 (
966 EmbedderProxy {
967 sender,
968 event_loop_waker,
969 },
970 receiver,
971 )
972}
973
974fn create_generic_embedder_channel<T>(
975 event_loop_waker: Box<dyn EventLoopWaker>,
976) -> (GenericEmbedderProxy<T>, Receiver<T>) {
977 let (sender, receiver) = unbounded();
978 (
979 GenericEmbedderProxy {
980 sender,
981 event_loop_waker,
982 },
983 receiver,
984 )
985}
986
987fn create_paint_channel(
988 event_loop_waker: Box<dyn EventLoopWaker>,
989) -> (PaintProxy, RoutedReceiver<PaintMessage>) {
990 let (sender, receiver) = unbounded();
991 let sender_clone = sender.clone();
992 let event_loop_waker_clone = event_loop_waker.clone();
993 let result_callback = move |msg: Result<PaintMessage, ipc_channel::IpcError>| {
995 if let Err(err) = sender_clone.send(msg) {
996 warn!("Failed to send response ({:?}).", err);
997 }
998 event_loop_waker_clone.wake();
999 };
1000
1001 let generic_callback =
1002 GenericCallback::new(result_callback).expect("Failed to create callback");
1003 let cross_process_paint_api = CrossProcessPaintApi::new(generic_callback);
1004 let paint_proxy = PaintProxy {
1005 sender,
1006 cross_process_paint_api,
1007 event_loop_waker,
1008 };
1009
1010 (paint_proxy, receiver)
1011}
1012
1013#[expect(clippy::too_many_arguments)]
1014fn create_constellation(
1015 embedder_to_constellation_receiver: Receiver<EmbedderToConstellationMessage>,
1016 paint: &Paint,
1017 embedder_proxy: EmbedderProxy,
1018 paint_proxy: PaintProxy,
1019 time_profiler_chan: time::ProfilerChan,
1020 mem_profiler_chan: mem::ProfilerChan,
1021 devtools_sender: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
1022 protocols: Arc<ProtocolRegistry>,
1023 public_resource_threads: ResourceThreads,
1024 private_resource_threads: ResourceThreads,
1025 async_runtime: Box<dyn net_traits::AsyncRuntime>,
1026 public_storage_threads: StorageThreads,
1027 private_storage_threads: StorageThreads,
1028) {
1029 let opts = opts::get();
1031
1032 #[cfg(feature = "bluetooth")]
1033 let bluetooth_thread: GenericSender<BluetoothRequest> =
1034 BluetoothThreadFactory::new(embedder_proxy.clone());
1035
1036 let privileged_urls = protocols.privileged_urls();
1037
1038 let system_font_service = Arc::new(
1039 SystemFontService::spawn(
1040 paint_proxy.cross_process_paint_api.clone(),
1041 mem_profiler_chan.clone(),
1042 )
1043 .to_proxy(),
1044 );
1045
1046 let initial_state = InitialConstellationState {
1047 paint_proxy,
1048 embedder_proxy,
1049 devtools_sender,
1050 #[cfg(feature = "bluetooth")]
1051 bluetooth_thread,
1052 system_font_service,
1053 public_resource_threads,
1054 private_resource_threads,
1055 public_storage_threads,
1056 private_storage_threads,
1057 time_profiler_chan,
1058 mem_profiler_chan,
1059 #[cfg(feature = "webxr")]
1060 webxr_registry: Some(paint.webxr_main_thread_registry()),
1061 #[cfg(not(feature = "webxr"))]
1062 webxr_registry: None,
1063 webgl_threads: Some(paint.webgl_threads()),
1064 webrender_external_image_id_manager: paint.webrender_external_image_id_manager(),
1065 #[cfg(feature = "webgpu")]
1066 wgpu_image_map: paint.webgpu_image_map(),
1067 async_runtime,
1068 privileged_urls,
1069 };
1070
1071 let layout_factory = Arc::new(LayoutFactoryImpl());
1072
1073 Constellation::<script::ScriptThread, script::ServiceWorkerManager>::start(
1074 embedder_to_constellation_receiver,
1075 initial_state,
1076 layout_factory,
1077 opts.random_pipeline_closure_probability,
1078 opts.random_pipeline_closure_seed,
1079 opts.hard_fail,
1080 );
1081}
1082
1083struct BothLogger<Log1, Log2>(Log1, Log2);
1086
1087impl<Log1, Log2> Log for BothLogger<Log1, Log2>
1088where
1089 Log1: Log,
1090 Log2: Log,
1091{
1092 fn enabled(&self, metadata: &Metadata) -> bool {
1093 self.0.enabled(metadata) || self.1.enabled(metadata)
1094 }
1095
1096 fn log(&self, record: &Record) {
1097 self.0.log(record);
1098 self.1.log(record);
1099 }
1100
1101 fn flush(&self) {
1102 self.0.flush();
1103 self.1.flush();
1104 }
1105}
1106
1107fn set_logger(script_to_constellation_sender: ScriptToConstellationSender) {
1108 let con_logger = FromScriptLogger::new(script_to_constellation_sender);
1109 let env = env_logger::Env::default();
1110 let env_logger = EnvLoggerBuilder::from_env(env).build();
1111
1112 let filter = max(env_logger.filter(), con_logger.filter());
1113 let logger = BothLogger(env_logger, con_logger);
1114
1115 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
1116 log::set_max_level(filter);
1117}
1118
1119pub fn run_content_process(token: String) {
1121 let (unprivileged_content_sender, unprivileged_content_receiver) =
1122 ipc::channel::<UnprivilegedContent>().unwrap();
1123 let connection_bootstrap: IpcSender<IpcSender<UnprivilegedContent>> =
1124 IpcSender::connect(token).unwrap();
1125 connection_bootstrap
1126 .send(unprivileged_content_sender)
1127 .unwrap();
1128
1129 let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
1130 opts::initialize_options(unprivileged_content.opts());
1131 prefs::set(unprivileged_content.prefs().clone());
1132
1133 if opts::get().sandbox {
1135 create_sandbox();
1136 }
1137
1138 let _js_engine_setup = script::init();
1139
1140 match unprivileged_content {
1141 UnprivilegedContent::ScriptEventLoop(new_event_loop_info) => {
1142 media_platform::init();
1143
1144 let fetch_thread_join_handle = start_fetch_thread();
1146
1147 set_logger(
1148 new_event_loop_info
1149 .initial_script_state
1150 .script_to_constellation_sender
1151 .clone(),
1152 );
1153
1154 register_system_memory_reporter_for_event_loop(&new_event_loop_info);
1155
1156 let (background_hang_monitor_register, background_hang_monitor_join_handle) =
1157 HangMonitorRegister::init(
1158 new_event_loop_info.bhm_to_constellation_sender.clone(),
1159 new_event_loop_info.constellation_to_bhm_receiver,
1160 opts::get().background_hang_monitor,
1161 );
1162
1163 let layout_factory = Arc::new(LayoutFactoryImpl());
1164 let script_join_handle = script::ScriptThread::create(
1165 new_event_loop_info.initial_script_state,
1166 layout_factory,
1167 Arc::new(ImageCacheFactoryImpl::new(
1168 new_event_loop_info.broken_image_icon_data,
1169 )),
1170 background_hang_monitor_register,
1171 );
1172
1173 script_join_handle
1174 .join()
1175 .expect("Failed to join on the script thread.");
1176 background_hang_monitor_join_handle
1177 .join()
1178 .expect("Failed to join on the BHM background thread.");
1179
1180 StyleThreadPool::shutdown();
1181
1182 exit_fetch_thread();
1184 fetch_thread_join_handle
1185 .join()
1186 .expect("Failed to join on the fetch thread in the constellation");
1187 },
1188 UnprivilegedContent::ServiceWorker(content) => {
1189 content.start::<ServiceWorkerManager>();
1190 },
1191 }
1192}
1193
1194#[cfg(all(
1195 not(target_os = "windows"),
1196 not(target_os = "ios"),
1197 not(target_os = "android"),
1198 not(target_arch = "arm"),
1199 not(target_arch = "aarch64"),
1200 not(target_env = "ohos"),
1201))]
1202fn create_sandbox() {
1203 ChildSandbox::new(content_process_sandbox_profile())
1204 .activate()
1205 .expect("Failed to activate sandbox!");
1206}
1207
1208#[cfg(any(
1209 target_os = "windows",
1210 target_os = "ios",
1211 target_os = "android",
1212 target_arch = "arm",
1213 target_arch = "aarch64",
1214 target_env = "ohos",
1215))]
1216fn create_sandbox() {
1217 panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android.");
1218}
1219
1220struct DefaultEventLoopWaker;
1221
1222impl EventLoopWaker for DefaultEventLoopWaker {
1223 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
1224 Box::new(DefaultEventLoopWaker)
1225 }
1226}
1227
1228#[cfg(feature = "webxr")]
1229struct DefaultWebXrRegistry;
1230#[cfg(feature = "webxr")]
1231impl webxr::WebXrRegistry for DefaultWebXrRegistry {}
1232
1233pub struct ServoBuilder {
1234 opts: Option<Box<Opts>>,
1235 preferences: Option<Box<Preferences>>,
1236 event_loop_waker: Box<dyn EventLoopWaker>,
1237 protocol_registry: ProtocolRegistry,
1238 #[cfg(feature = "webxr")]
1239 webxr_registry: Box<dyn webxr::WebXrRegistry>,
1240}
1241
1242impl Default for ServoBuilder {
1243 fn default() -> Self {
1244 Self {
1245 opts: Default::default(),
1246 preferences: Default::default(),
1247 event_loop_waker: Box::new(DefaultEventLoopWaker),
1248 protocol_registry: Default::default(),
1249 #[cfg(feature = "webxr")]
1250 webxr_registry: Box::new(DefaultWebXrRegistry),
1251 }
1252 }
1253}
1254
1255impl ServoBuilder {
1256 pub fn build(self) -> Servo {
1257 Servo::new(self)
1258 }
1259
1260 pub fn opts(mut self, opts: Opts) -> Self {
1261 self.opts = Some(Box::new(opts));
1262 self
1263 }
1264
1265 pub fn preferences(mut self, preferences: Preferences) -> Self {
1266 self.preferences = Some(Box::new(preferences));
1267 self
1268 }
1269
1270 pub fn event_loop_waker(mut self, event_loop_waker: Box<dyn EventLoopWaker>) -> Self {
1271 self.event_loop_waker = event_loop_waker;
1272 self
1273 }
1274
1275 pub fn protocol_registry(mut self, protocol_registry: ProtocolRegistry) -> Self {
1276 self.protocol_registry = protocol_registry;
1277 self
1278 }
1279
1280 #[cfg(feature = "webxr")]
1281 pub fn webxr_registry(mut self, webxr_registry: Box<dyn webxr::WebXrRegistry>) -> Self {
1282 self.webxr_registry = webxr_registry;
1283 self
1284 }
1285}
1286
1287fn register_system_memory_reporter_for_event_loop(
1288 new_event_loop_info: &NewScriptEventLoopProcessInfo,
1289) {
1290 let callback = GenericCallback::new(|message| {
1294 if let Ok(request) = message {
1295 system_reporter::collect_reports(request);
1296 }
1297 })
1298 .expect("Could not create memory reporter callback");
1299 new_event_loop_info
1300 .initial_script_state
1301 .memory_profiler_sender
1302 .send(ProfilerMsg::RegisterReporter(
1303 format!("system-content-{}", std::process::id()),
1304 Reporter(callback),
1305 ));
1306}