[ZZ]翻譯chromium開發文檔之-Inter-process Communication,進程間通信

Inter-process Communication

進程間通信


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


總覽

Chromium有一個多進程的架構,這意味着我們有許多進程間通信.我們主要使用命名管道來做進程間通信.每一個渲染進程都創建一個命名管道,用來和瀏覽器主進程通信.這些管理都是異步模式的,用來保證它們不會阻塞在對其它管道的等待上.


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 ChannelProxy. 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 a ChannelProxy::MessageFilter which is inserted into the channel by the RenderProcessHost. 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

在瀏覽器進程中,與渲染進程的通信是在一個單獨的IO線程中完成的[譯註:這裏的IO線程是用來做通信,而不是讀寫磁盤的].從視圖中發送或者是接收的消息需要使用一個ChannelProxy來代理.這種機制的好處就是,資源請求(如網頁),是最常見也是與性能息息相關的消息,可以完全在IO線程中處理而不影響用戶界面.通過使用ChannelProxy::messageFilter可以做到這一點.它被RenderProcessHost插入到一個通道中.這個filter在IO線程中運行,攔截資源請求消息,然後把消息發給ResourceDispather宿主.(參見Multi-process 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).


渲染進程中的IPC

每一個渲染進程同樣也有一個線程來管理通信(在主線程中),主要處理渲染和大部分在其它線程上做的處理(能見multi-process architecture文章中的圖).瀏覽器主進程通過渲染進程的主線程發送大部分消息到WebKit線程中,或者正好相反.這個額外的線程用來支持異步的renderer-to-browser消息(見下面的"異步消息").


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.


消息

消息類型

我們有兩種最根本的消息類型:"routed"和"control".Routed消息用於一個網頁,使用一個ID連接到響應這個網頁的視圖上.舉個例子,消息告訴視圖要繪製屏幕,或者是提示要顯示一個上下文菜單,這就是routed消息.


Control messages are not specific to a given view and will be handled by the RenderProcess (renderer) or the RenderProcessHost (browser). For example, requests for resources or to modify the clipboard are not view-specific so are control messages.


Control消息不指定到一個視圖上,被RenderProcess(渲染進程)或者是RenderProcessHost(瀏覽器主進程)處理.例如,請求資源或者是對剪切簿做操作就是視圖無關的,也就是Control消息.


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 View messages because they are being sent to the RenderView. Messages sent from the renderer to the browser are called ViewHost messages because they are being sent to the RenderViewHost. You will notice the messages defined in render_messages_internal.h are separated into these two categories.


與消息類型無關的是,消息如何從瀏覽器主進程發送到渲染進程,或者是從渲染進程發送到瀏覽器主進程.從瀏覽器主進程發送到渲染進程的消息被稱爲View消息,因爲它們被髮送到RenderView. 從渲染進程發送到瀏覽器主進程的消息被稱爲ViewHost消息,因爲它們被髮送到RenderViewHost。你會看到render_messages_internal.h中定義的消息被分成這兩種。


Plugins also have separate processes. Like the render messages, there are PluginProcess messages (sent from the browser to the plugin process) and PluginProcessHost messages (sent from the plugin process to the browser). These messages are all defined in plugin_messages_internal.h. The automation messages (for controlling the browser from the UI tests) are done in a similar manner.


插件同樣有單獨的進程。與渲染進程消息類似,同樣也有PluginProcess消息(從主瀏覽器進程發送到插件進程)和PluginProcessHost消息(從插件進程到瀏覽器主進程)。這些消息都定義在plugin_messages_internal.h頭文件中。自動消息(UI測試中用來控制瀏覽器)的收發也是一樣的。


Declaring messages

Special macros are used to declare messages. The messages sent between the renderer and the browser are all declared in render_messages_internal.h. 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:


聲明一個消息

聲明消息需要使用特別的宏。瀏覽器主進程和渲染進程間的消息都在plugin_messages_internal.h中聲明。它們分成兩部分,一種叫"View",發往渲染進程,另一種叫"ViewHost",發往瀏覽器主進程。


聲明一個從渲染進程發送到瀏覽器主進程的消息(或者是"ViewHost"消息),消息是與一個視圖相關的("routed"),包含了一個URL和一個整數,寫法如下:


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:


聲明一個從瀏覽器主進程發送到渲染進程的coltrol消息(或者是"View"消息),消息是與福星無關的,不包含參數,寫法如下:


IPC_MESSAGE_CONTROL0(ViewMsg_MyMessage)


Pickling values


Parameters are serialized and de-serialized to message bodies using the ParamTraits template. Specializations of this template are provided for most common types in ipc_message_utils.h. If you define your own types, you will also have to define your own ParamTraits specialization for it.


使用ParamTraits模型將參數序列化和反序列化到消息主體。提供類型來特化這個模板,常見的類型位於ipc_message_utils.h。如果你定義了自己的類型,你也需要定義自己的ParamTraits特化。


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 ViewMsg_Navigate message, the ViewMsg_Navigate_Params structure is defined in render_messages.h. That file also defines the ParamTraits specializations for the structures.


有時候,一個消息有過的參數要放入消息中。在這種情況下,我們定義了一個單獨的結構來保存這些值。舉個例子,對ViewMsg_Navigate消息來說,render_messages.h頭文件中定義了ViewMsg_Navigate_Params 結構。這個頭文件同樣定義了對這個結構的ParamTraits特化。


Sending messages

You send messages through "channels" (see below). In the browser, the RenderProcessHost contains the channel used to send messages from the UI thread of the browser to the renderer. The RenderWidgetHost (base class for RenderViewHost) provides a Send function that is used for convenience.


發送消息

通過"channels"發送消息(見下文)。在瀏覽器中,RenderProcessHost 包含用來發送來自瀏覽器UI線程的消息的通道(channel),這些消息發往渲染進程。RenderWidgetHost(RenderViewHost的基類)提供一個Send函數簡化操作。


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 function, just call it with a new message:


消息用指針的形式發送,在它們派發後被IPC層刪除。因此,當你找到了合適的的Send函數,只要用一個新消息調用它就可以了。


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.


要注意的是,你必須指定一個routing ID,用來使消息能夠被路由[譯註:或者關聯]到接收端正確的View/ViewHost。RenderWidgetHost(RenderViewHost的基類)和RenderWidget(RenderView的基類)都包含routing_id_ 成員,你可以使用它們來做routing ID。


Handling messages

Messages are handled by implementing the IPC::Channel::Listener interface, the most important function on which is OnMessageReceived. We have a variety of macros to simplify message handling in this function, which can best be illustrated by example:


處理消息

實現IPC::Channel::Listener接口來處理消息,最重要的函數是OnMessageReceived。我們有多種宏來簡化這個函數中的消息處理,舉個例子是最好不過的了:


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 IPC_DEFINE_MESSAGE_MAP to implement the function definition for you as well. In this case, do not specify a message variable name, it will declare a OnMessageReceived function on the given class and implement its guts.


你也可以使用IPC_DEFINE_MESSAGE_MAP來實現函數的定義。在這種情況下,不需要指定消息變量名,它會在指定的類上聲明一個OnMessageReceived 函數,實現函數內容。


Other macros:


其它宏:


IPC_MESSAGE_FORWARD: This is the same as IPC_MESSAGE_HANDLER 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)

IPC_MESSAGE_HANDLER_GENERIC: 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

IPC::Channel (defined in chrome/common/ipc_channel.h) defines the methods for communicating across pipes. IPC::SyncChannel 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).


通道

IPC::Channel (定義在chrome/common/ipc_channel.h)定義了通過管道通信的成員函數。IPC::SyncChannel 提供了附加的同步等待某些消息迴應的功能(渲染進程像在下面""Synchronous messages"描述的那樣使用它,但是瀏覽器進程卻沒有)。


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 IPC::ChanelProxy. 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 a IPC::ChannelProxy::Listener 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. RenderProcessHost installs a ResourceMessageFilter object that does this filtering.


通道不是線程安全的。我們經常想要使用通道發送消息到另一個線程。舉個例子,當UI線程想要發送一個消息,它必須通過I/O線程[注:IO線程是用來通信的,讀寫磁盤要用file線程]。我們使用 IPC::ChanelProxy來做這個工作,它有和普通channel對象相似的API,但是代理髮送到其它進程的消息,也代理當接收到消息時,將消息返回到原始發送的線程。它允許你的對象(在UI線程中)安裝一個IPC::ChannelProxy::Listener在channel線程(在IO線程上)上來過濾一些消息。我們使用它來做資源請求或者是其它可以直接在IO線程上處理的請求。RenderProcessHost安裝一個ResourceMessageFilter對象來做消息過濾。


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.


同步消息

從渲染進程的角度來看,有一些消息應該是同步的。這經常發生在,當WebKit調用希望返回一些東西時,但是這些東西我們需要在瀏覽器主進程中完成。例如這種消息是:拼寫檢查,爲JavaScript獲取cookies。同步的broser-to-render IPC不允許潛在的用戶界面阻塞。


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.


危險性:不要在UI線程中處理任何同步消息!你必須在IO線程中處理它們。否則應用程序可能會死鎖,因爲插件請求同步繪製,當渲染進程在等待瀏覽器主進程的同步消息時,而這些請求將被阻塞。


Declaring synchronous messages

Synchronous messages are declared using the IPC_SYNC_MESSAGE_* 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 2_1 to the macro name to get:


聲明同步消息

同步消息使用IPC_SYNC_MESSAGE_* 宏來聲明。這些宏有輸入和返回參數(異步消息沒有返回參數的概念)。對於一個clntrol函數,它帶有兩個輸入參數和一個返回參數,你需要添加2_1到宏名字上:


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 IPC_SYNC_MESSAGE_ROUTED2_1. You can also have 0 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.


同樣的,你可以使用關聯到視圖的消息,在這種情況下,你可以用"routed"替換"control"來得到IPC_SYNC_MESSAGE_ROUTED2_1。你可以擁有0個輸入參數或者是輸出參數。沒有返回參數用於渲染進程必須等待瀏覽器進程做完某些事情,但是不需要結果。我們使用它來做某些打印和剪切簿操作。


Issuing synchronous messages

When the WebKit thread issues a synchronous IPC request, the request object (derived from IPC::SyncMessage) is dispatched to the main thread on the renderer through a IPC::SyncChannel object (the same one is also used to send all asynchronous messages). The SyncChannel will block the calling thread when it receives a synchronous message, and will only unblock it when the reply is received.


發出一個同步消息

當WebKit線程發出一個同步IPC請求,這個請求對象(繼承自IPC::SyncMessage)通過IPC::SyncChannel 對象(用於發送所有的同步消息)發送到瀏覽進程的主線程中。SyncChannel將阻塞調用線程直到它接收到一個迴應。


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.


當WebKit線程在等待同步消息的迴應時,主線程仍然在接收來自瀏覽器主進程的消息。這些消息被加入到WebKit線程的隊列中,以便它喚醒時處理。當接收到同步消息的應答時,線程被解鎖。這意味着同步消息應答可以被無序處理。


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 IPC_MESSAGE_HANDLER, 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,等等的宏。宏用來發送消息。這個用於處理消息的函數與消息創建者有着同樣的特徵,函數只是簡單地把輸入寫到輸入參數中。在上面的消息裏你可能添加:


IPC_MESSAGE_HANDLER(MyMessage, OnMyMessage)

to the OnMessageReceived function, and write:

void RenderProcessHost::OnMyMessage(GURL input_param, std::string* result) {

*result = input_param.spec() + " is not available";

}

====================================================

感謝原作者的辛勤勞動!感謝!

官方原文:: http://www.chromium.org/developers/design-documents/inter-process-communication

本文ref :: http://hi.baidu.com/shihuap/blog/item/55f69ddfad74af144854034f.html

你可以自由傳播此文章但請註明譯者

[email protected]

發佈了27 篇原創文章 · 獲贊 25 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章