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

news/2024/11/5 20:41:46 标签: mojo, chrome, c++

   网上搜索关于mojo教程 多数都是理论 加上翻译谷歌mojo文档的,但是如何自定义两个进程使用mojo通信呢?看下面的完整例子介绍:(本人也是参考谷歌代码例子改编而成)

本文演示了client.exe和service.exe 通过mojo::IncomingInvitation模式进行通信使用例子。

废话不多说直接上代码:

一、目录结构如下图:

按照如图所示目录结构添加文件即可。 

二、定义sample.mojom接口

1、demo\logger\public\mojom\sample.mojom

module sample.mojom;

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

2、demo\logger\public\mojom\BUILD.gn

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

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

3、gn gen out/debug 自动生成代码如下:

out\Debug\gen\demo\logger\public\mojom\sample.mojom.h

out\Debug\gen\demo\logger\public\mojom\sample.mojom.cc 

其他更多参考out\Debug\gen\demo\logger\目录下

三、client.exe端代码: 

1、demo\client\client.cc  //client.exe main函数实现文件:

#include<iostream>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "demo/logger/public/mojom/sample.mojom.h"
#include "demo/client/logger_test.h"
#include "demo/process_bootstrapper_helper.h"
#include "mojo/core/embedder/configuration.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.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("./service")};
  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;
}

logger_test *g_logger_test = nullptr;

void CreateProcessRemote(mojo::ScopedMessagePipeHandle pipe,
                         const std::string& msg) {
  mojo::PendingRemote<sample::mojom::Logger> pending_remote(std::move(pipe),
                                                            0u);
  mojo::Remote<sample::mojom::Logger> remote(std::move(pending_remote));
  g_logger_test = new logger_test(std::move(remote));
  LOG(INFO) << "Browser invoking SayHello() on remote pointing to renderer";
  g_logger_test->sendLoggerMsg(msg);
  g_logger_test->sendLoggerExt();
}

int main(int argc, const char* argv[]) {
  base::AtExitManager at_exit_manager;
  base::CommandLine::Init(argc, argv);
  ProcessBootstrapperHelp bootstrapper;
  bootstrapper.InitMainThread(base::MessagePumpType::IO);
  bootstrapper.InitMojo(/*as_browser_process=*/true);

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

  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();
  delete g_logger_test;
  g_logger_test = nullptr;

  return 0;
}

2、demo\client\logger_test.cc

#include "demo/client/logger_test.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <iostream>
#include "base/functional/bind.h"

logger_test::logger_test(mojo::Remote<sample::mojom::Logger> rc)
    : logger_client_(std::move(rc)) {}

logger_test::~logger_test() {
  std::cout << "~logger_test()\n";
}

void logger_test::sendLoggerMsg(const std::string& msg) {
  logger_client_->Log(msg);
}

void logger_test::GetTailCallbackTest(const std::string& msg){
    LOG(ERROR) << "GetTail callback " << msg;

}
void logger_test::sendLoggerExt(){
    logger_client_->GetTail(base::BindOnce(&logger_test::GetTailCallbackTest,
                                           base::Unretained(this)));
}

3、demo\client\logger_test.h


#ifndef CHROME_BROWSER_LOGGER_TEST_H_
#define CHROME_BROWSER_LOGGER_TEST_H_
#include <string>
#include <vector>
#include "base/logging.h"
#include "demo/logger/public/mojom/sample.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

class logger_test {
 public:
  logger_test(mojo::Remote<sample::mojom::Logger> rc);
  ~logger_test();

  void sendLoggerMsg(const std::string& msg);
  void sendLoggerExt();

 private:
  void GetTailCallbackTest(const std::string& msg);
  /* data */
  mojo::Remote<sample::mojom::Logger> logger_client_;
};

#endif  // CHROME_BROWSER_LOGGER_TEST_H_

四、service.exe端代码: 

1、demo\service\service.cc  //service.exe main函数实现文件:

#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <iostream>

#include <initializer_list>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "demo/process_bootstrapper_helper.h"
#include "demo/service/LoggerImpl.h"
#include "mojo/core/embedder/configuration.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.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"

LoggerImpl* g_process_impl = nullptr;

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

int main(int argc, const char* argv[]) {
  base::AtExitManager at_exit_manager;
  base::CommandLine::Init(argc, argv);
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  std::wcout << command_line.GetCommandLineString().c_str()<<"\n";

  ProcessBootstrapperHelp 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();

  std::cout << "service\n";

  return 0;
}

LoggerImpl.h 和LoggerImpl.cc 是sample::mojom::Logger 实现类:

2、demo\service\LoggerImpl.h

#ifndef CHROME_BROWSER_LOGGERIMPL_H_
#define CHROME_BROWSER_LOGGERIMPL_H_

#include <string>
#include <vector>
#include "base/logging.h"
#include "demo/logger/public/mojom/sample.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.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> pending_receiver);
  ~LoggerImpl() override;

  // sample::mojom::Logger:
  void Log(const std::string& message) override;
  void GetTail(GetTailCallback callback) override;
  void OnError();

 private:
  mojo::Receiver<sample::mojom::Logger> receiver_;
  std::vector<std::string> lines_;
  LoggerImpl(const LoggerImpl&) = delete;
  LoggerImpl& operator=(const LoggerImpl&) = delete;
};

#endif  // CHROME_BROWSER_LOGGERIMPL_H_

3、demo\service\LoggerImpl.cc


#include "demo/service/LoggerImpl.h"
#include "base/functional/bind.h"

LoggerImpl::LoggerImpl(
    mojo::PendingReceiver<sample::mojom::Logger> pending_receiver)
    : receiver_(this, std::move(pending_receiver)) {
  // receiver_.Bind(std::move(pending_receiver));
  receiver_.set_disconnect_handler(
      base::BindOnce(&LoggerImpl::OnError, base::Unretained(this)));
}

LoggerImpl::~LoggerImpl() {}

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

void LoggerImpl::GetTail(GetTailCallback callback) {
  std::move(callback).Run(lines_.back());
}

void LoggerImpl::OnError() {
  LOG(ERROR) << "Client disconnected! Purging log lines.";
  lines_.clear();
}

五、初始化mojo和线程辅助类: 

demo\process_bootstrapper_helper.h

// 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.

#ifndef CODELABS_MOJO_EXAMPLES_PROCESS_BOOTSTRAPPER_HELPER_H_
#define CODELABS_MOJO_EXAMPLES_PROCESS_BOOTSTRAPPER_HELPER_H_

#include "base/message_loop/message_pump.h"
#include "base/run_loop.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/threading/thread.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.h"

class ProcessBootstrapperHelp {
 public:
  ProcessBootstrapperHelp();
  ~ProcessBootstrapperHelp();

  // This sets up the main thread with a message pump of `type`, and optionally
  // a dedicated IO thread if `type` is *not* `base::MessagePumpType::IO`.
  void InitMainThread(base::MessagePumpType type) {
    // Creates a sequence manager bound to the main thread with a message pump
    // of some specified type. The message pump determines exactly what the
    // event loop on its thread is capable of (i.e., what *kind* of messages it
    // can "pump"). For example, a `DEFAULT` message pump is capable of
    // processing simple events, like async timers and posted tasks. The `IO`
    // message pump type — which is used in every example in this codelab — is
    // capable of asynchronously processing IO over IPC primitives like file
    // descriptors, used by Mojo. A thread with *that* kind of message pump is
    // required for any process using Mojo for IPC.
    std::unique_ptr<base::MessagePump> pump = base::MessagePump::Create(type);
    sequence_manager =
        base::sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
            std::move(pump),
            base::sequence_manager::SequenceManager::Settings::Builder()
                .SetMessagePumpType(type)
                .Build());
    default_tq = std::make_unique<base::sequence_manager::TaskQueue::Handle>(
        sequence_manager->CreateTaskQueue(
            base::sequence_manager::TaskQueue::Spec(
                base::sequence_manager::QueueName::DEFAULT_TQ)));
    sequence_manager->SetDefaultTaskRunner((*default_tq)->task_runner());

    if (type == base::MessagePumpType::DEFAULT) {
      InitDedicatedIOThread();
    }
  }

  // Must be called after `InitMainThread()`.
  void InitMojo(bool as_browser_process) {
    CHECK(default_tq) << "Must call `InitMainThread()` before `InitMojo()`";
    // Basic Mojo initialization for a new process.
    mojo::core::Configuration config;
    // For mojo, one process must be the broker process which is responsible for
    // trusted cross-process introductions etc. Traditionally this is the
    // "browser" process.
    config.is_broker_process = as_browser_process;
    mojo::core::Init(config);

    // The effects of `ScopedIPCSupport` are mostly irrelevant for our simple
    // examples, but this class is used to determine how the IPC system shuts
    // down. The two shutdown options are "CLEAN" and "FAST", and each of these
    // may determine how other processes behave if *this* process has a message
    // pipe that is in the middle of proxying messages to another process where
    // the other end of the message pipe lives.
    //
    // In real Chrome, both the browser and renderer processes can safely use
    // `FAST` mode, because the side effects of quickly terminating the IPC
    // system in the middle of cross-process IPC message proxying is not
    // important. See this class's documentation for more information on
    // shutdown.
    //
    // We initialize `ipc_support` with a task runner for whatever thread should
    // be the IO thread. This means preferring `io_task_runner` when it is
    // non-null, and the default task runner otherwise.
    mojo::core::ScopedIPCSupport ipc_support(
        io_task_runner ? io_task_runner : (*default_tq)->task_runner(),
        mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
  }

  std::unique_ptr<base::sequence_manager::TaskQueue::Handle> default_tq;
  std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager;
  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner;

 private:
  // Note that you cannot call this if you've ever called
  // `InitMainThread(base::MessagePumpType::IO)` since that means the main
  // thread *itself* the IO thread.
  void InitDedicatedIOThread() {
    io_thread_ = std::make_unique<base::Thread>("ipc!");
    io_thread_->StartWithOptions(
        base::Thread::Options(base::MessagePumpType::IO, 0));
    io_task_runner = io_thread_->task_runner();
  }

  std::unique_ptr<base::Thread> io_thread_;
};

ProcessBootstrapperHelp::ProcessBootstrapperHelp() = default;
ProcessBootstrapperHelp::~ProcessBootstrapperHelp() = default;

#endif  // CODELABS_MOJO_EXAMPLES_PROCESS_BOOTSTRAPPER_HELPER_H_

六、添加demo\build.gn文件:

   1、  dem\BUILD.gn

# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
 
import("//build/config/compiler/compiler.gni")

group("jdcode_mojo_examples") {
  testonly = true
  if (is_win) {
    deps = [
      ":client",
      ":service",
    ]
  }
}

executable("client") {
    sources = [
        "client/client.cc",
        "client/logger_test.cc",
        "client/logger_test.h",
        "process_bootstrapper_helper.h",
    ]
 
    if (is_win) {
      ldflags = [ "/LARGEADDRESSAWARE" ]
    }
 
    deps = [
      "//base",
      "//build/win:default_exe_manifest",
      "//demo/logger/public/mojom",
      "//ipc",
      "//mojo/core/embedder",
      "//mojo/public/cpp/platform",
      "//mojo/public/mojom/base",
    ]
}

executable("service") {
    sources = [
         "service/service.cc",
         "service/LoggerImpl.h",
         "service/LoggerImpl.cc",
         "process_bootstrapper_helper.h",
    ]
 
    if (is_win) {
      ldflags = [ "/LARGEADDRESSAWARE" ]
    }
 
    deps = [
      "//base",
      "//build/win:default_exe_manifest",
      "//demo/logger/public/mojom",
      "//ipc",
      "//mojo/core/embedder",
      "//mojo/public/cpp/platform",
      "//mojo/public/mojom/base",
    ]
}

2、src\BUILD.gn 追加如下:

    if (is_win) {
      deps += [
        "//demo/logger/public/mojom",
        "//demo:jdcode_mojo_examples",
      ]
    }

七、开始编译和调试:

1、gn gen out/debug

   自动生成mojo文件:   

2、ninja -C out/debug client

编译client.exe

3、ninja -C out/debug service

编译service.exe

 4、最终生成文件如图:

八、看下调试堆栈效果: 

  8.1)、 client.exe主要流程:

1、初始化线程和mojo // mojo::core::Init(config);

  ProcessBootstrapperHelp bootstrapper;

  bootstrapper.InitMainThread(base::MessagePumpType::IO);

  bootstrapper.InitMojo(/*as_browser_process=*/true); 

2、LaunchAndConnect();

 2.1)、mojo::OutgoingInvitation建立并且启动service.exe[通过base::LaunchProcess],

2.2)将./service --mojo-platform-channel-handle=508传递给service.exe

3、CreateProcessRemote调用Log和GetTail接口函数

8.2)、service.exe主要流程:

1、初始化线程和mojo // mojo::core::Init(config);

  ProcessBootstrapperHelp bootstrapper;

  bootstrapper.InitMainThread(base::MessagePumpType::IO);

  bootstrapper.InitMojo(/*as_browser_process=*/false);

2、与client.exe建立链接:

  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");

3、BindProcessImpl(mojo::ScopedMessagePipeHandle pipe)处理客户端client.exe发出的函数请求Log和GetTail

8.3)、看下最终效果图:

总结: 

本文演示了通过mojo::IncomingInvitation进行通信的完整例子,仅供参考,mojo基础和原理参考官网介绍。


http://www.niftyadmin.cn/n/5739843.html

相关文章

UE5相机系统初探(一)

UE5相机系统初探&#xff08;一&#xff09; 和Unity类似&#xff0c;UE的相机也是由名为Camera的component控制的。那么&#xff0c;在UE中要如何实现一个跟随玩家的第三人称相机呢&#xff1f;假设我们已经有了一个表示玩家的类ACF_Character&#xff0c;首先第一步就是要先在…

导师双选系统开发:Spring Boot技术详解

第一章 绪论 1.1 选题背景 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;尽管身边每时每刻都在产生大量信息&#xff0c;这些信息也都会在短时间内得到处理&#xff0c;并迅速传播。因为很多时候&#xff0c;管理层决策需要大量信…

死锁(Dead Lock)

目录 一. 死锁出现的场景 1. 一个线程, 一个锁对象 2. 两个线程, 两个锁对象 3. N个线程, M个锁对象 二. 造成死锁的必要条件 1. 锁是互斥的 2. 锁是不可被抢占的 3.请求和保持 4. 循环等待 三. 死锁的解决方案 1. 预防死锁 2. 死锁产生后的解决 一. 死锁出现的场景…

Java环境下配置环境(jar包)并连接mysql数据库

目录 jar包下载 配置 简单连接数据库 一、注册驱动&#xff08;jdk6以后会自动注册&#xff09; 二、连接对应的数据库 以前学习数据库就只是操作数据库&#xff0c;根本不知道该怎么和软件交互&#xff0c;将存储的数据读到软件中去&#xff0c;最近学习了Java连接数据库…

江协科技STM32学习- P36 SPI通信外设

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

LabVIEW适合开发的软件

LabVIEW作为一种图形化编程环境&#xff0c;主要用于测试、测量和控制系统的开发。以下是LabVIEW在不同应用场景中的适用性和优势。 一、测试与测量系统 LabVIEW在测试与测量系统中的应用广泛&#xff0c;是工程测试领域的主流工具之一。利用其强大的数据采集与处理功能&…

5G工业网关的主要功能有哪些?天拓四方

随着5G技术的快速发展和广泛应用&#xff0c;其在工业领域的融合创新日益显著。5G工业网关作为连接工业设备与网络的关键枢纽&#xff0c;正逐步成为推动工业自动化、智能化和数字化的重要力量。 一、5G工业网关的定义 5G工业网关是一种基于5G网络技术的工业通信设备&#xf…

stm32使用串口的轮询模式,实现数据的收发

------内容以b站博主keysking为原型&#xff0c;整理而来&#xff0c;用作个人学习记录。 首先在STM32CubeMX中配置 前期工作省略&#xff0c;只讲重点设置。 这里我配置的是USART2的模式。 会发现&#xff0c;PA2和PA3分别是TX与RX&#xff0c;在连接串口时需要TX对RX&…