Chromium Mojo(IPC)进程通信演示 c++(4)

122版本自带的mojom通信例子仅供学习参考:

codelabs\mojo_examples\01-multi-process

其余定义参考文章:

Chromium Mojo(IPC)进程通信演示 c++(2)-CSDN博客

01-mojo-browser.exe 与 01mojo-renderer.exe进程通信完整例子。

一、目录结构:

二、01-mojo-browser.exe 

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/run_loop.h"
#include "codelabs/mojo_examples/mojom/interface.mojom.h"
#include "codelabs/mojo_examples/process_bootstrapper.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"

mojo::ScopedMessagePipeHandle LaunchAndConnect() {
  // Under the hood, this is essentially always an OS pipe (domain socket pair,
  // Windows named pipe, Fuchsia channel, etc).
  mojo::PlatformChannel channel;

  mojo::OutgoingInvitation invitation;

  // Attach a message pipe to be extracted by the receiver. The other end of the
  // pipe is returned for us to use locally. We choose the arbitrary name "pipe"
  // here, which is the same name that the receiver will have to use when
  // plucking this pipe off of the invitation it receives to join our process
  // network.
  mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe("pipe");

  base::LaunchOptions options;
  // This is the relative path to the mock "renderer process" binary. We pass it
  // into `base::LaunchProcess` to run the binary in a new process.
  static const base::CommandLine::CharType* argv[] = {
      FILE_PATH_LITERAL("./01-mojo-renderer")};
  base::CommandLine command_line(1, argv);

  // Delegating to Mojo to "prepare" the command line will append the
  // `--mojo-platform-channel-handle=N` command line argument, so that the
  // renderer knows which file descriptor name to recover, in order to establish
  // the primordial connection with this process. We log the full command line
  // next, to show what mojo information the renderer will be initiated with.
  channel.PrepareToPassRemoteEndpoint(&options, &command_line);
  LOG(INFO) << "Browser: " << command_line.GetCommandLineString();
  base::Process child_process = base::LaunchProcess(command_line, options);
  channel.RemoteProcessLaunchAttempted();

  mojo::OutgoingInvitation::Send(std::move(invitation), child_process.Handle(),
                                 channel.TakeLocalEndpoint());
  return pipe;
}

void CreateProcessRemote(mojo::ScopedMessagePipeHandle pipe) {
  mojo::PendingRemote<codelabs::mojom::Process> pending_remote(std::move(pipe),
                                                               0u);
  mojo::Remote<codelabs::mojom::Process> remote(std::move(pending_remote));
  LOG(INFO) << "Browser invoking SayHello() on remote pointing to renderer";
  remote->SayHello();
}

int main(int argc, char** argv) {
  LOG(INFO) << "'Browser process' starting up";
  base::CommandLine::Init(argc, argv);
  ProcessBootstrapper bootstrapper;
  bootstrapper.InitMainThread(base::MessagePumpType::IO);
  bootstrapper.InitMojo(/*as_browser_process=*/true);

  mojo::ScopedMessagePipeHandle pipe = LaunchAndConnect();
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&CreateProcessRemote, std::move(pipe)));

  base::RunLoop run_loop;
  // Delay shutdown of the browser process for visual effects, as well as to
  // ensure the browser process doesn't die while the IPC message is still being
  // sent to the target process asynchronously, which would prevent its
  // delivery.
  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(
          [](base::OnceClosure quit_closure) {
            LOG(INFO) << "'Browser process' shutting down";
            std::move(quit_closure).Run();
          },
          run_loop.QuitClosure()),
      base::Seconds(2));
  run_loop.Run();
  return 0;
}

三、01-mojo-renderer.exe

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "codelabs/mojo_examples/mojom/interface.mojom.h"
#include "codelabs/mojo_examples/process_bootstrapper.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"

class ProcessImpl : public codelabs::mojom::Process {
 public:
  explicit ProcessImpl(
      mojo::PendingReceiver<codelabs::mojom::Process> pending_receiver) {
    receiver_.Bind(std::move(pending_receiver));
  }

 private:
  // codelabs::mojo::Process
  void GetAssociatedInterface(
      const std::string&,
      mojo::PendingAssociatedReceiver<codelabs::mojom::GenericInterface>)
      override {
    NOTREACHED();
  }
  void SayHello() override { LOG(INFO) << "Hello!"; }

  mojo::Receiver<codelabs::mojom::Process> receiver_{this};
};
ProcessImpl* g_process_impl = nullptr;

void BindProcessImpl(mojo::ScopedMessagePipeHandle pipe) {
  // Create a receiver
  mojo::PendingReceiver<codelabs::mojom::Process> pending_receiver(
      std::move(pipe));
  g_process_impl = new ProcessImpl(std::move(pending_receiver));
}

int main(int argc, char** argv) {
  base::CommandLine::Init(argc, argv);
  // Logging the entire command line shows all of the information that the
  // browser seeded the renderer with. Notably, this includes the mojo platform
  // channel handle that the renderer will use to bootstrap its primordial
  // connection with the browser process.
  LOG(INFO) << "Renderer: "
            << base::CommandLine::ForCurrentProcess()->GetCommandLineString();

  ProcessBootstrapper bootstrapper;
  bootstrapper.InitMainThread(base::MessagePumpType::IO);
  bootstrapper.InitMojo(/*as_browser_process=*/false);

  // Accept an invitation.
  //
  // `RecoverPassedEndpointFromCommandLine()` is what makes use of the mojo
  // platform channel handle that gets printed in the above `LOG()`; this is the
  // file descriptor of the first connection that this process shares with the
  // browser.
  mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept(
      mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
          *base::CommandLine::ForCurrentProcess()));
  // Extract one end of the first pipe by the name that the browser process
  // added this pipe to the invitation by.
  mojo::ScopedMessagePipeHandle pipe = invitation.ExtractMessagePipe("pipe");

  base::RunLoop run_loop;
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&BindProcessImpl, std::move(pipe)));
  run_loop.Run();
  return 0;
}

四、编译

 1、gn gen out/debug

 2、 ninja -C out/debug 01-mojo-browser

     生成01-mojo-browser.exe

3、ninja -C out/debug 01-mojo-renderer

      生成01-mojo-renderer.exe

<think>好的,我需要回答用户关于Chromium项目中IPC(进程间通信)的机制和实现的问题。首先,我需要回顾自己已有的知识,并参考用户提供的引用内容。用户提到两个引用:一个是关于ChromiumIPC消息处理宏,另一个是UNIX Domain Socket在IPC中的应用。 首先,ChromiumIPC机制主要用于不同进程之间的通信,比如浏览器进程和渲染进程。根据引用[^1],Chromium使用宏来定义和处理IPC消息。例如,IPC_MESSAGE_ROUTED0用于定义不带参数的路由消息,而IPC_MESSAGE_DECL则用于声明消息类型。这些宏帮助生成消息的序列化和反序列化代码,简化了开发流程。 接下来,进程间通信需要高效的数据传输方式。引用[^2]提到UNIX Domain Socket相比网络socket更高效,因为它不需要经过网络协议栈。不过,Chromium可能不直接使用UNIX Domain Socket,而是采用其他机制,比如命名管道(Named Pipes)或共享内存,特别是在跨平台支持上。需要确认Chromium在不同操作系统上的具体实现,比如Windows可能使用命名管道,而Linux使用socketpair或类似的机制。 另外,IPC消息的序列化和反序列化是关键步骤。Chromium使用Mojo作为现代IPC库,它提供了更灵活的消息传递方式,支持接口定义语言(IDL),允许生成强类型的消息处理代码。Mojo不仅处理消息的传输,还管理进程间的接口和代理,使得多进程架构更易维护。 安全性方面,IPC机制必须防止恶意消息或数据篡改。ChromiumIPC通道应该实施消息验证,确保只有拥有正确权限的进程可以发送和接收特定消息。沙箱机制也会限制渲染进程的能力,进一步保护系统安全。 还需要考虑消息的路由机制。引用[^1]中的路由消息可能涉及将消息发送到特定的渲染框架或工作线程。这需要进程间有明确的路由标识,比如Frame ID或Render Process ID,确保消息正确到达目标。 最后,性能优化方面,大块数据的传输可能使用共享内存来减少拷贝开销。例如,处理大型图像或视频时,通过共享内存传递数据指针,而不是复制数据本身,从而提高效率。 总结起来,回答需要涵盖Chromium IPC的基本架构、消息定义与处理、传输机制、序列化、安全性、路由以及性能优化等方面,并结合用户提供的引用内容,特别是宏的使用和UNIX Domain Socket的优势,尽管Chromium可能采用其他方法,但可以对比说明不同IPC机制的特点。</think>ChromiumIPC通信机制基于多进程架构设计,主要实现浏览器进程与渲染进程、插件进程等子进程间的安全高效通信。以下是核心实现要点: ### 一、消息通道架构 1. **通道类型**:采用命名管道(Windows)或UNIX Domain Socket(Linux/macOS)建立双向通信链路。UNIX Domain Socket相比网络socket减少协议栈开销,通过文件系统路径标识通信端点 2. **序列化机制**:使用Mojo IPC库进行结构化数据序列化,支持自动生成接口绑定代码。例如消息定义: ```cpp // 接口定义语言(IDL) interface Renderer { SubmitForm(FormData data) => (bool success); } ``` ### 二、消息路由机制 1. **路由标识符**:每个消息携带`routing_id`字段标识目标框架(frame),通过`IPC_MESSAGE_ROUTED`宏定义路由消息 2. **代理模式**:通过`ChannelProxy`实现线程间消息转发,主线程的IPC消息通过代理分发到IO线程 ### 三、安全控制 1. **权限校验**:渲染进程只能发送白名单内预定义的IPC消息类型 2. **沙箱过滤**:敏感操作(如文件访问)必须通过浏览器进程代理执行 3. **消息验证**:自动校验消息结构合法性,防止畸形数据攻击 ### 四、性能优化 1. **共享内存**:大块数据(如图像缓冲区)通过共享内存传递,减少拷贝开销 2. **批量处理**:多个IPC消息合并发送,降低上下文切换频率 3. **优先级队列**:输入事件等高优先级消息优先处理 ```cpp // 典型消息处理流程 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect) void RenderWidget::OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params) { // 处理界面更新 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值