现在的位置: 首页 > 综合 > 正文

chromium源码分析之进程通讯片段

2018年06月08日 ⁄ 综合 ⁄ 共 4999字 ⁄ 字号 评论关闭

进程间通信

http://www.chromium.org.sixxs.org/developers/design-documents/inter-process-communication
目录
1。      概述
    1.1 在浏览器中的IPC 
    1.2 在渲染器中的IPC
2。     消息
     2.1 消息的类型
     2.2 声明消息
          2.2.1 产生值
     2.3 消息的发送
     2.4 消息的处理
     2.5 安全注意事项
3。   通道
4。同步消息
     4.1 同步消息的声明
     4.2 同步消息的发布
     4.3 同步信息处理
概述
Chromium 有一个多进程架构,这意味着我们可以用多个进程进行相互的沟通。我们的主要进程间通信的工具是命名管道。在Linux和OS X中,我们使用socketpair()。一个命名管道建立起来,用来连接浏览器进程和渲染器进程。该管道运行在异步模式下,以确保任何一端封锁并且等待着另一端。
IPC在浏览器
浏览器和渲染器沟通是在一个单独的I/O线程中完成的。主线程与Views消息传输都要通过ChannelProxy通道代理。这个方案的好处是,一些资源请求(网页等),是最常见的和重要的消息,它们可以由I/O线程完全处理的,并不会阻止用户界面。这些都通过使用ChannelProxy::MessageFilter,这个函数是的是RenderProcessHost插入到了通道。该过滤器运行在I / O线程,拦截资源请求消息,并直接将它们转发到资源调度主机。见 多进程加载的资源 以获得的加载信息资源。
在渲染器中的IPC
每个渲染器也有一个线程负责管理通讯(在这种情况下,是主线程),渲染和大多数处理发生在另一个线程(参见 多进程架构 中的图)。大多数消息通过主渲染线程从浏览器发送到WebKit线程,反之亦然。这一额外的线程支持同步的渲染器到浏览器的消息(见下面的“同步消息”)。
消息
消息类型
我们有两个主要消息类型:“路由”和“控制”。路由消息是是一个页面特有的,将被传送到该网页的使用这个视图的标识符。例如,告诉视图重绘、通知显示上下文菜单都是路由信息。
控制消息不是针对于一个视图特有的,将会由RenderProcess(渲染器)或RenderProcessHost(浏览器)处理。例如,对于资源的请求或修改剪贴板不是视图特有的,是控制消息。
这些消息类型的独立的信息是消息是否从浏览器发送到渲染器,或从渲染器到浏览器。从浏览器到渲染器的消息的被称为View messages,因为他们被发送到RenderView。从渲染器发送到浏览器的消息被称为ViewHost message,因为他们被发送到RenderViewHost。你会注意到在render_messages_internal.h定义的消息分成这两类。
插件也有独立的进程。就像渲染器的消息,有PluginProcess messages(从浏览器发送的插件进程的消息)和PluginProcessHost messages(从插件进程道浏览器的消息)。这些消息都定义在plugin_messages_internal.h。自动化信息控制,(从浏览器的用户界面测试)都使用了类似的方式。
声明消息
特定的宏用于声明的消息。浏览器与渲染器之间发送的消息都被定义在render_messages_internal.h中。有两个部分,发送到渲染器的"View"消息,发送到浏览器的"ViewHost" 消息。
声明一个从渲染器到浏览器的消息(“ ViewHost”消息)是具体到一个视图(“可路由消息”),其中包含一个网址和一个整数作为参数,可以这样写:
IPC_MESSAGE_ROUTED2(ViewHostMsg_MyMessage, GURL, int)
声明一个从浏览器到渲染器的控制的消息(View消息)不是具体到某一个视图View(“控制”),不包含任何参数,可以这样写:
IPC_MESSAGE_CONTROL0(ViewMsg_MyMessage)
产生值
参数进行序列化和去序列化,变成消息体,使用ParamTraits模板。此模板专门为ipc_message_utils.h提供最常见的类型。如果你定义自己的类型,你也必须为它定义您自己的ParamTraits专有模板。
有时候,一条消息有太多的值是需要放入一个消息中。在这种情况下,我们定义一个单独的结构来保存值。例如,对于ViewMsg_Navigate消息,ViewMsg_Navigate_Params结构定义在render_messages.h。该文件还定义了此结构专用ParamTraits模板。
发送消息
消息是通过“channels”进行发送的在浏览器中,RenderProcessHost包含用于发送从浏览器的UI线程到渲染器的通道。在RenderWidgetHost(RenderViewHost的基类)提供了一个发送函数,为了方便使用。
消息由指针发送,在IPC层在解析完成以后将被删除。因此,只要你找到合适的Send函数,就可以使用一个新的消息来调用它:
Send(new ViewMsg_StopFinding(routing_id_));
请注意,您必须指定路由编号(routing ID),以便将消息路由到正确View/ViewHost的接收端。无论是RenderWidgetHost(RenderViewHost的基类)还是RenderWidget(RenderView的基类)都有routing_id_成员,你都可以使用。
处理消息
消息是由实现IPC::Channel::Listener接口来处理的,其中最重要的函数是的OnMessageReceived。我们有宏来简化消息处理,就像下面的例子:
MyClass::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(MyClass, message)
//将调用OnMyMessage来处理消息。该消息中的参数将被解开。
IPC_MESSAGE_HANDLER(ViewHostMsg_MyMessage,OnMyMessage)
...
IPC_MESSAGE_UNHANDLED_ERROR()//这将对未处理的消息抛出一个异常。
IPC_END_MESSAGE_MAP()
}

//此函数将被调用的以提取的ViewHostMsg_MyMessage消息作为参数。
MyClass::OnMyMessage(const GURL& url, int something) {
...
}
您还可以使用IPC_DEFINE_MESSAGE_MAP来实现函数定义。在这种情况下,不要指定一个消息变量名,它将在给定的类声明一个OnMessageReceived函数并实现其内部。
其它的宏:
?         IPC_MESSAGE_FORWARD:这和IPC_MESSAGE_HANDLER一样,但你可以指定你自己的发送到的类,而不是发送到当前类。
IPC_MESSAGE_FORWARD(ViewHostMsg_MyMessage,some_object_pointer,SomeObject::OnMyMessage)
?         IPC_MESSAGE_HANDLER_GENERIC:这允许你写自己的代码,但是你必须自己打开消息中的参数信息:
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_MyMessage, printf("Hello, world, I got the message."))
安全性考虑
你必须 非常小心, 当拆包浏览器中的消息。由于渲染器是沙箱,走出沙箱的最简单的方法之一就是采取的不安全信息拆包。所有的参数必须仔细验证,从不信任。必须特别小心带符号的错误。
通道
IPC::Channel(定义在 chrome/common/ipc_channel.h) 定义整个管道的通讯方法。IPC::SyncChannel提供附加功能来同步等待一些消息的回应(渲染器进程使用这个,如下文所述的“同步信息”一节,但浏览器进程从来不使用)。
通道不是线程安全的。我们经常要发送消息,在另一个线程上建立一个通道。例如,当UI线程需要发送消息,它必须通过I / O线程。为此,我们使用的IPC::ChanelProxy。它有一个类似正常通道对象的API,但代理将消息发送到另一个线程来发送他们,和当收到回复时代理消息返回到原来的线程。它可以让你的对象(通常在UI线程)在通道线程上来安装的IPC::ChannelProxy::Listener(通常在I / O线程上)来过滤掉从代理获得的一些消息。我们利用这个来处理资源的请求,其他的请求可由I / O线程直接处理。RenderProcessHost安装一个ResourceMessageFilter对象,来进行过滤。
同步消息
有些消息从渲染器的角度应该是同步的。出现这种情况主要是当有WebKit的调用给我们,并且要求应该返回某些东西,但我们必须在浏览器中这样做。这一消息类型的例子有拼写检查以及为JavaScript获取cookie。同步浏览器对渲染器IPC是不允许的,以防止阻碍潜在的片状渲染器的用户界面。
危险: 不要在UI线程中处理任何同步消息!你必须只在I / O线程中处理他们。否则,应用程序可能会死锁,因为插件需要从UI线程同步的重绘消息,当渲染器等待从浏览器的同步的消息时这些将被封锁。
声明同步消息
同步消息声明使用IPC_SYNC_MESSAGE_ *宏。这些宏有输入和返回参数(非同步讯息缺乏返回参数的概念)。对于控制函数,它接受两个输入参数并返回一个参数,你会追加2_1到宏的名字来获取:
IPC_SYNC_MESSAGE_CONTROL2_1(SomeMessage,/ /消息的名称
GURL,// input_param1
int,// input_param2
std::string);//结果
同样,你也可以声明路由消息,在这种情况下,你只需要把“Control”换为“Routed”,如IPC_SYNC_MESSAGE_ROUTED2_1。您还可以声明0个输入或返回参数。没有返回参数在渲染器必须等待浏览器做一些事情时使用的,但不需要任何结果。我们使用这对于某些印刷和剪贴板操作。
发布同步消息
当WebKit线程发布一个同步的IPC的请求,该请求对象(从IPC::SyncMessage派生)被派出到渲染器的主线程通过IPC::SyncChannel对象(同样也是用来发送所有异步消息) 。当接收同步信息时,该SyncChannel会阻止调用线程,并且直到收到的答复时,才解除封锁。
当WebKit线程等待同步答复,主线程仍然接收来自浏览器进程的消息。这些消息将被添加到WebKit的线程队列来等待其醒来时处理。当同步消息答复被收到时,该线程将被取消封锁。请注意,这意味着同步消息答复可以不按顺序来处理。
同步消息发送和正常消息一样,只是输出参数被传递给构造函数。例如:
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());
同步消息处理
同步消息和异步消息使用同一IPC_MESSAGE_HANDLER宏等来调度消息。为消息处理函数将与信息构造函数具有相同的签名,函数简单地将输出写入到输出参数作。对于上述消息您会增加以下代码:
IPC_MESSAGE_HANDLER(MyMessage, OnMyMessage)
到OnMessageReceived函数,可以这样写:
void RenderProcessHost::OnMyMessage(GURL input_param, std::string* result) {
*result = input_param.spec() + " is not available";
}
 

抱歉!评论已关闭.