[Chromium中文文档]跨进程通信 (IPC)

2024-06-08 18:18

本文主要是介绍[Chromium中文文档]跨进程通信 (IPC),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

跨进程通信 (IPC)

转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_Architecture/Inter-process_Communication.html

全书地址
Chromium中文文档 for https://www.chromium.org/developers/design-documents
持续更新ing,欢迎star
gitbook地址:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//
github地址: https://github.com/ahangchen/Chromium_doc_zh

概览

Chromium有一个多进程架构,这意味着我们有许多需要互相交流的进程。我们的主要跨进程交流元素是命名管道。在Linux和OS X上,我们使用socketpair()。每个渲染器进程可以分配到一个命名管道来跟浏览器进程交流。这些管道是用异步方式使用的,确保没有哪个端会等待另一个端。

想要得到如何编写安全的IPC端点的知识,请查看IPC安全要点.

浏览器中IPC

在浏览器中,与渲染器的交流是通过一个独立的I/O线程完成的。来自或者去往view的消息需要使用一个ChannelProxy代理到主线程。这种方案的优点是,资源请求(比如网页等),这种最经常且极其关注性能的消息,可以整个的在I/O线程中处理,不会阻塞用户界面。这些通过使用Channel::MessageFilter(由RenderProcessHost插入channel)来完成。这个过滤器运行在I/O线程里,拦截资源请求信息,将它们直接转发到资源分发主机。查看多进程资源加载获取更多关于资源加载的信息。

渲染器中的IPC

每个渲染器也有一个线程管理交流(在这个例子里,是主线程),而大多数渲染和大多数处理发生在另一个线程里(查看多进程架构的那个图表)。大多数消息通过主渲染线程从浏览器发送给WebKit线程,反之亦然。这个额外的线程是用于支持同步的渲染器到浏览器的消息(参考下面的“同步消息”)。

消息

消息的类型

我们有两种基本的消息类型:”路由“和”控制“。控制消息由创建管道的类处理,有时候这个类允许其他人通过一个MessageRouter对象接收消息,其他监听器可以通过这个对象注册和接收有着唯一管道id的消息。

例如,渲染时,控制消息没有消息指定目标view,会被RenderProcess(渲染器)或者RenderProcessHost(浏览器)处理。来自资源的请求或者修改剪贴板的请求是没有目标view的,所以是控制消息。一个路由消息的例子是,要求一个view绘制一个区域的消息。

路由消息曾经被用于从指定的RenderViewHost获取消息。然而,技术上,任何类可以通过使用RenderProcessHost::GetNextRoutingID接收路由消息,并用RenderProcessHost::AddRoute注册它自己这个消息。现在,RenderFrameHost和RenderViewHost有了他们自己的路由ID了。

消息是否是独立类型在于,消息是从浏览器发送到渲染器,还是从渲染器到浏览器。从浏览器到渲染器的被称为View消息,因为它们被发送给RenderViewHost。从渲染器发送到浏览器的消息叫做ViewHost消息,因为他们被发送给RenderViewHost。你会注意到render_messages_internal.h里定义的消息被分为两类。

插件也有独立的进程。像渲染消息那样,PluginProcess消息(从浏览器发送到插件进程)和PluginProcessHost消息(从插件进程发送到浏览器)。这些消息都定义在plugin_messages_internal.h里。自动化消息(用于控制浏览器做UI测试)通过相同的方式完成。

声明消息

特殊的宏用于声明消息。渲染器和浏览器间发送的消息都声明在render_messages_internal.h里。有两个部分,一个是发送到渲染器的View消息,一个是发送到浏览器的ViewHost消息。

如果要声明一个从渲染器发送到浏览器(一个ViewHost消息)的消息,并且指定一个view(路由)包含一个url和一个整数作为参数,这样写:

IPC_MESSAGE_ROUTED2(ViewHostMsg_MyMessage, GURL, int)

如果要声明一个从浏览器发往渲染器的控制消息(一个View消息),并且不指定目标view(控制),不包含参数,这样写:

IPC_MESSAGE_CONTROL0(ViewMsg_MyMessage)
包装数据

参数通过ParamTraits模板序列化或者反序列化到消息体中。这种模板的具体化在ipc_message_utils.h中提供给大多数常见的类型。如果你定义了你自己的类型,你也需要为它定义你自己的ParamTraits具体形式。

有时候,一条消息有太多的值了,没法合理得放到消息里。这种情况下,我们定义一个独立的结构来存放这些值。例如,对于FrameMsg_Navigate消息,在navigation_params.h中,定义了CommonNavigationParams结构。frame_messages.h用IPC_STRUCT_TRAITS类型的宏定义了这个结构的具体ParamTraits。

发送消息

你通过“channel(通道)”发送消息(往下看)。在浏览器里,RenderProcessHost包含了用于从浏览器UI线程发送消息到渲染器的channel。为了方便,RenderWidgetHost(RenderViewHost的基类)提供了一个Send函数。

消息由指针发送,并将在它们分发后由IPC层删除。因此,一旦你发现合适的Send函数,尽管带着一条新消息去调用它:

Send(new ViewMsg_StopFinding(routing_id_));

注意,你必须按顺序指定路由ID,让消息能够路由到接收端正确的View/ViewHost。RenderWidgetHost(RenderViewHost的基类)和RenderWidget(RenderViewHost的基类)都有GetRoutingID()成员函数给你使用。

处理消息

消息由对IPC::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) {...
}

你也可以使用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中的安全漏洞有着严重的后果(文件盗取,沙箱逃逸,远程代码执行),查看我们的IPC安全文档以获取如何避免常见陷阱的一些提示。

通道

IPC::Channel()(定义在ipc/ipc_channel.h里)定义了通过管道交流的方法。IPC::SyncChannel提供了额外的功能用于同步等待一些消息的响应(正如下面的“同步消息”描述的,渲染器进程使用了这个特性,但浏览器进程不会这样做)。

通道不是线程安全的,我们通常希望用通道在另一个线程里发送消息。例如,当UI线程希望发送消息时,它必须通过I/O线程。为此,我们使用IPC::ChannelProxy。它有着与正常通道对象类似的API,但它把消息代理到另一个线程去发送,而在收到这些消息时,把消息代理回原来的线程。这允许你的对象(通常是在UI线程中)在通道线程(通常是在I/O线程中)安装一个IPC::ChannelProxy::Listener,以此从代理的消息中过滤掉一些消息。我们使用这个特性去做资源请求以及其他可以直接在I/O线程处理的请求。RenderProcessHost安装一个RenderMessageFilter对象执行这种过滤。

同步消息

有些消息应该从渲染器的角度来同步。这大多数时候发生在,有一个支持返回值的WebKit调用,但我们必须在浏览器中执行这个调用。这种消息的例子是拼写检查以及在javaScript中获取cookie。同步浏览器到渲染器的IPC是不允许的,以此避免在一个潜在的片段渲染器中阻塞用户界面。

警告: 不要在UI线程处理任何同步消息!你必须在I/O线程中处理他们。否则,应用程序可能因为插件等待UI线程的同步绘制而陷入死锁,而渲染器等待浏览器同步消息时也会有一些阻塞。

声明同步消息

同步消息用IPC_SYNC_MESSAGE_*这样的宏来声明。这些宏有输入,也有返回值()(非同步消息没有返回参数的概念)。对于一个有着两个输入参数和一个返回参数的控制函数,你应该在宏的名字中插入“2_1”:

IPC_SYNC_MESSAGE_CONTROL2_1(SomeMessage,  // Message nameGURL, //input_param1int, //input_param2std::string); //result

类似的,你也可以让消息路由到view,这种情况下你需要把“CONTROL”换成“ROUTED”,得到IPC_SYNC_MESSAGE_*。你也可以没有输入或返回参数。没有返回参数常用于渲染器必须等待浏览器完成某些操作但不需要结果时。我们在某些打印和剪贴板操作使用这种特性。

分发同步消息

当WebKit线程分发出一个同步IPC请求时,请求对象(继承自IPC::SyncMessage)会在渲染器中通过IPC::SyncChannel对象分发给主线程。所有同步的消息也是通过它发送的。同步通道在接收到同步消息时,会阻塞调用线程,只有当收到回复时,才会解除阻塞。

在WebKit线程等待同步请求时,主线程仍然会从浏览器进程接收消息。这些消息会添加到WebKit线程里,等到WebKit线程被唤醒时处理它们。当同步消息回复被接收时,这个线程会解除阻塞。注意这意味着同步消息回复可以不按顺序处理。

同步消息和正常的消息用同样的方式,带着赋予构造器的输出参数发送出去,例如:

const GURL input_param("http://www.google.com/");
std::string result;
content::RenderThread::Get()->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";
}

转换消息类型为消息名

如果运行崩溃了,并且此时你有消息的类型,你可以把它转为消息名。这种消息类型是一个32位值,高16位是类,低16位是ID。类基于ipc/ipc_message_start.h中的枚举值,id基于定义消息的文件中的行号。这意味着你需要获取准确的Chromium版本以获取消息名。

一个554011中的例子是Chromium ad0950c1ac32ef02b0b0133ebac2a0fa4771cf20 版0x1c0098中。类0x1c,意味着行40,匹配ChildProcessMsgStart。ChildProcessMsgStart消息在content/common/child_process_messages.h中,而0x98行,即152行,对应的IPC是ChildProcessHostMsg_ChildHistogramData.

当你在处理content::RenderProcessHostImpl::OnBadMessageReceived导致的crash时,这项技术非常有用。

这篇关于[Chromium中文文档]跨进程通信 (IPC)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1042945

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

java 进程 返回值

实现 Callable 接口 与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 public class MyCallable implements Callable<Integer> {public Integer call() {return 123;}} public static void main(String[] args

C#关闭指定时间段的Excel进程的方法

private DateTime beforeTime;            //Excel启动之前时间          private DateTime afterTime;               //Excel启动之后时间          //举例          beforeTime = DateTime.Now;          Excel.Applicat