Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Servo into multiple processes, and introduce simple sandboxing #4735

Closed
wants to merge 7 commits into from
@@ -249,7 +249,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {

(Msg::Exit(chan), _) => {
debug!("shutting down the constellation");
let ConstellationChan(ref con_chan) = self.constellation_chan;
let con_chan = &mut self.constellation_chan;
con_chan.send(ConstellationMsg::Exit);
chan.send(());
self.shutdown_state = ShutdownState::ShuttingDown;
@@ -659,12 +659,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
root_layer.add_child(new_layer);
}

fn send_window_size(&self) {
fn send_window_size(&mut self) {
let dppx = self.page_zoom * self.device_pixels_per_screen_px();
let initial_viewport = self.window_size.as_f32() / dppx;
let visible_viewport = initial_viewport / self.viewport_zoom;

let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::ResizedWindow(WindowSizeData {
device_pixel_ratio: dppx,
initial_viewport: initial_viewport,
@@ -828,7 +828,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {

WindowEvent::Quit => {
debug!("shutting down the constellation for WindowEvent::Quit");
let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::Exit);
self.shutdown_state = ShutdownState::ShuttingDown;
}
@@ -866,7 +866,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {

let msg = ConstellationMsg::LoadUrl(root_pipeline_id,
LoadData::new(Url::parse(url_string.as_slice()).unwrap()));
let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(msg);
}

@@ -980,17 +980,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.composite_if_necessary();
}

fn on_navigation_window_event(&self, direction: WindowNavigateMsg) {
fn on_navigation_window_event(&mut self, direction: WindowNavigateMsg) {
let direction = match direction {
windowing::WindowNavigateMsg::Forward => NavigationDirection::Forward,
windowing::WindowNavigateMsg::Back => NavigationDirection::Back,
};
let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::Navigate(direction))
}

fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
let ConstellationChan(ref chan) = self.constellation_chan;
fn on_key_event(&mut self, key: Key, state: KeyState, modifiers: KeyModifiers) {
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::KeyEvent(key, state, modifiers))
}

@@ -1200,7 +1200,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
assert!(res.is_ok());

debug!("shutting down the constellation after generating an output file");
let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::Exit);
self.shutdown_state = ShutdownState::ShuttingDown;
}
@@ -1351,7 +1351,8 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
}

match self.composition_request {
CompositionRequest::NoCompositingNecessary | CompositionRequest::CompositeOnScrollTimeout(_) => {}
CompositionRequest::NoCompositingNecessary |
CompositionRequest::CompositeOnScrollTimeout(_) => {}
CompositionRequest::CompositeNow => self.composite(),
}

@@ -1405,12 +1406,12 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
self.viewport_zoom.get() as f32
}

fn get_title_for_main_frame(&self) {
fn get_title_for_main_frame(&mut self) {
let root_pipeline_id = match self.root_pipeline {
None => return,
Some(ref root_pipeline) => root_pipeline.id,
};
let ConstellationChan(ref chan) = self.constellation_chan;
let chan = &mut self.constellation_chan;
chan.send(ConstellationMsg::GetPipelineTitle(root_pipeline_id));
}
}
@@ -19,16 +19,19 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics
use layers::layers::LayerBufferSet;
use pipeline::CompositionPipeline;
use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy};
use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptToCompositorMsg, ScrollPolicy};
use servo_msg::constellation_msg::{ConstellationChan, LoadData, PipelineId};
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers};
use servo_net::server::{Server, SharedServerProxy};
use servo_util::cursor::Cursor;
use servo_util::geometry::PagePx;
use servo_util::memory::MemoryProfilerChan;
use servo_util::time::TimeProfilerChan;
use std::comm::{channel, Sender, Receiver};
use std::fmt::{Error, Formatter, Show};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::task;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
@@ -62,41 +65,6 @@ impl CompositorReceiver for Receiver<Msg> {
}
}

/// Implementation of the abstract `ScriptListener` interface.
impl ScriptListener for Box<CompositorProxy+'static+Send> {
fn set_ready_state(&mut self, pipeline_id: PipelineId, ready_state: ReadyState) {
let msg = Msg::ChangeReadyState(pipeline_id, ready_state);
self.send(msg);
}

fn scroll_fragment_point(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
point: Point2D<f32>) {
self.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point));
}

fn close(&mut self) {
let (chan, port) = channel();
self.send(Msg::Exit(chan));
port.recv();
}

fn dup(&mut self) -> Box<ScriptListener+'static> {
box self.clone_compositor_proxy() as Box<ScriptListener+'static>
}

fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) {
self.send(Msg::ChangePageTitle(pipeline_id, title))
}

fn send_key_event(&mut self, key: Key, state: KeyState, modifiers: KeyModifiers) {
if state == KeyState::Pressed {
self.send(Msg::KeyEvent(key, modifiers));
}
}
}

/// Information about each layer that the compositor keeps.
#[deriving(Copy)]
pub struct LayerProperties {
@@ -270,14 +238,55 @@ impl CompositorTask {
NativeCompositingGraphicsContext::new()
}

pub fn create_compositor_server_channel() -> (Server<ScriptToCompositorMsg,()>,
SharedServerProxy<ScriptToCompositorMsg,()>) {
let mut server = Server::new("CompositorTask");
let server_proxy = Arc::new(Mutex::new(server.create_new_client()));
(server, server_proxy)
}

pub fn create<Window>(window: Option<Rc<Window>>,
sender: Box<CompositorProxy+Send>,
receiver: Box<CompositorReceiver>,
mut server: Server<ScriptToCompositorMsg,()>,
constellation_chan: ConstellationChan,
time_profiler_chan: TimeProfilerChan,
memory_profiler_chan: MemoryProfilerChan)
-> Box<CompositorEventListener + 'static>
where Window: WindowMethods + 'static {
// Create a proxy server to forward messages received via IPC to the compositor.
let mut compositor_proxy_for_forwarder = sender.clone_compositor_proxy();
task::spawn(proc() {
while let Some(msgs) = server.recv() {
for (_, msg) in msgs.into_iter() {
match msg {
ScriptToCompositorMsg::SetReadyState(pipeline_id, ready_state) => {
compositor_proxy_for_forwarder.send(Msg::ChangeReadyState(
pipeline_id,
ready_state))
}
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id,
layer_id,
point) => {
compositor_proxy_for_forwarder.send(Msg::ScrollFragmentPoint(
pipeline_id,
layer_id,
point))
}
ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
compositor_proxy_for_forwarder.send(Msg::ChangePageTitle(pipeline_id,
title))
}
ScriptToCompositorMsg::SendKeyEvent(key, state, modifiers) => {
if state == KeyState::Pressed {
compositor_proxy_for_forwarder.send(Msg::KeyEvent(key, modifiers))
}
}
}
}
}
});

match window {
Some(window) => {
box compositor::IOCompositor::create(window,
@@ -305,6 +314,6 @@ pub trait CompositorEventListener {
fn shutdown(&mut self);
fn pinch_zoom_level(&self) -> f32;
/// Requests that the compositor send the title for the main frame as soon as possible.
fn get_title_for_main_frame(&self);
fn get_title_for_main_frame(&mut self);
}

@@ -16,7 +16,7 @@ use layout_traits::LayoutTaskFactory;
use libc;
use script_traits::{CompositorEvent, ConstellationControlMsg};
use script_traits::{ScriptControlChan, ScriptTaskFactory};
use servo_msg::compositor_msg::LayerId;
use servo_msg::compositor_msg::{LayerId, ScriptToCompositorMsg};
use servo_msg::constellation_msg::{mod, ConstellationChan, Failure};
use servo_msg::constellation_msg::{IFrameSandboxState, NavigationDirection};
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers};
@@ -25,9 +25,9 @@ use servo_msg::constellation_msg::{PipelineExitType, PipelineId};
use servo_msg::constellation_msg::{SubpageId, WindowSizeData};
use servo_msg::constellation_msg::Msg as ConstellationMsg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
use servo_net::storage_task::{StorageTask, StorageTaskMsg};
use servo_net::resource_task::{mod, ResourceTask};
use servo_net::server::{ClientId, Server, SharedServerProxy};
use servo_net::storage_task::StorageTask;
use servo_util::cursor::Cursor;
use servo_util::geometry::{PagePx, ViewportPx};
use servo_util::opts;
@@ -39,20 +39,21 @@ use std::collections::{HashMap, HashSet};
use std::io;
use std::mem::replace;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use url::Url;

/// Maintains the pipelines and navigation context and grants permission to composite.
pub struct Constellation<LTF, STF> {
/// A channel through which messages can be sent to this object.
pub chan: ConstellationChan,

/// Receives messages.
pub request_port: Receiver<ConstellationMsg>,
/// The server that we receive messages on.
pub server: Server<ConstellationMsg,()>,

/// A channel (the implementation of which is port-specific) through which messages can be sent
/// to the compositor.
pub compositor_proxy: Box<CompositorProxy>,

/// An client that the script thread uses to communicate with the compositor.
pub script_to_compositor_client: SharedServerProxy<ScriptToCompositorMsg,()>,

/// A channel through which messages can be sent to the resource task.
pub resource_task: ResourceTask,

@@ -341,20 +342,22 @@ impl NavigationContext {

impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pub fn start(compositor_proxy: Box<CompositorProxy+Send>,
script_to_compositor_client: SharedServerProxy<ScriptToCompositorMsg,()>,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
font_cache_task: FontCacheTask,
time_profiler_chan: TimeProfilerChan,
devtools_chan: Option<DevtoolsControlChan>,
storage_task: StorageTask)
-> ConstellationChan {
let (constellation_port, constellation_chan) = ConstellationChan::new();
let constellation_chan_clone = constellation_chan.clone();
let mut server = Server::new("Constellation");
let constellation_chan = Arc::new(Mutex::new(server.create_new_client()));
let constellation_chan = ConstellationChan::from_server_proxy(constellation_chan);
spawn_named("Constellation".to_owned(), proc() {
let mut constellation: Constellation<LTF, STF> = Constellation {
chan: constellation_chan_clone,
request_port: constellation_port,
server: server,
compositor_proxy: compositor_proxy,
script_to_compositor_client: script_to_compositor_client,
devtools_chan: devtools_chan,
resource_task: resource_task,
image_cache_task: image_cache_task,
@@ -379,10 +382,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
}

fn run(&mut self) {
loop {
let request = self.request_port.recv();
if !self.handle_request(request) {
break;
while let Some(msgs) = self.server.recv() {
for (client_id, msg) in msgs.into_iter() {
if !self.handle_request(client_id, msg) {
return
}
}
}
}
@@ -394,15 +398,18 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
script_pipeline: Option<Rc<Pipeline>>,
load_data: LoadData)
-> Rc<Pipeline> {
let constellation_chan = Arc::new(Mutex::new(self.server.create_new_client()));
let constellation_chan = ConstellationChan::from_server_proxy(constellation_chan);
let pipe = Pipeline::create::<LTF, STF>(id,
subpage_id,
self.chan.clone(),
constellation_chan,
self.compositor_proxy.clone_compositor_proxy(),
self.script_to_compositor_client.clone(),
self.devtools_chan.clone(),
self.image_cache_task.clone(),
self.font_cache_task.clone(),
self.font_cache_task.create_new_client(),
self.resource_task.clone(),
self.storage_task.clone(),
self.storage_task.create_new_client(),
self.time_profiler_chan.clone(),
self.window_size,
script_pipeline,
@@ -443,7 +450,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
}

/// Handles loading pages, navigation, and granting access to the compositor
fn handle_request(&mut self, request: ConstellationMsg) -> bool {
fn handle_request(&mut self, _: ClientId, request: ConstellationMsg) -> bool {
match request {
ConstellationMsg::Exit => {
debug!("constellation exiting");
@@ -464,7 +471,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("constellation got frame rect message");
self.handle_frame_rect_msg(pipeline_id, subpage_id, Rect::from_untyped(&rect));
}
ConstellationMsg::ScriptLoadedURLInIFrame(url, source_pipeline_id, new_subpage_id, old_subpage_id, sandbox) => {
ConstellationMsg::ScriptLoadedURLInIFrame(url,
source_pipeline_id,
new_subpage_id,
old_subpage_id,
sandbox) => {
debug!("constellation got iframe URL load message");
self.handle_script_loaded_url_in_iframe_msg(url,
source_pipeline_id,
@@ -521,8 +532,6 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
self.devtools_chan.as_ref().map(|chan| {
chan.send(devtools_traits::ServerExitMsg);
});
self.storage_task.send(StorageTaskMsg::Exit);
self.font_cache_task.exit();
self.compositor_proxy.send(CompositorMsg::ShutdownComplete);
}

@@ -1068,9 +1077,11 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
fn send_frame_tree_and_grant_paint_permission(&mut self, frame_tree: Rc<FrameTree>) {
debug!("Constellation sending SetFrameTree");
let (chan, port) = channel();
let constellation_chan = Arc::new(Mutex::new(self.server.create_new_client()));
let constellation_chan = ConstellationChan::from_server_proxy(constellation_chan);
self.compositor_proxy.send(CompositorMsg::SetFrameTree(frame_tree.to_sendable(),
chan,
self.chan.clone()));
constellation_chan));
if port.recv_opt().is_err() {
debug!("Compositor has discarded SetFrameTree");
return; // Our message has been discarded, probably shutting down.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.