chromium通信系统-ipcz系统(七)-ipcz系统代码实现-跨Node通信-NonBroker和NonBroker通信

chromium通信系统-ipcz系统(六)-ipcz系统代码实现-跨Node通信-基础通信 一文中我们分析了broker 和 nonbroker 通信的过程。本文我们来分析NonBroker 和NonBroker的通信过程,同样以单元测试为例子分析。

mojo/core/invitation_unittest.cc

cpp 复制代码
 951 DEFINE_TEST_CLIENT(NonBrokerToNonBrokerHost) {
 952   MojoHandle invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_NONE);
 953   MojoHandle test = ExtractPipeFromInvitation(invitation);
 954 
 955   MojoHandle pipe_for_client;
 956   EXPECT_EQ("aaa", ReadMessageWithHandles(test, &pipe_for_client, 1));
 957 
 958   MojoHandle client;
 959   base::Process client_process =
 960       LaunchChildTestClient("NonBrokerToNonBrokerClient", &client, 1,
 961                             MOJO_SEND_INVITATION_FLAG_SHARE_BROKER);
 962 
 963   // Forward the pipe from the test to the client, then wait. We're done
 964   // whenever the client acks. The success of the test is determined by
 965   // the outcome of interactions between the test and the client process.
 966   WriteMessageWithHandles(client, "ddd", &pipe_for_client, 1);
 967 
 968   // Wait for a signal from the test to let us know we can terminate.
 969   EXPECT_EQ("bye", ReadMessage(test));
 970   WriteMessage(client, "bye");
 971   WaitForProcessToTerminate(client_process);
 972 
 973   MojoClose(client);
 974   MojoClose(test);
 975 }

在TEST_F(MAYBE_InvitationTest, NonBrokerToNonBroker) 这个单元测试工A和B进程是Broker和NonBroker 通信,B进程启动后又调用LaunchChildTestClient 启动C进程(代码960行), 我们进入590行来分析B和C如何通信。LaunchChildTestClient我们已经分析过了,不过在broker 启动非broker进程中第三个参数是MOJO_SEND_INVITATION_FLAG_NONE,而这里是MOJO_SEND_INVITATION_FLAG_SHARE_BROKER,通过值的名称我们可以看出来,这里是要建立共享broker。LaunchChildTestClient前边的调用流程和Broker 启动NonBroker没有区别,我们重点分析对MOJO_SEND_INVITATION_FLAG_SHARE_BROKER的特殊处理, 直接看建立Connector的过程。

third_party/ipcz/src/ipcz/node_connector.cc

cpp 复制代码
528 // static
529 IpczResult NodeConnector::ConnectNode(
530     Ref<Node> node,
531     Ref<DriverTransport> transport,
532     IpczConnectNodeFlags flags,
533     const std::vector<Ref<Portal>>& initial_portals,
534     ConnectCallback callback) {
535   const bool from_broker = node->type() == Node::Type::kBroker;
536   const bool to_broker = (flags & IPCZ_CONNECT_NODE_TO_BROKER) != 0;
537   const bool inherit_broker = (flags & IPCZ_CONNECT_NODE_INHERIT_BROKER) != 0;
538   const bool share_broker = (flags & IPCZ_CONNECT_NODE_SHARE_BROKER) != 0;
539   Ref<NodeLink> broker_link = node->GetBrokerLink();
      ......
546 
547   auto [connector, result] = CreateConnector(
548       std::move(node), std::move(transport), flags, initial_portals,
549       std::move(broker_link), std::move(callback));
550   if (result != IPCZ_RESULT_OK) {
551     return result;
552   }
553 
554   if (!share_broker && !connector->ActivateTransport()) {
555     // Note that when referring another node to our own broker, we don't
556     // activate the transport, since the transport will be passed to the broker.
557     // See NodeConnectorForReferrer.
558     return IPCZ_RESULT_UNKNOWN;
559   }
560 
561   if (!connector->Connect()) {
562     return IPCZ_RESULT_UNKNOWN;
563   }
564 
565   return IPCZ_RESULT_OK;
566 }

先分析B进程

函数参数transport是指B和C的传输点。flags 为IPCZ_CONNECT_NODE_SHARE_BROKER,所以538行share_broker为真。547行创建Connector。 与Broker 和NonBroker通信不同,这里554行并不会激活传输点。 561行直接调用Connector的Connect方法。我们先来看CreateConnector方法创建哪一类Connector。

cpp 复制代码
471 std::pair<Ref<NodeConnector>, IpczResult> CreateConnector(
472     Ref<Node> node,
473     Ref<DriverTransport> transport,
474     IpczConnectNodeFlags flags,
475     const std::vector<Ref<Portal>>& initial_portals,
476     Ref<NodeLink> broker_link,
477     NodeConnector::ConnectCallback callback) {
478   const bool from_broker = node->type() == Node::Type::kBroker;
479   const bool to_broker = (flags & IPCZ_CONNECT_NODE_TO_BROKER) != 0;
480   const bool share_broker = (flags & IPCZ_CONNECT_NODE_SHARE_BROKER) != 0;
481   const bool inherit_broker = (flags & IPCZ_CONNECT_NODE_INHERIT_BROKER) != 0;
      ......
508 
509   if (share_broker) {
510     return {MakeRefCounted<NodeConnectorForReferrer>(
511                 std::move(node), std::move(transport), flags, initial_portals,
512                 std::move(broker_link), std::move(callback)),
513             IPCZ_RESULT_OK};
514   }
515 
     ......
522 
523   return {nullptr, IPCZ_RESULT_INVALID_ARGUMENT};
524 }

函数510行创建了NodeConnectorForReferrer。

cpp 复制代码
  NodeConnectorForReferrer(Ref<Node> node,
                           Ref<DriverTransport> transport,
                           IpczConnectNodeFlags flags,
                           std::vector<Ref<Portal>> waiting_portals,
                           Ref<NodeLink> broker_link,
                           ConnectCallback callback)
      : NodeConnector(std::move(node),
                      /*transport=*/nullptr,
                      flags,
                      std::move(waiting_portals),
                      std::move(callback)),
        transport_for_broker_(std::move(transport)),
        broker_link_(std::move(broker_link)) {}

NodeConnectorForReferrer的成员变量transport_for_broker_代表B和C的传输点。 broker_link_则表示B->A(Broker) 的链接。

cpp 复制代码
166   // NodeConnector:
167   bool Connect() override {
168     ABSL_ASSERT(node_->type() == Node::Type::kNormal);
169     if (!broker_link_) {
170       // If there's no broker link yet, wait for one.
171       node_->WaitForBrokerLinkAsync(
172           [connector = WrapRefCounted(this)](Ref<NodeLink> broker_link) {
173             connector->broker_link_ = std::move(broker_link);
174             connector->Connect();
175           });
176       return true;
177     }
178 
179     broker_link_->ReferNonBroker(
180         std::move(transport_for_broker_), checked_cast<uint32_t>(num_portals()),
181         [connector = WrapRefCounted(this), broker = broker_link_](
182             Ref<NodeLink> link_to_referred_node,
183             uint32_t remote_num_initial_portals) {
184           if (link_to_referred_node) {
185             connector->AcceptConnection(
186                 {.link = link_to_referred_node, .broker = broker},
187                 remote_num_initial_portals);
188           } else {
189             connector->RejectConnection();
190           }
191         });
192     return true;
193   }

NodeConnectorForReferrer->Connect()函数:

169到177行如果A和B还没完全建立链接,则调用node_->WaitForBrokerLinkAsync异步等待链接建立后再执行NodeConnectorForReferrer->Connect()函数。

179-191行broker_link_->ReferNonBroker() 函数建立链接。181-191行为一个回调函数,我们后面分析。

cpp 复制代码
 223 void NodeLink::ReferNonBroker(Ref<DriverTransport> transport,
 224                               uint32_t num_initial_portals,
 225                               ReferralCallback callback) {
 226   ABSL_ASSERT(node_->type() == Node::Type::kNormal &&
 227               remote_node_type_ == Node::Type::kBroker);
 228 
 229   uint64_t referral_id;
 230   {
 231     absl::MutexLock lock(&mutex_);
 232     for (;;) {
 233       referral_id = next_referral_id_++;
 234       auto [it, inserted] =
 235           pending_referrals_.try_emplace(referral_id, std::move(callback));
 236       if (inserted) {
 237         break;
 238       }
 239     }
 240   }
 241 
 242   msg::ReferNonBroker refer;
 243   refer.params().referral_id = referral_id;
 244   refer.params().num_initial_portals = num_initial_portals;
 245   refer.params().transport =
 246       refer.AppendDriverObject(transport->TakeDriverObject());
 247   Transmit(refer);
 248 }

注意这个NodeLink是B->A的NodeLink,A是Broker。

229 -240行生成一个referral_id,用于维护请求和回调函数的关系。

242-247行创建ReferNonBroker消息体,并发起传输。ReferNonBroker有三个参数referral_id用于找到对应回调。num_initial_portals表示B和C要建立的RouterLink。 transport为B->C的传输端点。

我们来看A如何处理该消息

cpp 复制代码
 366 bool NodeLink::OnReferNonBroker(msg::ReferNonBroker& refer) {
 367   if (remote_node_type_ != Node::Type::kNormal ||
 368       node()->type() != Node::Type::kBroker) {
 369     return false;
 370   }
 371 
 372   DriverObject transport = refer.TakeDriverObject(refer.params().transport);
 373   if (!transport.is_valid()) {
 374     return false;
 375   }
 376 
 377   DriverMemoryWithMapping link_memory =
 378       NodeLinkMemory::AllocateMemory(node()->driver());
 379   DriverMemoryWithMapping client_link_memory =
 380       NodeLinkMemory::AllocateMemory(node()->driver());
      ......
 390 
 391   return NodeConnector::HandleNonBrokerReferral(
 392       node(), refer.params().referral_id, refer.params().num_initial_portals,
 393       WrapRefCounted(this),
 394       MakeRefCounted<DriverTransport>(std::move(transport)),
 395       std::move(link_memory), std::move(client_link_memory));
 396 }

函数很简单,377-380行创建了两个内存映射对象,实际上指向同一块内存。

391行调用 NodeConnector::HandleNonBrokerReferral() 函数进一步处理。注意这里的transport是通过B->C的文件描述符反序列化出来的(文件描述符通过socket传递),所以这里A->C也具备了信道。

cpp 复制代码
bool NodeConnector::HandleNonBrokerReferral(
    Ref<Node> node,
    uint64_t referral_id,
    uint32_t num_initial_portals,
    Ref<NodeLink> referrer,
    Ref<DriverTransport> transport_to_referred_node,
    DriverMemoryWithMapping link_memory,
    DriverMemoryWithMapping client_link_memory) {
  ABSL_ASSERT(node->type() == Node::Type::kBroker);
  auto connector = MakeRefCounted<NodeConnectorForBrokerReferral>(
      std::move(node), referral_id, num_initial_portals, std::move(referrer),
      std::move(transport_to_referred_node), std::move(link_memory),
      std::move(client_link_memory));

  // The connector effectively owns itself and lives only until its transport is
  // disconnected or it receives a greeting from the referred node.
  return connector->ActivateTransport();
}

HandleNonBrokerReferral函数先创建了NodeConnectorForBrokerReferral对象,这是一个Connector对象,然后调用connector->ActivateTransport()激活传输点。先来看NodeConnectorForBrokerReferral对象创建

cpp 复制代码
  NodeConnectorForBrokerReferral(Ref<Node> node,
                                 uint64_t referral_id,
                                 uint32_t num_initial_portals,
                                 Ref<NodeLink> referrer,
                                 Ref<DriverTransport> transport,
                                 DriverMemoryWithMapping link_memory,
                                 DriverMemoryWithMapping client_link_memory)
      : NodeConnector(std::move(node),
                      std::move(transport),
                      IPCZ_NO_FLAGS,
                      /*waiting_portals=*/{},
                      /*callback=*/nullptr),
        referral_id_(referral_id),
        num_initial_portals_(num_initial_portals),
        referrer_(std::move(referrer)),
        link_memory_(std::move(link_memory)),
        client_link_memory_(std::move(client_link_memory)) {
    ABSL_HARDENING_ASSERT(link_memory_.mapping.is_valid());
    ABSL_HARDENING_ASSERT(client_link_memory_.mapping.is_valid());
  }

NodeConnectorForBrokerReferral的成员变量如下:

  • referral_id_ 对端请求的id
  • num_initial_portals_ B和C要初始建立的RouterLink数量
  • referrer_: A->B的链接
  • transport:A->C的传输点
  • link_memory_ : Broker创建的共享内存对象
  • client_link_memory_: Broker创建的共享内存对象
    到目前位置建立的信道:
    A<->B, A<->C, B<->C。

传输点激活的代码我们在chromium通信系统-ipcz系统(五)-ipcz系统代码实现-信道和共享内存一文已经分析过了。

我们接下来看C进程接收邀请。

cpp 复制代码
DEFINE_TEST_CLIENT(NonBrokerToNonBrokerClient) {
  MojoHandle invitation =
      AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_INHERIT_BROKER);
 ......
}

这里面标志为MOJO_ACCEPT_INVITATION_FLAG_INHERIT_BROKER, AcceptInvitation在chromium通信系统-ipcz系统(五)-ipcz系统代码实现-信道和共享内存一文已经分析过了。我们主要关注对MOJO_ACCEPT_INVITATION_FLAG_INHERIT_BROKER标志的处理。同样直接看Connect的过程

cpp 复制代码
528 // static
529 IpczResult NodeConnector::ConnectNode(
530     Ref<Node> node,
531     Ref<DriverTransport> transport,
532     IpczConnectNodeFlags flags,
533     const std::vector<Ref<Portal>>& initial_portals,
534     ConnectCallback callback) {
535   const bool from_broker = node->type() == Node::Type::kBroker;
536   const bool to_broker = (flags & IPCZ_CONNECT_NODE_TO_BROKER) != 0;
537   const bool inherit_broker = (flags & IPCZ_CONNECT_NODE_INHERIT_BROKER) != 0;
538   const bool share_broker = (flags & IPCZ_CONNECT_NODE_SHARE_BROKER) != 0;
539   Ref<NodeLink> broker_link = node->GetBrokerLink();
540   if (share_broker && (from_broker || to_broker || inherit_broker)) {
541     return IPCZ_RESULT_INVALID_ARGUMENT;
542   }
543   if ((to_broker || from_broker) && (inherit_broker || share_broker)) {
544     return IPCZ_RESULT_INVALID_ARGUMENT;
545   }
546 
547   auto [connector, result] = CreateConnector(
548       std::move(node), std::move(transport), flags, initial_portals,
549       std::move(broker_link), std::move(callback));
550   if (result != IPCZ_RESULT_OK) {
551     return result;
552   }
553 
554   if (!share_broker && !connector->ActivateTransport()) {
555     // Note that when referring another node to our own broker, we don't
556     // activate the transport, since the transport will be passed to the broker.
557     // See NodeConnectorForReferrer.
558     return IPCZ_RESULT_UNKNOWN;
559   }
560 
561   if (!connector->Connect()) {
562     return IPCZ_RESULT_UNKNOWN;
563   }
564 
565   return IPCZ_RESULT_OK;
566 }

这里inherit_broker表示继承broker,也代表该节点非中心链接。

函数先创建Connector,然后激活传输点,最后请求建立链接,这个函数我们分析好几遍了,直接先Connector的创建。

cpp 复制代码
471 std::pair<Ref<NodeConnector>, IpczResult> CreateConnector(
472     Ref<Node> node,
473     Ref<DriverTransport> transport,
474     IpczConnectNodeFlags flags,
475     const std::vector<Ref<Portal>>& initial_portals,
476     Ref<NodeLink> broker_link,
477     NodeConnector::ConnectCallback callback) {
478   const bool from_broker = node->type() == Node::Type::kBroker;
479   const bool to_broker = (flags & IPCZ_CONNECT_NODE_TO_BROKER) != 0;
480   const bool share_broker = (flags & IPCZ_CONNECT_NODE_SHARE_BROKER) != 0;
481   const bool inherit_broker = (flags & IPCZ_CONNECT_NODE_INHERIT_BROKER) != 0;
      ......
516   if (inherit_broker) {
517     return {MakeRefCounted<NodeConnectorForReferredNonBroker>(
518                 std::move(node), std::move(transport), flags, initial_portals,
519                 std::move(callback)),
520             IPCZ_RESULT_OK};
521   }
522 
523   return {nullptr, IPCZ_RESULT_INVALID_ARGUMENT};
524 }
525 
526 }  // namespace
527 

这里创建的Connector为NodeConnectorForReferredNonBroker。我们看下它是如何创建的

cpp 复制代码
203   NodeConnectorForReferredNonBroker(Ref<Node> node,
204                                     Ref<DriverTransport> transport,
205                                     IpczConnectNodeFlags flags,
206                                     std::vector<Ref<Portal>> waiting_portals,
207                                     ConnectCallback callback)
208       : NodeConnector(std::move(node),
209                       std::move(transport),
210                       flags,
211                       std::move(waiting_portals),
212                       std::move(callback)) {}

比较简单, 传输点的激活我们在chromium通信系统-ipcz系统(五)-ipcz系统代码实现-信道和共享内存一文已经分析过了。接下来看一下请求链接的过程

cpp 复制代码
216   // NodeConnector:
217   bool Connect() override {
218     ABSL_ASSERT(node_->type() == Node::Type::kNormal);
219     msg::ConnectToReferredBroker connect;
220     connect.params().protocol_version = msg::kProtocolVersion;
221     connect.params().num_initial_portals =
222         checked_cast<uint32_t>(num_portals());
223     return IPCZ_RESULT_OK == transport_->Transmit(connect);
224   }

创建了一个ConnectToReferredBroker对象,这个对象非常简单。只有要初始化的端口数一个参数。 由于此时B进程并没有激活传输点,消息会被A进程读取。我们来看A进程如何处理。

回到A进程, NodeConnectorForBrokerReferral会收到对应消息。

cpp 复制代码
314   // NodeMessageListener overrides:
315   bool OnConnectToReferredBroker(
316       msg::ConnectToReferredBroker& connect_to_broker) override {
317     DVLOG(4) << "Accepting ConnectToReferredBroker on broker "
318              << broker_name_.ToString() << " from new referred node "
319              << referred_node_name_.ToString();
320 
321     // Ensure this NodeConnector stays alive until this method returns.
322     // Otherwise the last reference may be dropped when the new NodeLink below
323     // takes over listening on `transport_`.
324     Ref<NodeConnector> self(this);
325 
326     // First, accept the new non-broker client on this broker node. There are
327     // no initial portals on this link, as this link was not established
328     // directly by the application. Note that this takes over listsening on
329     // `transport_`
330     const uint32_t protocol_version = std::min(
331         connect_to_broker.params().protocol_version, msg::kProtocolVersion);
        // 建立A->C的NodeLink
332     Ref<NodeLink> link_to_referree = NodeLink::CreateActive(
333         node_, LinkSide::kA, broker_name_, referred_node_name_,
334         Node::Type::kNormal, protocol_version, transport_,
335         NodeLinkMemory::Create(node_, std::move(link_memory_.mapping)));
336     AcceptConnection({.link = link_to_referree}, /*num_remote_portals=*/0);
337 
338     // Now we can create a new link to introduce both clients -- the referrer
339     // and the referree -- to each other.
        // 创建一对传输点
340     auto [referrer, referree] = DriverTransport::CreatePair(
341         node_->driver(), referrer_->transport().get(), transport_.get());
342 
343     // Give the referred node a reply with sufficient details for it to
344     // establish links to both this broker and the referrer simultaneously.
345     //
346     // SUBTLE: It's important that this message is sent before the message to
347     // the referrer below. Otherwise the referrer might begin relaying messages
348     // through the broker to the referree before this handshake is sent to the
349     // referree, which would be bad.
350     msg::ConnectToReferredNonBroker connect;
351     connect.params().name = referred_node_name_;
352     connect.params().broker_name = broker_name_;
353     connect.params().referrer_name = referrer_->remote_node_name();
354     connect.params().broker_protocol_version = protocol_version;
355     connect.params().referrer_protocol_version =
356         referrer_->remote_protocol_version();
357     connect.params().num_initial_portals = num_initial_portals_;
358     connect.params().broker_link_buffer =
359         connect.AppendDriverObject(link_memory_.memory.TakeDriverObject());
360     connect.params().referrer_link_transport =
361         connect.AppendDriverObject(referree->TakeDriverObject());
362     connect.params().referrer_link_buffer = connect.AppendDriverObject(
363         client_link_memory_.memory.Clone().TakeDriverObject());
        // 向C发送ConnectToReferredNonBroker 消息
364     link_to_referree->Transmit(connect);
365 
366     // Finally, give the referrer a repy which includes details of its new link
367     // to the referred node.
368     msg::NonBrokerReferralAccepted accepted;
369     accepted.params().referral_id = referral_id_;
370     accepted.params().protocol_version =
371         connect_to_broker.params().protocol_version;
372     accepted.params().num_initial_portals =
373         connect_to_broker.params().num_initial_portals;
374     accepted.params().name = referred_node_name_;
375     accepted.params().transport =
376         accepted.AppendDriverObject(referrer->TakeDriverObject());
377     accepted.params().buffer = accepted.AppendDriverObject(
378         client_link_memory_.memory.TakeDriverObject());
        // 向B发送NonBrokerReferralAccepted 消息
379     referrer_->Transmit(accepted);
380     return true;
381   }

函数332-336 建立A->C的NodeLink。340-341行创建一对传输点(这对传输点可以互相通信)

350行-364行向C发送一个ConnectToReferredNonBroker消息

368-379行向B发送一个NonBrokerReferralAccepted 消息。我们先来看一下ConnectToReferredNonBroker包含的参数。

ConnectToReferredNonBroker:

  • name: 为C分配的NodeName
  • broker_name_: A进程为broker进程,它对应的名字
  • referrer_name: B进程Node的名字
  • broker_protocol_version: broker协议版本
  • referrer_protocol_version:B的协议版本
  • num_initial_portals 初始化端口数量
  • broker_link_buffer 和broker的共享内存
  • referrer_link_transport:创建的一对传输点的一端
  • referrer_link_buffer 和B的共享内存

再来看一下NonBrokerReferralAccepted的数据过程

  • referral_id:B的请求id
  • protocol_version 协议版本
  • num_initial_portals 初始化端口数
  • referred_node_name_ C NodeName
  • transport:创建的一对传输点的另一端
  • buffer:共享内存

知道的消息体的结构,我们大概可以知道A进程帮助B、C进程创建了一个通信管道,这就是broker的作用,我们来具体看B、C进程如何处理消息。 先看C进程

third_party/ipcz/src/ipcz/node_connector.cc

NodeConnectorForReferredNonBroker

cpp 复制代码
227   bool OnConnectToReferredNonBroker(
228       msg::ConnectToReferredNonBroker& connect) override {
        ......
234     DriverMemoryMapping broker_mapping =
235         DriverMemory(
236             connect.TakeDriverObject(connect.params().broker_link_buffer))
237             .Map();
238     DriverMemoryMapping referrer_mapping =
239         DriverMemory(
240             connect.TakeDriverObject(connect.params().referrer_link_buffer))
241             .Map();
242     Ref<DriverTransport> referrer_transport = MakeRefCounted<DriverTransport>(
243         connect.TakeDriverObject(connect.params().referrer_link_transport));
244     if (!broker_mapping.is_valid() || !referrer_mapping.is_valid() ||
245         !referrer_transport->driver_object().is_valid()) {
246       return false;
247     }
248 
249     // Ensure this NodeConnector stays alive until this method returns.
250     // Otherwise the last reference may be dropped when the new NodeLink takes
251     // over listening on `transport_`.
252     Ref<NodeConnector> self(this);
253     const uint32_t broker_protocol_version = std::min(
254         connect.params().broker_protocol_version, msg::kProtocolVersion);
255     auto broker_link = NodeLink::CreateActive(
256         node_, LinkSide::kB, connect.params().name,
257         connect.params().broker_name, Node::Type::kBroker,
258         broker_protocol_version, transport_,
259         NodeLinkMemory::Create(node_, std::move(broker_mapping)));
260     if ((flags_ & IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE) != 0) {
261       node_->SetAllocationDelegate(broker_link);
262     }
263     node_->AddConnection(connect.params().broker_name,
264                          {
265                              .link = broker_link,
266                              .broker = broker_link,
267                          });
268 
269     const uint32_t referrer_protocol_version = std::min(
270         connect.params().referrer_protocol_version, msg::kProtocolVersion);
271     auto referrer_link = NodeLink::CreateInactive(
272         node_, LinkSide::kB, connect.params().name,
273         connect.params().referrer_name, Node::Type::kNormal,
274         referrer_protocol_version, std::move(referrer_transport),
275         NodeLinkMemory::Create(node_, std::move(referrer_mapping)));
276 
277     AcceptConnection({.link = referrer_link, .broker = broker_link},
278                      connect.params().num_initial_portals);
279     referrer_link->Activate();
280     return true;
281   }
	

252-267行创建了和broker(A进程)的NodeLink。

269-278行 创建了C和B的NodeLink,并初始化端口,然后激活链接。

我们再开看B进程如何处理NonBrokerReferralAccepted消息

third_party/ipcz/src/ipcz/node_link.cc

cpp 复制代码
398 bool NodeLink::OnNonBrokerReferralAccepted(
 399     msg::NonBrokerReferralAccepted& accepted) {
 400   if (remote_node_type_ != Node::Type::kBroker) {
 401     return false;
 402   }
 403 
 404   ReferralCallback callback;
 405   {
 406     absl::MutexLock lock(&mutex_);
 407     auto it = pending_referrals_.find(accepted.params().referral_id);
 408     if (it == pending_referrals_.end()) {
 409       return false;
 410     }
 411     callback = std::move(it->second);
 412     pending_referrals_.erase(it);
 413   }
 414 
 415   const uint32_t protocol_version =
 416       std::min(msg::kProtocolVersion, accepted.params().protocol_version);
 417   auto transport = MakeRefCounted<DriverTransport>(
 418       accepted.TakeDriverObject(accepted.params().transport));
 419   DriverMemoryMapping mapping =
 420       DriverMemory(accepted.TakeDriverObject(accepted.params().buffer)).Map();
 421   if (!transport->driver_object().is_valid() || !mapping.is_valid()) {
 422     // Not quite a validation failure if the broker simply failed to allocate
 423     // resources for this link. Treat it like a connection failure.
 424     callback(/*link=*/nullptr, /*num_initial_portals=*/0);
 425     return true;
 426   }
 427 
 428   Ref<NodeLink> link_to_referree = NodeLink::CreateInactive(
 429       node_, LinkSide::kA, local_node_name_, accepted.params().name,
 430       Node::Type::kNormal, protocol_version, std::move(transport),
 431       NodeLinkMemory::Create(node_, std::move(mapping)));
 432   callback(link_to_referree, accepted.params().num_initial_portals);
 433   link_to_referree->Activate();
 434   return true;
 435 }

创建了B->C的NodeLink,并激活。这个过程中还会回调callback。回顾一下回调函数

cpp 复制代码
166   // NodeConnector:
167   bool Connect() override {
168     ABSL_ASSERT(node_->type() == Node::Type::kNormal);
169     if (!broker_link_) {
170       // If there's no broker link yet, wait for one.
171       node_->WaitForBrokerLinkAsync(
172           [connector = WrapRefCounted(this)](Ref<NodeLink> broker_link) {
173             connector->broker_link_ = std::move(broker_link);
174             connector->Connect();
175           });
176       return true;
177     }
178 
179     broker_link_->ReferNonBroker(
180         std::move(transport_for_broker_), checked_cast<uint32_t>(num_portals()),
181         [connector = WrapRefCounted(this), broker = broker_link_](
182             Ref<NodeLink> link_to_referred_node,
183             uint32_t remote_num_initial_portals) {
184           if (link_to_referred_node) {
185             connector->AcceptConnection(
186                 {.link = link_to_referred_node, .broker = broker},
187                 remote_num_initial_portals);
188           } else {
189             connector->RejectConnection();
190           }
191         });
192     return true;
193   }

181-191行,调用AcceptConnection 接受链接。

到这里我们大概理解了NonBroker和NonBroker通信的流程,是借助broker实现的,broker帮忙建立Transport,并且分配共享内存。

到这里NonBroker 和NonBroker通信我们就分析完了。

相关推荐
微wx笑10 小时前
chrome扩展程序如何实现国际化
前端·chrome
CUIYD_198910 小时前
Chrome 浏览器(版本号49之后)‌解决跨域问题
前端·chrome
Dontla1 天前
华为昇腾服务器(固件版本查询、驱动版本查询、CANN版本查询)
运维·服务器·chrome
JsenLong1 天前
ubuntu 守护进程
linux·chrome·ubuntu
前端大全1 天前
Chrome 推出全新的 DOM API,彻底革新 DOM 操作!
前端·chrome
林的快手1 天前
CSS文本属性
前端·javascript·css·chrome·node.js·css3·html5
码农君莫笑1 天前
Linux系统上同时打印到物理打印机并生成PDF副本方法研究
linux·前端·chrome·打印·信管通
代码轨迹2 天前
青龙面板运行selenium启动Chrome报错
chrome·python·selenium
三月七(爱看动漫的程序员)2 天前
与本地电脑PDF文档对话的PDF问答程序
前端·人工智能·chrome·gpt·搜索引擎·pdf·知识图谱
码界领航2 天前
【2025最新版】Chrome谷歌浏览器如何能恢复到之前的旧版本
前端·chrome