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 "