Mojo cho Nhà Phát Triển Chromium

Mojo cho Nhà Phát Triển Chromium

Tổng Quan

Tài liệu này chứa thông tin tối thiểu cần thiết để một nhà phát triển có thể bắt đầu sử dụng Mojo trong Chromium. Để biết tài liệu chi tiết hơn về các ràng buộc C++, hãy xem liên kết này.

Thuật Ngữ

Một ống tin nhắn là một cặp điểm cuối. Mỗi điểm cuối có hàng đợi tin nhắn đến, và việc gửi một tin nhắn tới một điểm cuối sẽ thực tế là thêm tin nhắn đó vào hàng đợi của điểm cuối còn lại. Vì vậy ống tin nhắn là hai chiều.

Một tệp mojom mô tả các giao diện mô tả cấu trúc tin nhắn có kiểu mạnh, tương tự như các tệp proto.

Cho một giao diện mojom và một ống tin nhắn, hai điểm cuối có thể được gán nhãn là InterfacePtrBinding. Điều này mô tả một ống tin nhắn có kiểu mạnh vận chuyển các tin nhắn được mô tả bởi giao diện mojom. InterfacePtrđiểm cuối "gửi" tin nhắn, và Binding "nhận" tin nhắn. Lưu ý rằng chính ống tin nhắn vẫn là hai chiều, và có thể có một phản hồi trả về, mà InterfacePtr sẽ nhận được.

Cách suy nghĩ khác là InterfacePtr có khả năng thực hiện các cuộc gọi từ xa trên một bản triển khai của giao diện mojom liên quan đến Binding.

Binding chỉ đơn giản là phần nối giữa hàng đợi tin nhắn của điểm cuối với một bản triển khai của giao diện do nhà phát triển cung cấp.

Ví Dụ

Hãy áp dụng điều này vào Chrome. Giả sử chúng ta muốn gửi một tin nhắn "Ping" từ Browser đến Renderer. Trước tiên chúng ta cần định nghĩa giao diện mojom.

module example.mojom;
interface PingResponder {
  // Nhận một "Ping" và phản hồi bằng một số nguyên ngẫu nhiên.
  Ping() => (int random);
};

Bây giờ hãy tạo một MessagePipe.

example::mojom::PingResponderPtr ping_responder;
example::mojom::PingResponderRequest request = mojo::MakeRequest(&ping_responder);

Trong ví dụ này, ping_responderInterfacePtr, và request là một InterfaceRequest, là tiền đề của Binding sẽ được chuyển thành Binding sau đó. Bây giờ chúng ta có thể gửi tin nhắn Ping của mình.

auto callback = base::Bind(&OnPong);
ping_responder->Ping(callback);

Lưu ý quan trọng: Nếu chúng ta muốn nhận phản hồi, chúng ta phải giữ đối tượng ping_responder sống. Tất cả, nó chỉ là một lớp bọc quanh một điểm cuối ống tin nhắn, nếu nó biến mất thì sẽ không còn gì để nhận phản hồi.

Chúng ta đã xong! Tất nhiên, nếu mọi thứ dễ dàng như vậy, tài liệu này sẽ không cần thiết. Chúng ta đã chuyển đổi vấn đề khó khăn là gửi một tin nhắn từ Browser đến Renderer thành một vấn đề chỉ cần lấy đối tượng request, truyền nó đến Renderer, chuyển nó thành một Binding, và triển khai giao diện.

Trong Chrome, các quy trình lưu trữ dịch vụ, và chính các dịch vụ được kết nối với Service Manager qua ống tin nhắn. Việc truyền request đến Renderer thích hợp dễ dàng bằng Service Manager, nhưng điều này yêu cầu khai báo rõ ý định thông qua các tệp manifest. Với ví dụ này, chúng ta sẽ sử dụng tệp manifest của dịch vụ content_browser và tệp manifest của dịch vụ content_renderer.

content_renderer_manifest.json:
...
  "interface_provider_specs": {
    "service_manager:connector": {
      "provides": {
        "cool_ping_feature": [
          "example::mojom::PingResponder"
        ]
      },
    },
...
content_browser_manifest.json:
...
 "interface_provider_specs": {
    "service_manager:connector": {
      "requires": {
        "content_renderer": [ "cool_ping_feature" ],
      },
    },
  },
...

Những thay đổi này cho thấy rằng dịch vụ content_renderer cung cấp giao diện PingResponder, dưới khả năng tên là "cool_ping_feature". Và dịch vụ content_browser dự định sử dụng tính năng này. content::BindInterface là hàm trợ giúp nhận request và gửi nó đến tiến trình renderer qua Service Manager.

content::RenderProcessHost* host = GetRenderProcessHost();
content::BindInterface(host, std::move(request));

Kết hợp tất cả lại cho quy trình Browser:

example::mojom::PingResponderPtr ping_responder;  // Đảm bảo giữ đối tượng này sống! Nếu không, phản hồi sẽ không bao giờ được nhận.
example::mojom::PingResponderRequest request = mojo::MakeRequest(&ping_responder);
ping_responder->Ping(base::BindOnce(&OnPong));
content::RenderProcessHost* host = GetRenderProcessHost();
content::BindInterface(host, std::move(request));

Trong quy trình Renderer, chúng ta cần viết bản triển khai cho PingResponder, và đảm bảo rằng một Binding được tạo bằng cách sử dụng request được truyền đi. Trong một dịch vụ Mojo độc lập, điều này đòi hỏi chúng ta triển khai service_manager::Service::OnBindInterface(). Trong Chrome, điều này được trừu tượng phía sau content::ConnectionFiltersservice_manager::BinderRegistry. Thường được thực hiện trong RenderThreadImpl::Init.

class PingResponderImpl : mojom::PingResponder {
  void BindToInterface(example::mojom::PingResponderRequest request) {
    binding_.reset(
      new mojo::Binding<mojom::MemlogClient>(this, std::move(request)));
  }
  void Ping(PingCallback callback) { std::move(callback).Run(4); }
  std::unique_ptr<mojo::Binding<mojom::PingResponder>> binding_;
};

RenderThreadImpl::Init() {
...
  this->ping_responder = std::make_unique<PingResponderImpl>();
  auto registry = base::MakeUnique<service_manager::BinderRegistry>();

  // Giả định rằng |this->ping_responder| sẽ sống lâu hơn |registry|.
  registry->AddInterface(base::Bind(&PingResponderImpl::BindToInterface), base::Unretained(this->ping_responder.get()));

  GetServiceManagerConnection()->AddConnectionFilter(
      base::MakeUnique<SimpleConnectionFilter>(std::move(registry)));
...

Được hỗ trợ bởi Gitiles| Bảo mật

Thẻ: Mojo Chromium message pipe InterfacePtr Binding

Đăng vào ngày 15 tháng 6 lúc 20:20