注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

Inter-process Communication  

2010-01-10 21:12:30|  分类: Chrome |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Overview

Chromium 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 asocketpair(). 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 browser

Within 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 de style="color: rgb(0, 96, 0); "<ChannelProxyde<. The advantage of this scheme is that resource requests (for web pages, etc.), which are the most common and performance critical messages, can be handled entirely on the I/O thread and not block the user interface. These are done through the use of ade style="color: rgb(0, 96, 0); "<ChannelProxy::MessageFilterde< which is inserted into the channel by the de style="color: rgb(0, 96, 0); "<RenderProcessHostde<. This filter runs in the I/O thread, intercepts resource request messages, and forwards them directly to the resource dispatcher host. See Multi-process Resource Loading for more information on resource loading.

IPC in the renderer

Each 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).

Messages

Types of messages

We 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 de style="color: rgb(0, 96, 0); "<RenderProcessde< (renderer) or the de style="color: rgb(0, 96, 0); "<RenderProcessHostde< (browser). For example, requests for resources or to modify the clipboard are not view-specific so are control messages.

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 de style="color: rgb(0, 96, 0); "<Viewde< messages because they are being sent to the de style="color: rgb(0, 96, 0); "<RenderViewde<. Messages sent from the renderer to the browser are calledde style="color: rgb(0, 96, 0); "<ViewHostde< messages because they are being sent to the de style="color: rgb(0, 96, 0); "<RenderViewHostde<. You will notice the messages defined in de style="color: rgb(0, 96, 0); "<render_messages_internal.hde< are separated into these two categories.

Plugins also have separate processes. Like the render messages, there are de style="color: rgb(0, 96, 0); "<PluginProcessde< messages (sent from the browser to the plugin process) andde style="color: rgb(0, 96, 0); "<PluginProcessHostde< messages (sent from the plugin process to the browser). These messages are all defined in de style="color: rgb(0, 96, 0); "<plugin_messages_internal.hde<. The automation messages (for controlling the browser from the UI tests) are done in a similar manner.

Declaring messages

Special macros are used to declare messages. The messages sent between the renderer and the browser are all declared in de style="color: rgb(0, 96, 0); "<render_messages_internal.hde<. There are two sections, one for "View" messages sent to the renderer, and one for "ViewHost" messages sent to the browser.

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 values

Parameters are serialized and de-serialized to message bodies using the de style="color: rgb(0, 96, 0); "<ParamTraitsde< template. Specializations of this template are provided for most common types in de style="color: rgb(0, 96, 0); "<ipc_message_utils.hde<. If you define your own types, you will also have to define your own de style="color: rgb(0, 96, 0); "<ParamTraitsde< specialization for it.

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 de style="color: rgb(0, 96, 0); "<ViewMsg_Navigatede< message, the de style="color: rgb(0, 96, 0); "<ViewMsg_Navigate_Paramsde< structure is defined in de style="color: rgb(0, 96, 0); "<render_messages.hde<. That file also defines the de style="color: rgb(0, 96, 0); "<ParamTraitsde<specializations for the structures.

Sending messages

You send messages through "channels" (see below). In the browser, the de style="color: rgb(0, 96, 0); "<RenderProcessHostde< contains the channel used to send messages from the UI thread of the browser to the renderer. The de style="color: rgb(0, 96, 0); "<RenderWidgetHostde< (base class for de style="color: rgb(0, 96, 0); "<RenderViewHostde<) provides a de style="color: rgb(0, 96, 0); "<Sendde< function that is used for convenience.

Messages are sent by pointer and will be deleted by the IPC layer after they are dispatched. Therefore, once you can find the appropriate de style="color: rgb(0, 96, 0); "<Sendde< function, just call it with a new message:

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 de style="color: rgb(0, 96, 0); "<RenderWidgetHostde<(base class for de style="color: rgb(0, 96, 0); "<RenderViewHostde<) and the de style="color: rgb(0, 96, 0); "<RenderWidgetde< (base class for de style="color: rgb(0, 96, 0); "<RenderViewde<) have de style="color: rgb(0, 96, 0); "<routing_id_de< members that you can use.

Handling messages

Messages are handled by implementing the de style="color: rgb(0, 96, 0); "<IPC::Channel::Listenerde< interface, the most important function on which is de style="color: rgb(0, 96, 0); "<OnMessageReceivedde<. We have a variety of macros to simplify message handling in this function, which can best be illustrated by example:

MyClass::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(MyClass, message)
// Will call OnMyMessage with the message. The parameters of the message will be unpacked for you.
IPC_MESSAGE_HANDLER(ViewHostMsg_MyMessage, OnMyMessage)
...
IPC_MESSAGE_UNHANDLED_ERROR() // This will throw an exception for unhandled messages.
IPC_END_MESSAGE_MAP()
}

// This function will be called with the parameters extracted from the ViewHostMsg_MyMessage message.
MyClass::OnMyMessage(const GURL& url, int something) {
...
}

You can also use de style="color: rgb(0, 96, 0); "<IPC_DEFINE_MESSAGE_MAPde< to implement the function definition for you as well. In this case, do not specify a message variable name, it will declare a de style="color: rgb(0, 96, 0); "<OnMessageReceivedde< function on the given class and implement its guts.

Other macros:

  • de style="color: rgb(0, 96, 0); "<IPC_MESSAGE_FORWARDde<: This is the same as de style="color: rgb(0, 96, 0); "<IPC_MESSAGE_HANDLERde< but you can specify your own class to send the message to, instead of sending it to the current class.
IPC_MESSAGE_FORWARD(ViewHostMsg_MyMessage, some_object_pointer, SomeObject::OnMyMessage)
  • de style="color: rgb(0, 96, 0); "<IPC_MESSAGE_HANDLER_GENERICde<: This allows you to write your own code, but you have to unpack the parameters from the message yourself:
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_MyMessage, printf("Hello, world, I got the message."))

Security considerations

You 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

de style="color: rgb(0, 96, 0); "<IPC::Channelde< (defined in chromede style="color: rgb(0, 96, 0); font-family: 'courier new', monospace; "</common/ipc_channel.hde<) defines the methods for communicating across pipes. de style="color: rgb(0, 96, 0); "<IPC::SyncChannelde< provides additional capabilities for synchronously waiting for responses to some messages (the renderer processes use this as described below in the "Synchronous messages" section, but the browser process never does).

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 de style="color: rgb(0, 96, 0); "<IPC::ChanelProxyde<. It has a similar API as the regular channel object, but proxies messages to another thread for sending them, and proxies messages back to the original thread when receiving them. It allows your object (typically on the UI thread) to install ade style="color: rgb(0, 96, 0); "<IPC::ChannelProxy::Listenerde< on the channel thread (typically the I/O thread) to filter out some messages from getting proxied over. We use this for resource requests and other requests that can be handled directly on the I/O thread. de style="color: rgb(0, 96, 0); "<RenderProcessHostde< installs a de style="color: rgb(0, 96, 0); "<ResourceMessageFilterde< object that does this filtering.

Synchronous messages

Some 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 messages

Synchronous messages are declared using the de style="color: rgb(0, 96, 0); "<IPC_SYNC_MESSAGE_*de< macros. These macros have input and return parameters (non-synchronous messages lack the concept of return parameters). For a control function which takes two input parameters and returns one parameter, you would append de style="color: rgb(0, 96, 0); "<2_1de< to the macro name to get:

IPC_SYNC_MESSAGE_CONTROL2_1(SomeMessage,  // Message name
GURL, //input_param1
int, //input_param2
std::string); //result

Likewise, you can also have messages that are routed to the view in which case you would replace "control" with "routed" to get de style="color: rgb(0, 96, 0); "<IPC_SYNC_MESSAGE_ROUTED2_1de<. You can also have de style="color: rgb(0, 96, 0); "<0de< input or return parameters. Having no return parameters is used when the renderer must wait for the browser to do something, but needs no results. We use this for certain printing and clipboard operations.

Issuing synchronous messages

When the WebKit thread issues a synchronous IPC request, the request object (derived from de style="color: rgb(0, 96, 0); "<IPC::SyncMessagede<) is dispatched to the main thread on the renderer through a de style="color: rgb(0, 96, 0); "<IPC::SyncChannelde< object (the same one is also used to send all asynchronous messages). The de style="color: rgb(0, 96, 0); "<SyncChannelde< will block the calling thread when it receives a synchronous message, and will only unblock it when the reply is received.

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/");
std::string result;
RenderThread::current()->Send(new MyMessage(input_param, &result));
printf("The result is %s\n", result.c_str());

Handling synchronous messages

Synchronous messages and asynchronous messages use the same de style="color: rgb(0, 96, 0); "<IPC_MESSAGE_HANDLERde<, etc. macros for dispatching the message. The handler function for the message will have the same signature as the message constructor, and the function will simply write the output to the output parameter. For the above message you would add

IPC_MESSAGE_HANDLER(MyMessage, OnMyMessage)
to the de style="color: rgb(0, 96, 0); "<OnMessageReceivedde< function, and write:

void RenderProcessHost::OnMyMessage(GURL input_param, std::string* result) {
*result = input_param.spec() + " is not available";
}
  评论这张
 
阅读(226)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017