Inter-process Communication
OverviewChromium has a multi-process architecture which means that we have a lot of processes communicating with each other. Our main inter-process communication primitive is the named pipe. On Linux & OS X, we use a socketpair(). A named pipe is allocated for each renderer process for communication with the browser process. The pipes are used in asynchronous mode to ensure that neither end is blocked waiting for the other. IPC in the browserWithin the browser, communication with the renderers is done in a separate I/O thread. Messages to and from the views then have to be proxied over to the main thread using a IPC in the rendererEach renderer also has a thread that manages communication (in this case, the main thread), with the rendering and most processing happening on another thread (see the diagram in multi-process architecture). Most messages are sent from the browser to the WebKit thread through the main renderer thread and vice-versa. This extra thread is to support synchronous renderer-to-browser messages (see "Synchronous messages" below). MessagesTypes of messagesWe have two primary types of messages: "routed" and "control." Routed messages are specific to a page, and will be routed to the view representing that page using the identifier for that view. For example, messages telling the view to paint, or notifications to display a context menu are routed messages. Control messages are not specific to a given view and will be handled by the Independent of the message type is whether the message is sent from the browser to the renderer, or from the renderer to the browser. Messages sent from the browser to the renderer are called Plugins also have separate processes. Like the render messages, there are Declaring messagesSpecial macros are used to declare messages. The messages sent between the renderer and the browser are all declared in To declare a message from the renderer to the browser (a "ViewHost" message) that is specific to a view ("routed") that contains a URL and an integer as an argument, write: IPC_MESSAGE_ROUTED2(ViewHostMsg_MyMessage, GURL, int) To declare a control message from the browser to the renderer (a "View" message) that is not specific to a view ("control") that contains no parameters, write: IPC_MESSAGE_CONTROL0(ViewMsg_MyMessage) Pickling valuesParameters are serialized and de-serialized to message bodies using the Sometimes, a message has too many values to be reasonably put in a message. In this case, we define a separate structure to hold the values. For example, for the Sending messagesYou send messages through "channels" (see below). In the browser, the Messages are sent by pointer and will be deleted by the IPC layer after they are dispatched. Therefore, once you can find the appropriate Send(new ViewMsg_StopFinding(routing_id_));Notice that you must specify the routing ID in order for the message to be routed to the correct View/ViewHost on the receiving end. Both the RenderWidgetHost (base class for RenderViewHost ) and the RenderWidget (base class for RenderView ) have routing_id_ members that you can use.
Handling messagesMessages are handled by implementing the MyClass::OnMessageReceived(const IPC::Message& message) { You can also use Other macros:
IPC_MESSAGE_FORWARD(ViewHostMsg_MyMessage, some_object_pointer, SomeObject::OnMyMessage)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_MyMessage, printf("Hello, world, I got the message.")) Security considerationsYou must be very careful when unpacking messages in the browser. Since the renderer is sandboxed, one of the easiest ways to get out of the sandbox is to take advantage of insecure message unpacking. All parameters must be carefully validated and never trusted. Be particularly careful about signedness errors. Channels
Channels are not thread safe. We often want to send messages using a channel on another thread. For example, when the UI thread wants to send a message, it must go through the I/O thread. For this, we use a Synchronous messagesSome messages should be synchronous from the renderer's perspective. This happens mostly when there is a WebKit call to us that is supposed to return something, but that we must do in the browser. Examples of this type of messages are spell-checking and getting the cookies for JavaScript. Synchronous browser-to-renderer IPC is disallowed to prevent blocking the user-interface on a potentially flaky renderer. Danger: Do not handle any synchronous messages in the UI thread! You must handle them only in the I/O thread. Otherwise, the application might deadlock because plug-ins require synchronous painting from the UI thread, and these will be blocked when the renderer is waiting for synchronous messages from the browser. Declaring synchronous messagesSynchronous messages are declared using the IPC_SYNC_MESSAGE_CONTROL2_1(SomeMessage, // Message name Likewise, you can also have messages that are routed to the view in which case you would replace "control" with "routed" to get Issuing synchronous messagesWhen the WebKit thread issues a synchronous IPC request, the request object (derived from While the WebKit thread is waiting for the synchronous reply, the main thread is still receiving messages from the browser process. These messages will be added to the queue of the WebKit thread for processing when it wakes up. When the synchronous message reply is received, the thread will be un-blocked. Note that this means that the synchronous message reply can be processed out-of-order. Synchronous messages are sent the same way normal messages are, with output parameters being given to the constructor. For example: const GURL input_param("http://www.google.com/"); Handling synchronous messagesSynchronous messages and asynchronous messages use the same IPC_MESSAGE_HANDLER(MyMessage, OnMyMessage)to the OnMessageReceived function, and write:
void RenderProcessHost::OnMyMessage(GURL input_param, std::string* result) { |