Chromium Mojo C++ Bindings API(中文)

chromium 之 ipc (mojo) 消息机制 Mojo chromium 中的 ipc(进程间通信) 采用 mojo,使用双向的消息管道,每个终结点都有一个传入消息队列,并在一个终结点上写入消息,有效地将该消息排队到另一个 (对等 ) 终结点上。 通过 mojom 文件来描述并记录接口 Amojomfile describesinterfaces, which are strongly-typed collections ofmessages. Each interface message is roughly analogous to a... 阅读详情

概述

本文档为binding API的用法提供详细的指引,并附有示例代码段。详细的API文献请参考//mojo/public/cpp/bindings的头文件。
针对 Chromium开发者的简化指引,请看此链接。

起航

当Mojom IDL文件被bindings生成器处理时,c++代码产出了根据.mojom文件命名的一系列.h和.cc文件。假设我们在//services/db/public/mojom/db.mojom创建了以下Mojom文件:

module db.mojom;

interface Table {
   
   
  AddRow(int32 key, string data);
};

interface Database {
   
   
  CreateTable(Table& table);
};

并在==//services/db/public/mojom/BUILD.gn==有一个生成bindings的GN:

import("//mojo/public/tools/bindings/mojom.gni")

mojom("mojom") {
   
   
  sources = [
    "db.mojom",
  ]
}

确定需要本接口依赖的目标,比如这行代码:

   deps += [ '//services/db/public/mojom' ]

如果我们随后构建这个目标:

ninja -C out/r services/db/public/mojom

这将会生成几个源文件,一些与C++ bindings有关。其中的两个:

out/gen/services/db/public/mojom/db.mojom.cc
out/gen/services/db/public/mojom/db.mojom.h

你能将以上生成的头文件放入你的项目中,去运用它包含的定义:

#include "services/business/public/mojom/factory.mojom.h"

class TableImpl : public db::mojom::Table {
   
   
  // ...
};

本文档为C++开发覆盖了由Mojom IDL生成的各种不同的定义,并且他们如何有效的用于消息管道的通信。

接口

Mojom IDL接口被翻译成相应的C++(纯虚)类接口。在内部也有为消息的序列化和反序列化而生成的代码,不过详情是对bindings的消费者隐藏的。

基本用法

让我们来看一个新的//sample/logger.mojom,它定义了client用于log简单字符串消息的一个简单logging接口:

module sample.mojom;

interface Logger {
   
   
  Log(string message);
};

bindings生成器将会生产一个有如下定义的logger.mojom.h(隐藏了不重要的细节):

namespace sample {
   
   
namespace mojom {
   
   

class Logger {
   
   
  virtual ~Logger() {
   
   }

  virtual void Log(const std::string& message) = 0;
};

}  // namespace mojom
}  // namespace sample

Remote and PendingReceiver

在Mojo bindings库中,这些是有效的强类型消息管道端点。如果一个Remote< T>绑定了消息管道的一个端点,那么它能够通过解引用调用T的接口。这些调用立即序列化它们的参数(通过生成的代码),并将相关消息写入管道中。
PendingReceiver< T>一个持有Remote< T>管道另一端的类型容器–也就是接收端–它将被路由到一些绑定它的实现中去。PendingReceiver< T>除了持有管道的一端和一些有效的编译时类型信息外,不会做任何事情。
在这里插入图片描述
所以我们怎么创建一个强类型的消息管道呢?

创建接口管道

一个创建接口管道的办法就是通过手动地创建一个管道,然后将每一端用一个强类型对象封装:

#include "sample/logger.mojom.h"

mojo::MessagePipe pipe;
mojo::Remote<sample::mojom::Logger> logger(
    mojo::PendingRemote<sample::mojom::Logger>(std::move(pipe.handle0), 0));
mojo::PendingReceiver<sample::mojom::Logger> receiver(std::move(pipe.handle1));

这种做法很繁琐,C++ Bindings库提供了一个更方便的办法来完成这件事。remote.h定义了一个BindNewPipeAndPassReceive方法:

mojo::Remote<sample::mojom::Logger> logger;
auto receiver = logger.BindNewPipeAndPassReceiver();

第二个代码段和第一个是完全相同的。

注意:在第一个例子中你可能注意到mojo::PendingRemote< Logger>的使用。它和PendingReceiver< T>是一样的,都只持有一个管道handle,并且不在管道做实际的读写。这个类型和PendingReceiver< T>一样是安全的,当从一个序列移动到另一个序列时。一个绑定的Remote< T>被绑定于一个单独序列。
Remote< T>可能通过Unbind()方法来解除绑定,这个方法还返回一个新的PendingRemote< T>。反之,Remote< T>也可能绑定(并拥有所有权)PendingRemote< T>,这样就能在管道中进行接口调用。
==Remote< T>序列-绑定的特性,对于安全地分发消息响应和连接错误提醒是非常有必要的。

一旦PendingRemote< T>被绑定,我们可以立即开始调用Logger接口方法,它将会立刻将消息写入管道。这些消息将会在管道接收端排好序,直到接收端被绑定并且开始读消息。

logger->Log("Hello!");

这实际上写了一则Log消息给管道。
在这里插入图片描述
如上所述,PendingReceiver实际没有做任何事情,所以消息将会一直保留在管道中。我们需要一个办法来将消息从管道的另一端读出来并且分发它们。我们必须绑定pending receiver。

绑定一个PendingReceiver

在bindings库中有非常多不同的helper类用来绑定消息管道的接收端。它们中最原始的是mojo::Receiver< T>。mojo::Receiver< T>将T的实现和一个单一绑定消息管道端点连接起来(通过PendingRemote< T>),它将持续监控管道的可读状态。
任何时候只要被绑定的管道变成可读状态,Receiver将会调度一个task来读、反序列化(运用生成的代码)、将所有可用的消息分发给绑定的T的实现。以下是Logger接口的一个简单实现。需要注意的是,实现自身拥有mojo::Receiver。这是一个通用的模板,因为一个绑定的实现生命必须比绑定在它上面的mojo::Receiver长。

#include "base/logging.h"
#include "sample/logger.mojom.h"

class LoggerImpl : public sample::mojom::Logger {
   
   
 public:
  // NOTE: A common pattern for interface implementations which have one
  // instance per client is to take a PendingReceiver in the constructor.

  explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
      : receiver_(this, std::move(receiver)) {
   
   }
  Logger(const Logger&) = delete;
  Logger& operator=(const Logger&) = delete;
  ~Logger() override {
   
   }

  // sample::mojom::Logger:
  void Log(const std::string& message) override {
   
   
    LOG(ERROR) << "[Logger] " << message;
  }

 private:
  mojo::Receiver<sample::mojom::Logger> receiver_;
};

现在我们通过我们的LoggerImpl构造一个LoggerImpl,之前被排列好的Log消息将会被立即分发给LoggerImpl的序列:

LoggerImpl impl(std::move(receiver));

以下的示意图说明了事件的顺序,都是由上述代码行启动的:

  1. LoggerImpl构造器被调用,将PendingReceiver< Logger>传递给Receiver。
  2. Receiver拥有PendingReceiver< Logger>管道的端点,开始监控它是否可读。当管道是可读的,立即调度一个task来读管道中挂起的Log消息。
  3. Log消息被读取并且反序列化,造成Receiver触发它绑定的LoggerImpl的Logger::Log方法。
    在这里插入图片描述
    我们的implementation通过LOG(ERROR)最终log了client的"Hello!"消息。

注意:管道的消息被读取和分发,只在绑定它的对象(也就是以上的例子中的mojo::Receiver)活着的时候进行。

接收响应

一些Mojom 接口方法期望得到一个响应。假设我们修改Logger接口,最后一行log就可以这样获得:

module sample.mojom;

interface Logger {
   
   
  Log(string message);
  GetTail() => (string message);
};

生成的C++接口像这样:

namespace sample {
   
   
namespace mojom {
   
   

class Logger {
   
   
 public:
  virtual ~Logger() {
   
   }

  virtual void Log(const std::string& message) = 0;

  using GetTailCallback = base::OnceCallback<void(const std::string& message)>;

  virtual void GetTail(GetTailCallback callback) = 0;
}

}  // namespace mojom
}  // namespace sample

所有client和接口的implementation都使用GetTail方法相同的签名:implementation用callback参数来响应请求,clients传递callback参数来异步接收响应。传递给GetTail的GetTailCallback参数是有序的。它必须在GetTail被调用的相同序列中触发。client的callback也在GetTail被调用的相同序列中运行(logger被绑定的序列)。以下是更新之后的实现:

class LoggerImpl : public sample::mojom::Logger {
   
   
 public:
  // NOTE: A common pattern for interface implementations which have one
  // instance per client is to take a PendingReceiver in the constructor.

  explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
      : 
Chromium源码阅读:Mojo实战:从浏览器JS API 到blink实现 这个API是Web标准API,肯定在blink/render下面,简单一搜就找到了:> get(> get(// Cookie Store API的解释器文档链接// 定义一个名为CookieStore的接口,它在ServiceWorker和Window环境中被暴露,Exposed=(ServiceWorker,Window), // 暴露给ServiceWorker和WindowSecureContext // 并且仅在安全上下文中可用(如HTTPS) 阅读详情

相关推荐

Chromium源码阅读:深入理解Mojo框架的设计思想,并掌握其基本用法(1)

节。如果用计算机网络的术语进行类比,那么 Channel 类似于网络协议栈中的 IP 层,它提供了寻址和路由的能力;而 NodeChannel则相当于应用层的协议,例如 UDP,它在更高层次上处理数据的传输和相关逻辑。那么,可以预见,Mojo的应用层概念将围绕Node为核心展开。从上面代码中我们发现,NodeChannel中有个重要的嵌入类:Delegate。

hebhljdx的博客 2438

浏览器引擎漏洞利用实战:从V8/WebKit漏洞到沙箱逃逸的武器化指南

在软件安全领域,内存破坏漏洞和代码执行是核心攻防焦点。其原理通常源于程序对内存访问或代码逻辑的验证缺陷,例如类型混淆、释放后重用或越界读写。这类漏洞的技术价值在于,攻击者可能借此绕过现代操作系统的安全机制,实现远程代码执行。在Web安全场景中,浏览器作为复杂客户端应用,其JavaScript引擎(如V8、JavaScriptCore)和渲染引擎(如WebKit)因高度优化和庞大的代码库,成为此类漏洞的高发区。通过深入分析JIT编译器优化、堆内存管理等机制,安全研究者能够构建从信息泄露到稳定读写原语的利用链,

weixin_34161064的博客 387

Chromium 架构:从多进程模型到渲染管线,哪里最适合Hook?

本文深入剖析了Chromium浏览器的底层架构,为开发指纹浏览器提供了关键的技术路线。文章首先指出Chromium多进程模型的特殊性:主进程(Browser)拥有系统权限,而渲染进程(Renderer)运行在沙箱环境中。重点强调了必须在正确层级进行修改——渲染进程仅能接收主进程下发的伪造参数,任何直接调用系统API的行为都会触发沙箱保护机制。 文章详细解析了进程间通信(Mojo)机制,指出最佳Hook点是Browser端的IPC接口实现层,而非JS绑定层。在渲染引擎部分,揭示了Blink与V8的协作关系,建

数据知道的博客 680

指纹浏览器 API 拦截与伪装:Hook 原生 XHR 与 Fetch 请求实现自动 Token 刷新

本文深入探讨了指纹浏览器与风控系统在网络请求动态接管能力上的攻防对抗。研究发现,传统JS层Hook技术(如重写fetch/XHR)易被风控通过原生性检测、调用栈分析和时序测量识破。工业级解决方案需深入Chromium底层,通过V8 ObjectTemplate劫持实现原生级API伪装(保持[native code]特性),并进一步利用URLLoaderThrottle机制在网络栈层面实现无痕请求拦截。核心创新点包括:C++层静默Token刷新、请求重放时的流式Body保护,以及规避微秒级时序侧信

数据知道的博客 522

C++ 层拦截:修改 Blink 引擎与 V8 绑定的底层逻辑

本文深入探讨了从JS层Hook转向C++底层修改来实现指纹浏览器的关键技术。文章指出,基于JS的拦截(如Object.defineProperty或Proxy)容易被风控系统检测,而真正的工业级解决方案需要深入Chromium的Blink渲染引擎和V8绑定层进行改造。主要内容包括: 剖析Blink与V8的协作机制,解释JS调用(如navigator.platform)时底层的C++调用链 通过修改Web IDL文件彻底删除webdriver等敏感属性 实战演示在Blink的C++实现层伪装platform、

数据知道的博客 536

指纹浏览器突破沙箱限制:页面内 JS 调用宿主机本地程序的隐秘通道设计

真正的工业级指纹浏览器,必须构建一条对风控完全透明、绕过所有网络栈限制、且具备极速性能的隐秘通道。让页面内的 JS 能够像调用原生函数一样,无缝且安全地调用宿主机上的任意本地程序。 本文将拆解:如何突破 Chromium 沙箱的物理法则,基于 C++ 共享内存与 V8 引擎底层 API,构建一条从页面 JS 直达宿主机本地进程的无痕 IPC 桥梁。

数据知道的博客 452

南京工业大学高性能计算平台基础使用指南

高性能计算平台基础使用指南前言什么高性能计算南京工业大学高性能计算平台如何登录如何进行文件传输进行任务提交(本文以提交MATLAB任务为例)环境变量的配置(推荐)使用Environment Modules进行环境变量管理Modules 指令自定义MODULEFILE常见软件任务脚本 前言 第一次接触使用学校的高性能平台是在今年上半年进行毕业设计的时候,当时有大量的数据需要在Matab中进行模型运算,便向学校申请了账号,使用了HPC平台。计算速度确实比个人电脑快了太多太多。 近期,有很多初次想使用高性能计算

weixin_45710019的博客 6878

无人机飞控算法开发实战:从零到一构建企业级飞控系统

本文系统介绍了无人机飞控算法开发的完整流程,包括飞行动力学模型建立、传感器校准与数据融合、主流控制算法实现(PID、ADRC、EKF)以及企业级飞控系统架构设计。通过结合开源飞控框架(如PX4)和实际工程经验,提供了完整的代码实现示例,帮助学者从零开始掌握无人机飞控开发的核心技术。文中详细讲解了四旋翼无人机的动力学模型、传感器校准方法、EKF状态估计算法、PID和ADRC控制算法的实现,以及MAVLink通信协议的集成。最后,总结了完整的飞控系统开发流程和未来发展趋势。

全栈 3398

RK806S PMIC电源管理芯片调试

当点按PWRON按键时,rk806上电开始启动bootloader和uboot,在执行到此处时检测到是由于按键启动的,所以0x5d的值是0x80,0x74的值是0x80,在一般情况下,mode都默认是none的,所以mode值为11,因此就进入了我们的if判断,若是由于按键启动的,则直接调用rk8xx_shutdown函数关掉,进入这个函数会看到实际是通过i2c给0x72寄存器的BIT(0)写1,使其关机。当SoC在12V电源已经接入,且处于关机状态时,使用PWRON按键开机,0x74的值则为0x80。

Y1anoohh的博客 2539

apm软件仿真+QGC地面站 环境搭建

本教程使用场景:apm软件仿真运行于虚拟机 ubuntu环境。qgc地面站位于windows 系统。两个环境在同一台电脑上。 一.apm仿真环境搭建 1.安装vm虚拟机及ubuntu 18。 2.ubuntu下 下载Ardupilot 飞控源码 并配置环境。 下载源码: git clone https://github.com/ArduPilot/ardupilot cd ardupilot git submodule update --init --recursive 配置所需运行的环境:

qthello 6109

网络分析工具Wireshark系列专栏:01-专栏导读

随着人工智能技术的普及,越来越多的博主开始利用AI进行内容创作,导致优快云等平台上充斥着大量低质量的洗稿文章,严重影响了技术软文的质量和可信度。为了应对这一现象,提升技术内容的质量,瑞哥决定推出系列技术专栏,为大家带来系统、深入且高质量的技术学习资源。这些专栏将帮助读者从入门到精通,特别适合习惯通过文档学习的技术爱好者。作为首个专栏,我们将聚焦于Wireshark——一款广受欢迎的网络协议分析工具。根据优快云后台的反馈,许多读者表示Wireshark是他们欠缺的一项技能。因此,本专栏将通过精心设计的课程

网络技术联盟站 357

【Go语言实战】(2) Gin+Vue 电子商城

618来!!不用纠结去哪里剁手了!直接自己安排一个商场不香吗??

面向生活编程 4827

宇树G1二次开发资料汇总

宇树科技G1是一款29自由度的商业级人形机器人,配备NVIDIA Jetson Orin NX计算平台和完整SDK生态。本文系统介绍了G1的硬件架构、29个关节配置、传感器外设、双计算单元设计等关键信息,并详细解析了软件生态体系,包括C++/Python SDK、ROS2接口、仿真工具和AI框架。开发者可通过DDS通信实现高层运动控制或底层关节级精确控制,支持快速二次开发。文档提供了网络配置、接口调用示例等实用指南,帮助开发者高效利用该平台进行人形机器人应用开发。

m0_47999117的博客 1310

使用再生龙备份还原liunx系统(精确每一步)

再生龙镜像可自行到官网下载(ISO/ZIP格式均可),然后使用tuxboot烧录工具制作启动盘,另外准备一个U盘用来存储备份的镜像文件,即再生龙盘和存储盘是两个分开的。当然也可以用分区工具把同一个硬盘分区来使用,比较方便,先学会基本的吧,只是告诉有个捷径,省个U盘。

米可的博客! 8358

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: 第十五章 XMLHttpRequest
HowBlinkWorks
博客等级 码龄6年 0粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值