电 话:189-8042-8893
邮 箱:zl_hsd@163.com
网 址:www.hsdconn.com
地 址:四川省成都市天府新区正兴街道顺圣路172号
Chromium具有多进程架构 ,这意味着我们有很多相互通信的进程。工控机厂商主要的进程间通信原语是命名管道。在Linux和OS X上,我们使用socketpair()。为每个渲染器进程分配一个命名管道,以与浏览器进程进行通信。管道以异步模式使用,以确保没有一端等待另一端。
有关如何编写安全工控机端点的建议,请参阅 工控机的安全提示。
浏览器中的工控机
在浏览器中,与渲染器的通信是在单独的I / O线程中完成的。然后,必须使用来将往返于视图的消息代入主线程ChannelProxy。这种方案的优势在于,资源请求(用于网页等)是最常见且对性能至关重要的消息,可以完全在I / O线程上处理,而不会阻塞用户界面。这些是通过使用来完成的,通过将ChannelProxy::MessageFilter插入到通道中RenderProcessHost。该筛选器在I / O线程中运行,拦截资源请求消息,然后将其直接转发到资源调度程序主机。有关资源加载的更多信息,请参见多进程资源加载。
渲染器中的工控机
每个渲染器还具有一个管理通信的线程(在本例中为主线程),渲染和大多数处理都在另一个线程上进行(请参见多进程体系结构中的图)。大多数消息是通过主渲染器线程从浏览器发送到WebKit线程的,反之亦然。此额外的线程用于支持渲染器到浏览器的同步消息(请参见下面的“同步消息”)。
留言内容
讯息类型
我们有两种主要的消息类型:“路由”和“控制”。控制消息由创建管道的类处理。有时,该类通过使MessageListener 对象可以供其他侦听器注册并接收使用其(每个管道)ID发送的“路由”消息,从而允许其他人接收消息 。
例如,在渲染时,控制消息并不特定于给定的视图,而是由RenderProcess(渲染器)或RenderProcessHost(浏览器)处理。资源请求或修改剪贴板不是特定于视图的,控制消息也不是特定于视图的。路由消息的一个示例是询问视图以绘制区域的消息。
过去,路由消息一直用于将消息获取到特定的RenderViewHost 。但是,从技术上讲,任何类都可以通过使用RenderProcessHost :: GetNextRoutingID 并向RenderProcessHost :: AddRoute注册自身 来接收路由消息 。当前,RenderViewHost 和 RenderFrameHost 实例都有其自己的路由ID。
与消息类型无关的是,消息是从浏览器发送到渲染器,还是从渲染器发送到浏览器。与从浏览器到渲染器发送文档的框架消息称为是因为他们被发送的消息来的。同样,从渲染器到浏览器发送的消息被称为是因为他们被发送的消息来的 RenderFrameHost 。您会注意到在frame_messages.h 中定义的消息 分为 两部分,一个用于 Frame ,一个用于 FrameHost messages 。 Frame RenderFrame FrameHost
插件也有单独的过程。与渲染消息一样,有PluginProcess消息(从浏览器发送到插件进程)和PluginProcessHost消息(从插件进程发送到浏览器)。这些消息均在中定义plugin_process_messages.h。自动化消息(用于通过UI测试控制浏览器)以类似的方式完成。
相同的组织适用于在浏览器和渲染器之间交换的其他消息组,就像View_messages.h中定义的RenderViewHost 和RenderView 之间交换的View 和 ViewHost标记的消息一样。
宣告讯息
特殊宏用于声明消息。 要声明从渲染器到浏览器的路由消息(例如,特定于frame的 FrameHost 消息),其中包含URL和一个整数作为参数,请编写:
工控机_MESSAGE_ROUTED2(FrameHostMsg_MyMessage,GURL,int)
要声明 不包含参数的从浏览器到渲染器的控制消息(例如,不是特定于框架 的 框架消息),请输入:
工控机_MESSAGE_CONTROL0(FrameMsg_MyMessage)
酸洗值
使用ParamTraits模板将参数序列化并反序列化为消息正文。针对的大多数常见类型提供了此模板的专业化功能工控机_message_utils.h。如果定义自己的类型,则还必须为其定义自己的ParamTraits专业化。
有时,一条消息具有太多的值,无法合理地放入一条消息中。在这种情况下,我们定义一个单独的结构来保存值。例如,对于FrameMsg_Navigate消息,CommonNavigationParams结构在中定义navigation_params.h。使用宏系列frame_messages.h 定义ParamTraits结构的专业化工控机_STRUCT_TRAITS。
传送讯息
您通过“渠道”发送消息(请参见下文)。在浏览器中,RenderProcessHost包含用于将消息从浏览器的UI线程发送到渲染器的通道。的RenderWidgetHost(对于基类RenderViewHost)提供了Send一个用于方便功能。
消息是通过指针发送的,并且在分派后将被工控机层删除。因此,一旦找到合适的Send函数,就用新消息调用它:
发送(新ViewMsg_StopFinding(routing_id_));
请注意,必须指定路由ID,才能将消息路由到接收端的正确View / ViewHost。无论是RenderWidgetHost(对于基类RenderViewHost)和RenderWidget(对于基类RenderView)有 GetRoutingID()成员就可以使用。
处理消息
通过实现工控机::Listener接口来处理消息,该接口最重要的功能是OnMessageReceived。我们有各种宏来简化此功能中的消息处理,以示例说明:
MyClass :: OnMessageReceived(const 工控机 :: Message&message){
工控机_BEGIN_MESSAGE_MAP(MyClass,message)
//将使用消息调用OnMyMessage。消息的参数将为您解压缩。
工控机_MESSAGE_HANDLER(ViewHostMsg_MyMessage,OnMyMessage)
...
工控机_MESSAGE_UNHANDLED_ERROR()//这将引发未处理消息的异常。
工控机_END_MESSAGE_MAP()
}
//将使用从ViewHostMsg_MyMessage消息中提取的参数来调用此函数。
MyClass :: OnMyMessage(const GURL&url,int something){
...
}
您也可以工控机_DEFINE_MESSAGE_MAP用来为您实现函数定义。在这种情况下,请不要指定消息变量名称,它会OnMessageReceived在给定的类上声明一个函数并实现其胆量。
其他宏:
工控机_MESSAGE_FORWARD:与相同,工控机_MESSAGE_HANDLER但是您可以指定自己的类将消息发送到,而不是将其发送到当前类。
工控机_MESSAGE_FORWARD(ViewHostMsg_MyMessage,some_object_pointer,SomeObject :: OnMyMessage)
工控机_MESSAGE_HANDLER_GENERIC:这允许您编写自己的代码,但是您必须自己从消息中解压缩参数:
工控机_MESSAGE_HANDLER_GENERIC(ViewHostMsg_MyMessage,printf(“你好,世界,我收到了消息。”)
安全注意事项
工控机中的安全漏洞可能会带来 令人讨厌的后果 (文件盗窃,沙箱转义,远程代码执行)。查看我们 的工控机安全性 文档,以获取有关如何避免常见陷阱的提示。
频道
工控机::Channel(在工控机中定义)定义了跨管道通信的方法。 提供了用于同步等待对某些消息的响应的其他功能(呈现器进程使用此功能,如下面“同步消息”部分中所述,但浏览器进程从不使用)。 /工控机_channel.h工控机::SyncChannel
通道不是线程安全的。我们通常希望使用另一个线程上的通道发送消息。例如,当UI线程想要发送消息时,它必须通过I / O线程。为此,我们使用工控机::ChannelProxy。它具有与常规通道对象类似的API,但是将消息代理到另一个线程以发送它们,并在接收消息时将消息代理回到原始线程。它允许您的对象(通常在UI线程上)工控机::ChannelProxy::Listener 在通道线程(通常是I / O线程)上安装a ,以过滤掉某些消息,以免被代理。我们将其用于资源请求和其他可以直接在I / O线程上处理的请求。RenderProcessHost安装RenderMessageFilter执行此过滤的对象。
同步消息
从渲染器的角度来看,某些消息应该是同步的。发生这种情况的大多数情况是,有一个WebKit调用要返回给我们,但是我们必须在浏览器中执行。这类消息的示例包括拼写检查和获取JavaScript的cookie。不允许浏览器到渲染器同步工控机,以防止阻塞可能不稳定的渲染器上的用户界面。
危险:请勿在UI线程中处理任何同步消息!您必须仅在I / O线程中处理它们。否则,应用程序可能会死锁,因为插件需要从UI线程进行同步绘制,并且在渲染器等待来自浏览器的同步消息时,这些插件将被阻止。
声明同步消息
使用工控机_SYNC_MESSAGE_* 宏声明同步消息。这些宏具有输入和返回参数(非同步消息缺少返回参数的概念)。对于具有两个输入参数并返回一个参数的控制函数,您可以将其附加2_1到宏名称上以获得:
工控机_SYNC_MESSAGE_CONTROL2_1(SomeMessage,//消息名称
GURL,// input_param1
int,// input_param2
std :: string); //结果
同样,您还可以将消息路由到视图,在这种情况下,可以将“ control”替换为“ routed”以获取工控机_SYNC_MESSAGE_ROUTED2_1。您还可以具有0 输入或返回参数。当渲染器必须等待浏览器执行某些操作但不需要任何结果时,将使用没有返回参数。我们将其用于某些打印和剪贴板操作。
发布同步消息
当WebKit线程发出同步工控机请求时,请求对象(从派生工控机::SyncMessage)通过一个工控机::SyncChannel对象分派到渲染器上的主线程(该对象也用于发送所有异步消息)。在SyncChannel当它接收同步消息,并且在接收到答复时,将仅解锁会阻塞调用线程。
WebKit线程正在等待同步答复时,主线程仍在从浏览器进程接收消息。这些消息将被添加到WebKit线程的队列中,以在唤醒时进行处理。收到同步消息答复后,该线程将被解除阻塞。请注意,这意味着同步消息回复可能会乱序处理。
同步消息的发送方式与普通消息相同,并向构造函数提供了输出参数。例如:
const GURL input_param(“ http://www.google.com/”);
std :: string结果;
content :: RenderThread :: Get()-> Send(new MyMessage(input_param,&result));
printf(“结果为%s n”,result.c_str());
处理同步消息
同步消息和异步消息使用相同的工控机_MESSAGE_HANDLER等宏来调度消息。消息的处理函数将具有与消息构造函数相同的签名,并且该函数会将输出简单地写入输出参数。对于以上消息,您将添加
工控机_MESSAGE_HANDLER(MyMessage,OnMyMessage)
到OnMessageReceived函数,并编写:
void RenderProcessHost :: OnMyMessage(GURL input_param,std :: string * result){
*结果= input_param.spec()+“不可用”;
}
将消息类型转换为消息名称
如果发生崩溃并具有消息类型,则可以将其转换为消息名称。消息类型为32位值,高16位为类,低16位为id。该类基于工控机 / 工控机_message_start.h中的枚举 ,id基于定义消息的文件中的行号。这意味着您需要获取Chromium的确切版本,才能准确获取消息名称。
在这个例子 554011 是 0x1c0098在铬修订 ad0950c1ac32ef02b0b0133ebac2a0fa4771cf20。那是第40行的0x1c类 ,与ChildProcessMsgStart匹配 。 ChildProcessMsgStart消息位于content / common / child_process_messages.h中,而工控机将位于0x98行或152行 ,即 ChildProcessHostMsg_ChildHistogramData。
如果要处理由content :: RenderProcessHostImpl :: OnBadMessageReceived引起的崩溃,则此技术特别有用。