Chromium Mojo 消息管道的创建和使用
版本 | 备注 | 编写人 | 时间 |
---|---|---|---|
V1.0 | 初稿 | wangnn01 | 2020-1-9 |
文章目录
一、Mojo 消息管道(无响应)
S1 render 端
1.定义接口
在src/services/spider_mojo/ mojom/spider_mojo.mojom中创建以下Mojom文件,来定义一个简单的Logger接口,客户端可以使用该接口来输出简单的字符串消息:
1. module spider_mojo.mojom;
2.
3. interface Logger{
4. Log(string message);
5. };
还有一个GN目标(src/services/spider_mojo/ mojom/BUILD.gn)用来生成绑定:
1. import("//mojo/public/tools/bindings/mojom.gni")
2. mojom("mojom") {
3. sources = [ "spider_mojo.mojom" ]
4. }
确保需要此接口的任何目标都依赖于此接口,例如,在对应模块的BUILD.gn中添加像这样的一行:
1. deps += [ '//services/spider_mojo/mojom' ]
例如,在本示例中,render和browser进程中都需要Logger接口,因此需要在两个进程各自对应的模块中添加依赖,后面会详细讲述。
注:*.mojom
.mojom 是 mojo 的模板文件, mojo 类似于 Android 的 AIDL ,提供了跨语言(C++ / Java / JavaScript)的进程间对象(Object)通信机制, mojom 文件也类似于 aidl 文件,会生成进程间通信对象的抽象接口以及其底层的 IPC 实现。
2.创建管道&发送消息&发送一个PendingReceiver 至Browser
本示例中,我们在src/third_party/blink/renderer/core/html/parser/html_construction_site.cc的函数HTMLConstructionSite::FinishedParsing中添加如下代码:
1. //创建消息管道
2. mojo::Remote<spider_mojo::mojom::Logger> remote;
3. mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver = remote.BindNewPipeAndPassReceiver();
4. //发送消息
5. remote->Log("Hello");
6. //发送一个PendingReceiver到Browser
7. document_->GetBrowserInterfaceBroker().GetInterface(std::move(receiver));
注意:为了使用mojo相关的方法,还需在src/third_party/blink/renderer/core/html/parser/html_construction_site.cc中添加相应头文件:
1. #include "services/spider_mojo/mojom/spider_mojo.mojom.h"
2. //spider_mojo_impl.h为接口Logger的实现,在browser进程中定义,后续会详细讲述
3. #include "content/browser/spider_mojo/spider_mojo_impl.h"
在src/third_party/blink/renderer/core/html/parser/BUILD.gn中添加对接口Logger的依赖:
deps+={
"//services/spider_mojo/mojom"
}
render端的操作已完成,接下来是browser端。
S2 browser端
1.实现接口
本示例中,在src/content/browser中新建文件夹“spider_mojo”,并在该文件夹中新建spider_mojo_impl.h和spider_mojo_impl.cc。
其中,spider_mojo_impl.h的内容:
1. #include "base/logging.h"
2. #include "base/macros.h"
3. #include "mojo/public/cpp/bindings/receiver.h"
4. #include "mojo/public/cpp/bindings/binding.h"
5. #include "mojo/public/cpp/bindings/interface_request.h"
6. #include "services/spider_mojo/mojom/spider_mojo.mojom.h"
7.
8. namespace content{
9. class LoggerImpl : public spider_mojo::mojom::Logger {
10. public:
11. // NOTE: A common pattern for interface implementations which have one
12. // instance per client is to take a PendingReceiver in the constructor.
13.
14. explicit LoggerImpl(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver);
15.
16. ~LoggerImpl() override;
17.
18. // spider_mojo::mojom::Logger:
19. void Log(const std::string& message) override;
20.
21. private:
22. mojo::Receiver<spider_mojo::mojom::Logger> receiver_;
23.
24. DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
25. };
26. } //namespace content
spider_mojo_impl.cc的内容:
1. #include "content/browser/spider_mojo/spider_mojo_impl.h"
2. #include <utility>
3. #include "base/bind.h"
4.
5. namespace content{
6. LoggerImpl::LoggerImpl(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver)
7. : receiver_(this, std::move(receiver)) {}
8.
9. LoggerImpl::~LoggerImpl(){}
10.
11. void LoggerImpl::Log(const std::string& message) {
12. LOG(INFO) << "[Logger] " << message;
13. }
14. } // namespace content
在src/content/browser/BUILD.gn中相应位置添加依赖deps以及source:
1. deps += [
2. "//services/spider_mojo/mojom",
3. ]
...
1. sources += [
2. "spider_mojo/spider_mojo_impl.h",
3. "spider_mojo/spider_mojo_impl.cc",
4. ]
2.注册接口
注:*号为前缀的代码行需新添加。
1. //src/content/browser/frame_host/render_frame_host_impl.h
2. ...
3. *#include "services/spider_mojo/mojom/spider_mojo.mojom.h"
4. *#include "content/browser/spider_mojo/spider_mojo_impl.h"
5. ...
6.
7. namespace content {
8. ...
9. *class LoggerImpl;
10. ...
11. class CONTENT_EXPORT RenderFrameHostImpl{
12. public:
13. ...
14. *void GetLogger(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver);
15. ...
16. private:
17. ...
18. *std::unique_ptr<LoggerImpl> logger_;
19. ...
20. };
1. //src/content/browser/frame_host/render_frame_host_impl.cc
2. ...
3. * void RenderFrameHostImpl::GetLogger(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver){
4. * logger_ = std::make_unique<LoggerImpl>(std::move(receiver));
5. * LOG(INFO) << "Launching Successfully";
6. *}
1. //src/content/browser/browser_interface_binders.cc
2. ...
3. * #include "services/spider_mojo/mojom/spider_mojo.mojom.h"
4. ...
5. // Documents/frames
6. void PopulateFrameBinders(RenderFrameHostImpl* host,
7. service_manager::BinderMap* map) {
8. ...
9. * map->Add<spider_mojo::mojom::Logger>(base::BindRepeating(
10. &RenderFrameHostImpl::GetLogger,base::Unretained(host)));
11. ...
12. }
S3 编译
1.编译生成接口对应的源文件
使用ninja编译目标:
1. //在src/out/default目录下执行
2. ninja services/spider_mojo/mojom
执行完毕后,将会在src/out/Defaul/gen/service中生成相应的文件夹“spider_mojo”,该文件夹中包含生成的一些源文件:
2.编译content模块
使用ninja编译:
1. // 在src/out//Default目录下执行
2. ninja content
至此,大功告成,编译后会Log输出“hello”。
二、Mojo 消息管道(带响应)
创建过程和无响应的Mojo消息管道类似。
S1 render 端
1.定义接口
在src/services/spider_mojo/ mojom/spider_mojo.mojom中创建以下Mojom文件,来定义一个简单的Logger接口,客户端可以使用该接口来输出简单的字符串消息:
module blink.mojom;
interface Logger{
Log(string message);
GetTail() => (string message);
};
还有一个GN目标(src/services/spider_trans/ mojom/BUILD.gn)用来生成绑定:
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
sources = [ "spider_mojo.mojom" ]
}
确保需要此接口的任何目标都依赖于此接口,例如,在对应模块的BUILD.gn中添加像这样的一行:
1. deps += [ '//services/spider_mojo/mojom' ]
例如,在本示例中,render和browser进程中都需要Logger接口,因此需要在两个进程各自对应的模块中添加依赖,后面会详细讲述。
注:*.mojom
.mojom 是 mojo 的模板文件, mojo 类似于 Android 的 AIDL ,提供了跨语言(C++ / Java / JavaScript)的进程间对象(Object)通信机制, mojom 文件也类似于 aidl 文件,会生成进程间通信对象的抽象接口以及其底层的 IPC 实现。
2.创建管道&发送消息&发送一个PendingReceiver 至Browser
本示例中,我们在src/third_party/blink/renderer/core/html/parser/html_construction_site.cc中添加如下代码:
void HTMLConstructionSite::OnGetTail(const std::string& message) {
LOG(ERROR) << "Tail was: " << message;
}
...
void HTMLConstructionSite::FinishedParsing(){
...
//创建消息管道
mojo::Remote<spider_mojo::mojom::Logger> remote;
mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver = remote.BindNewPipeAndPassReceiver();
//发送一个PendingReceiver到Browser
document_->GetBrowserInterfaceBroker().GetInterface(std::move(receiver));
//发送消息
remote->Log("Hello");
//获得响应
remote->GetTail(base::BindOnce(&OnGetTail) ,base::Unretained(this));
...
}
注意:为了使用mojo相关的方法,还需在src/third_party/blink/renderer/core/html/parser/html_construction_site.cc中添加相应头文件:
1. #include "services/spider_mojo/mojom/spider_mojo.mojom.h"
2. //spider_mojo_impl.h为接口Logger的实现,在browser进程中定义,后续会详细讲述
3. #include "content/browser/spider_mojo/spider_mojo_impl.h"
在src/third_party/blink/renderer/core/html/parser/BUILD.gn中添加对接口Logger的依赖:
deps+={
"//services/spider_mojo/mojom"
}
render端的操作已完成,接下来是browser端。
S2 browser端
1.实现接口
本示例中,在src/content/browser中新建文件夹“spider_mojo”,并在该文件夹中新建spider_mojo_impl.h和spider_mojo_impl.cc。
其中,spider_mojo_impl.h的内容:
#include "base/logging.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/spider_mojo/mojom/spider_mojo.mojom.h"
namespace content{
class LoggerImpl : public spider_mojo::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<spider_mojo::mojom::Logger> receiver); ~LoggerImpl() override;
// spider_mojo::mojom::Logger:
void Log(const std::string& message) override;
void GetTail(GetTailCallback callback) override;
private:
mojo::Receiver<spider_mojo::mojom::Logger> receiver_;
std::string response;
DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
};
} //namespace content
spider_mojo_impl.cc的内容:
#include "content/browser/spider_mojo/spider_mojo_impl.h"
#include <utility>
#include "base/bind.h"
namespace content{
LoggerImpl::LoggerImpl(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver)
: receiver_(this, std::move(receiver)) {}
LoggerImpl::~LoggerImpl(){}
void LoggerImpl::Log(const std::string& message) {
LOG(INFO) << "[Logger] " << message;
response = message;
}
void GetTail(GetTailCallback callback) {
std::move(callback).Run(response);
}
} // namespace content
在src/content/browser/BUILD.gn中相应位置添加依赖deps以及source:
1. deps += [
2. "//services/spider_mojo/mojom",
3. ]
...
1. sources += [
2. "spider_mojo/spider_mojo_impl.h",
3. "spider_mojo/spider_mojo_impl.cc",
4. ]
2.注册接口
注:*号为前缀的代码行需新添加。
1. //src/content/browser/frame_host/render_frame_host_impl.h
2. ...
3. *#include "services/spider_mojo/mojom/spider_mojo.mojom.h"
4. *#include "content/browser/spider_mojo/spider_mojo_impl.h"
5. ...
6.
7. namespace content {
8. ...
9. *class LoggerImpl;
10. ...
11. class CONTENT_EXPORT RenderFrameHostImpl{
12. public:
13. ...
14. *void GetLogger(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver);
15. ...
16. private:
17. ...
18. *std::unique_ptr<LoggerImpl> logger_;
19. ...
20. };
1. //src/content/browser/frame_host/render_frame_host_impl.cc
2. ...
3. * void RenderFrameHostImpl::GetLogger(mojo::PendingReceiver<spider_mojo::mojom::Logger> receiver){
4. * logger_ = std::make_unique<LoggerImpl>(std::move(receiver));
5. * LOG(INFO) << "Launching Successfully";
6. *}
1. //src/content/browser/browser_interface_binders.cc
2. ...
3. * #include "services/spider_mojo/mojom/spider_mojo.mojom.h"
4. ...
5. // Documents/frames
6. void PopulateFrameBinders(RenderFrameHostImpl* host,
7. service_manager::BinderMap* map) {
8. ...
9. * map->Add<spider_mojo::mojom::Logger>(base::BindRepeating(
10. &RenderFrameHostImpl::GetLogger,base::Unretained(host)));
11. ...
12. }
S3 编译
1.编译生成接口对应的源文件
使用ninja编译目标:
1. //在src/out/default目录下执行
2. ninja services/spider_mojo/mojom
执行完毕后,将会在src/out/Defaul/gen/service中生成相应的文件夹“spider_mojo”,该文件夹中包含生成的一些源文件:
2.编译content模块
使用ninja编译:
1. // 在src/out//Default目录下执行
2. ninja content
至此,大功告成,编译后会Log输出“hello”和 "Tail was: hello "