1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2015 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <utility>
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/bind.h"
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/location.h"
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/macros.h"
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/memory/ptr_util.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/single_thread_task_runner.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/stl_util.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/threading/thread_task_runner_handle.h"
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/associated_group.h"
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace internal {
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// InterfaceEndpoint stores the information of an interface endpoint registered
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// with the router.
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// No one other than the router's |endpoints_| and |tasks_| should hold refs to
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// this object.
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass MultiplexRouter::InterfaceEndpoint
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : public base::RefCounted<InterfaceEndpoint>,
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      public InterfaceEndpointController {
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez public:
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint(MultiplexRouter* router, InterfaceId id)
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      : router_(router),
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        id_(id),
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        closed_(false),
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        peer_closed_(false),
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        client_(nullptr),
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        event_signalled_(false) {}
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following public methods are safe to call from any threads without
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // locking.
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceId id() const { return id_; }
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following public methods are called under the router's lock.
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool closed() const { return closed_; }
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void set_closed() {
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    closed_ = true;
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool peer_closed() const { return peer_closed_; }
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void set_peer_closed() {
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    peer_closed_ = true;
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::SingleThreadTaskRunner* task_runner() const {
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return task_runner_.get();
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpointClient* client() const { return client_; }
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void AttachClient(InterfaceEndpointClient* client,
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    scoped_refptr<base::SingleThreadTaskRunner> runner) {
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!client_);
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!closed_);
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(runner->BelongsToCurrentThread());
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    task_runner_ = std::move(runner);
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    client_ = client;
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // This method must be called on the same thread as the corresponding
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // AttachClient() call.
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void DetachClient() {
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(client_);
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!closed_);
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    task_runner_ = nullptr;
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    client_ = nullptr;
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sync_watcher_.reset();
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void SignalSyncMessageEvent() {
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (event_signalled_)
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return;
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EnsureEventMessagePipeExists();
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    event_signalled_ = true;
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MojoResult result =
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        WriteMessageRaw(sync_message_event_sender_.get(), nullptr, 0, nullptr,
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        0, MOJO_WRITE_MESSAGE_FLAG_NONE);
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(MOJO_RESULT_OK, result);
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following public methods (i.e., InterfaceEndpointController
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // implementation) are called by the client on the same thread as the
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // AttachClient() call. They are called outside of the router's lock.
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool SendMessage(Message* message) override {
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    message->set_interface_id(id_);
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return router_->connector_.Accept(message);
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void AllowWokenUpBySyncWatchOnSameThread() override {
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EnsureSyncWatcherExists();
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sync_watcher_->AllowWokenUpBySyncWatchOnSameThread();
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool SyncWatch(const bool* should_stop) override {
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EnsureSyncWatcherExists();
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return sync_watcher_->SyncWatch(should_stop);
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez private:
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  friend class base::RefCounted<InterfaceEndpoint>;
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ~InterfaceEndpoint() override {
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!client_);
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(closed_);
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(peer_closed_);
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!sync_watcher_);
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void OnHandleReady(MojoResult result) {
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    scoped_refptr<InterfaceEndpoint> self_protector(this);
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    scoped_refptr<MultiplexRouter> router_protector(router_);
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Because we never close |sync_message_event_{sender,receiver}_| before
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // destruction or set a deadline, |result| should always be MOJO_RESULT_OK.
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(MOJO_RESULT_OK, result);
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool reset_sync_watcher = false;
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    {
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::AutoLock locker(router_->lock_);
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (!more_to_process)
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ResetSyncMessageSignal();
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // Currently there are no queued sync messages and the peer has closed so
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // there won't be incoming sync messages in the future.
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      reset_sync_watcher = !more_to_process && peer_closed_;
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (reset_sync_watcher) {
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // If a SyncWatch() call (or multiple ones) of this interface endpoint is
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // on the call stack, resetting the sync watcher will allow it to exit
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // when the call stack unwinds to that frame.
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      sync_watcher_.reset();
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void EnsureSyncWatcherExists() {
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->BelongsToCurrentThread());
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (sync_watcher_)
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return;
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    {
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::AutoLock locker(router_->lock_);
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      EnsureEventMessagePipeExists();
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      auto iter = router_->sync_message_tasks_.find(id_);
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (iter != router_->sync_message_tasks_.end() && !iter->second.empty())
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        SignalSyncMessageEvent();
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sync_watcher_.reset(new SyncHandleWatcher(
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        sync_message_event_receiver_.get(), MOJO_HANDLE_SIGNAL_READABLE,
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        base::Bind(&InterfaceEndpoint::OnHandleReady, base::Unretained(this))));
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void EnsureEventMessagePipeExists() {
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (sync_message_event_receiver_.is_valid())
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return;
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MojoResult result = CreateMessagePipe(nullptr, &sync_message_event_sender_,
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                          &sync_message_event_receiver_);
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(MOJO_RESULT_OK, result);
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void ResetSyncMessageSignal() {
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    router_->lock_.AssertAcquired();
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!event_signalled_)
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return;
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(sync_message_event_receiver_.is_valid());
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MojoResult result = ReadMessageRaw(sync_message_event_receiver_.get(),
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                       nullptr, nullptr, nullptr, nullptr,
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                       MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(MOJO_RESULT_OK, result);
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    event_signalled_ = false;
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following members are safe to access from any threads.
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MultiplexRouter* const router_;
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const InterfaceId id_;
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following members are accessed under the router's lock.
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Whether the endpoint has been closed.
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool closed_;
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Whether the peer endpoint has been closed.
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool peer_closed_;
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The task runner on which |client_|'s methods can be called.
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Not owned. It is null if no client is attached to this endpoint.
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpointClient* client_;
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // A message pipe used as an event to signal that sync messages are available.
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The message pipe handles are initialized under the router's lock and remain
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // unchanged afterwards. They may be accessed outside of the router's lock
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // later.
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ScopedMessagePipeHandle sync_message_event_sender_;
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ScopedMessagePipeHandle sync_message_event_receiver_;
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool event_signalled_;
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // ---------------------------------------------------------------------------
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The following members are only valid while a client is attached. They are
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // used exclusively on the client's thread. They may be accessed outside of
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // the router's lock.
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::unique_ptr<SyncHandleWatcher> sync_watcher_;
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint);
251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct MultiplexRouter::Task {
254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez public:
255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Doesn't take ownership of |message| but takes its contents.
256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static std::unique_ptr<Task> CreateMessageTask(Message* message) {
257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Task* task = new Task(MESSAGE);
258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    task->message.reset(new Message);
259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    message->MoveTo(task->message.get());
260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return base::WrapUnique(task);
261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  static std::unique_ptr<Task> CreateNotifyErrorTask(
263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      InterfaceEndpoint* endpoint) {
264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Task* task = new Task(NOTIFY_ERROR);
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    task->endpoint_to_notify = endpoint;
266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return base::WrapUnique(task);
267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ~Task() {}
270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool IsMessageTask() const { return type == MESSAGE; }
272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool IsNotifyErrorTask() const { return type == NOTIFY_ERROR; }
273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::unique_ptr<Message> message;
275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<InterfaceEndpoint> endpoint_to_notify;
276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  enum Type { MESSAGE, NOTIFY_ERROR };
278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  Type type;
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez private:
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  explicit Task(Type in_type) : type(in_type) {}
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMultiplexRouter::MultiplexRouter(
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool set_interface_id_namesapce_bit,
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ScopedMessagePipeHandle message_pipe,
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    scoped_refptr<base::SingleThreadTaskRunner> runner)
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()),
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      set_interface_id_namespace_bit_(set_interface_id_namesapce_bit),
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      header_validator_(this),
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_(std::move(message_pipe),
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 Connector::MULTI_THREADED_SEND,
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 std::move(runner)),
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      control_message_handler_(this),
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      control_message_proxy_(&connector_),
296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      next_interface_id_value_(1),
297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      posted_to_process_tasks_(false),
298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      encountered_error_(false),
299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      testing_mode_(false) {
300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Always participate in sync handle watching, because even if it doesn't
301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // expect sync requests during sync handle watching, it may still need to
302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // dispatch messages to associated endpoints on a different thread.
303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.AllowWokenUpBySyncWatchOnSameThread();
304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_incoming_receiver(&header_validator_);
305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_connection_error_handler(
306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::Bind(&MultiplexRouter::OnPipeConnectionError,
307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 base::Unretained(this)));
308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMultiplexRouter::~MultiplexRouter() {
311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  sync_message_tasks_.clear();
314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  tasks_.clear();
315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceEndpoint* endpoint = iter->second.get();
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Increment the iterator before calling UpdateEndpointStateMayRemove()
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // because it may remove the corresponding value from the map.
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ++iter;
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(endpoint->closed());
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(endpoints_.empty());
327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::SetMasterInterfaceName(const std::string& name) {
330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  header_validator_.SetDescription(name + " [master] MessageHeaderValidator");
332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  control_message_handler_.SetDescription(
333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      name + " [master] PipeControlMessageHandler");
334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::CreateEndpointHandlePair(
337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ScopedInterfaceEndpointHandle* local_endpoint,
338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ScopedInterfaceEndpointHandle* remote_endpoint) {
339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t id = 0;
341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  do {
342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (next_interface_id_value_ >= kInterfaceIdNamespaceMask)
343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      next_interface_id_value_ = 1;
344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    id = next_interface_id_value_++;
345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (set_interface_id_namespace_bit_)
346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      id |= kInterfaceIdNamespaceMask;
347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } while (ContainsKey(endpoints_, id));
348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  endpoints_[id] = endpoint;
351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (encountered_error_)
352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true);
355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false);
356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezScopedInterfaceEndpointHandle MultiplexRouter::CreateLocalEndpointHandle(
359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceId id) {
360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!IsValidInterfaceId(id))
361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return ScopedInterfaceEndpointHandle();
362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool inserted = false;
365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (inserted) {
367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (encountered_error_)
368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
369645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else {
370645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // If the endpoint already exist, it is because we have received a
371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // notification that the peer endpoint has closed.
372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    CHECK(!endpoint->closed());
373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    CHECK(endpoint->peer_closed());
374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return CreateScopedInterfaceEndpointHandle(id, true);
376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::CloseEndpointHandle(InterfaceId id, bool is_local) {
379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!IsValidInterfaceId(id))
380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!is_local) {
385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(ContainsKey(endpoints_, id));
386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(!IsMasterInterfaceId(id));
387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We will receive a NotifyPeerEndpointClosed message from the other side.
389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    control_message_proxy_.NotifyEndpointClosedBeforeSent(id);
390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(ContainsKey(endpoints_, id));
395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = endpoints_[id].get();
396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!endpoint->client());
397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!endpoint->closed());
398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!IsMasterInterfaceId(id))
401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    control_message_proxy_.NotifyPeerEndpointClosed(id);
402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezInterfaceEndpointController* MultiplexRouter::AttachEndpointClient(
407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const ScopedInterfaceEndpointHandle& handle,
408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceEndpointClient* client,
409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    scoped_refptr<base::SingleThreadTaskRunner> runner) {
410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const InterfaceId id = handle.id();
411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(IsValidInterfaceId(id));
413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(client);
414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(ContainsKey(endpoints_, id));
417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = endpoints_[id].get();
419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  endpoint->AttachClient(client, std::move(runner));
420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (endpoint->peer_closed())
422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    tasks_.push_back(Task::CreateNotifyErrorTask(endpoint));
423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ProcessTasks(NO_DIRECT_CLIENT_CALLS, nullptr);
424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return endpoint;
426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::DetachEndpointClient(
429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const ScopedInterfaceEndpointHandle& handle) {
430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const InterfaceId id = handle.id();
431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(IsValidInterfaceId(id));
433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(ContainsKey(endpoints_, id));
436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = endpoints_[id].get();
438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  endpoint->DetachClient();
439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::RaiseError() {
442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (task_runner_->BelongsToCurrentThread()) {
443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    connector_.RaiseError();
444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else {
445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    task_runner_->PostTask(FROM_HERE,
446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                           base::Bind(&MultiplexRouter::RaiseError, this));
447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
449645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
450645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::CloseMessagePipe() {
451645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
452645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.CloseMessagePipe();
453645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // CloseMessagePipe() above won't trigger connection error handler.
454645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Explicitly call OnPipeConnectionError() so that associated endpoints will
455645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // get notified.
456645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  OnPipeConnectionError();
457645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
458645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
459645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::HasAssociatedEndpoints() const {
460645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
461645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
462645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
463645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (endpoints_.size() > 1)
464645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
465645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (endpoints_.size() == 0)
466645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
467645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
468645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return !ContainsKey(endpoints_, kMasterInterfaceId);
469645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
470645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
471645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::EnableTestingMode() {
472645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
473645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
474645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
475645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  testing_mode_ = true;
476645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_enforce_errors_from_incoming_receiver(false);
477645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
478645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
479645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::Accept(Message* message) {
480645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
481645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
482645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<MultiplexRouter> protector(this);
483645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
484645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
485645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ClientCallBehavior client_call_behavior =
486645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_.during_sync_handle_watcher_callback()
487645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          ? ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES
488645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          : ALLOW_DIRECT_CLIENT_CALLS;
489645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
490645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool processed =
491645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      tasks_.empty() && ProcessIncomingMessage(message, client_call_behavior,
492645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                               connector_.task_runner());
493645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
494645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!processed) {
495645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Either the task queue is not empty or we cannot process the message
496645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // directly. In both cases, there is no need to call ProcessTasks().
497645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    tasks_.push_back(Task::CreateMessageTask(message));
498645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Task* task = tasks_.back().get();
499645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
500645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (task->message->has_flag(Message::kFlagIsSync)) {
501645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      InterfaceId id = task->message->interface_id();
502645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      sync_message_tasks_[id].push_back(task);
503645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      auto iter = endpoints_.find(id);
504645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (iter != endpoints_.end())
505645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        iter->second->SignalSyncMessageEvent();
506645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
507645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else if (!tasks_.empty()) {
508645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Processing the message may result in new tasks (for error notification)
509645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // being added to the queue. In this case, we have to attempt to process the
510645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // tasks.
511645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ProcessTasks(client_call_behavior, connector_.task_runner());
512645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
513645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
514645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Always return true. If we see errors during message processing, we will
515645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // explicitly call Connector::RaiseError() to disconnect the message pipe.
516645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
517645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
518645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
519645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::OnPeerAssociatedEndpointClosed(InterfaceId id) {
520645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
521645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
522645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (IsMasterInterfaceId(id))
523645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
524645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
525645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
526645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
527645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // It is possible that this endpoint has been set as peer closed. That is
528645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // because when the message pipe is closed, all the endpoints are updated with
529645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // PEER_ENDPOINT_CLOSED. We continue to process remaining tasks in the queue,
530645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // as long as there are refs keeping the router alive. If there is a
531645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // PeerAssociatedEndpointClosedEvent control message in the queue, we will get
532645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // here and see that the endpoint has been marked as peer closed.
533645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!endpoint->peer_closed()) {
534645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (endpoint->client())
535645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      tasks_.push_back(Task::CreateNotifyErrorTask(endpoint));
536645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
537645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
538645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
539645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // No need to trigger a ProcessTasks() because it is already on the stack.
540645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
541645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
542645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
543645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
544645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::OnAssociatedEndpointClosedBeforeSent(InterfaceId id) {
545645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
546645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
547645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (IsMasterInterfaceId(id))
548645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
549645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
550645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, nullptr);
551645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!endpoint->closed());
552645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
553645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
554645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  control_message_proxy_.NotifyPeerEndpointClosed(id);
555645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
556645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
557645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
558645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
559645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::OnPipeConnectionError() {
560645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
561645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
562645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<MultiplexRouter> protector(this);
563645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
564645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
565645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  encountered_error_ = true;
566645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
567645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
568645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceEndpoint* endpoint = iter->second.get();
569645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Increment the iterator before calling UpdateEndpointStateMayRemove()
570645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // because it may remove the corresponding value from the map.
571645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ++iter;
572645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
573645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (endpoint->client())
574645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      tasks_.push_back(Task::CreateNotifyErrorTask(endpoint));
575645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
576645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED);
577645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
578645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
579645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ProcessTasks(connector_.during_sync_handle_watcher_callback()
580645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                   ? ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES
581645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                   : ALLOW_DIRECT_CLIENT_CALLS,
582645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez               connector_.task_runner());
583645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
584645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
585645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::ProcessTasks(
586645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ClientCallBehavior client_call_behavior,
587645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::SingleThreadTaskRunner* current_task_runner) {
588645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
589645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
590645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (posted_to_process_tasks_)
591645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
592645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
593645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  while (!tasks_.empty()) {
594645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    std::unique_ptr<Task> task(std::move(tasks_.front()));
595645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    tasks_.pop_front();
596645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
597645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceId id = kInvalidInterfaceId;
598645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool sync_message = task->IsMessageTask() && task->message &&
599645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        task->message->has_flag(Message::kFlagIsSync);
600645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (sync_message) {
601645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      id = task->message->interface_id();
602645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      auto& sync_message_queue = sync_message_tasks_[id];
603645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      DCHECK_EQ(task.get(), sync_message_queue.front());
604645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      sync_message_queue.pop_front();
605645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
606645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
607645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool processed =
608645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        task->IsNotifyErrorTask()
609645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            ? ProcessNotifyErrorTask(task.get(), client_call_behavior,
610645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                     current_task_runner)
611645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            : ProcessIncomingMessage(task->message.get(), client_call_behavior,
612645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                     current_task_runner);
613645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
614645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!processed) {
615645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (sync_message) {
616645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        auto& sync_message_queue = sync_message_tasks_[id];
617645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        sync_message_queue.push_front(task.get());
618645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
619645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      tasks_.push_front(std::move(task));
620645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
621645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else {
622645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (sync_message) {
623645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        auto iter = sync_message_tasks_.find(id);
624645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (iter != sync_message_tasks_.end() && iter->second.empty())
625645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          sync_message_tasks_.erase(iter);
626645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
627645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
628645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
629645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
630645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
631645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::ProcessFirstSyncMessageForEndpoint(InterfaceId id) {
632645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
633645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
634645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  auto iter = sync_message_tasks_.find(id);
635645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (iter == sync_message_tasks_.end())
636645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
637645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
638645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MultiplexRouter::Task* task = iter->second.front();
639645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  iter->second.pop_front();
640645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
641645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(task->IsMessageTask());
642645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::unique_ptr<Message> message(std::move(task->message));
643645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
644645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Note: after this call, |task| and  |iter| may be invalidated.
645645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool processed = ProcessIncomingMessage(
646645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      message.get(), ALLOW_DIRECT_CLIENT_CALLS_FOR_SYNC_MESSAGES, nullptr);
647645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(processed);
648645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
649645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  iter = sync_message_tasks_.find(id);
650645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (iter == sync_message_tasks_.end())
651645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
652645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
653645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (iter->second.empty()) {
654645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sync_message_tasks_.erase(iter);
655645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
656645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
657645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
658645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
659645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
660645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
661645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::ProcessNotifyErrorTask(
662645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Task* task,
663645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ClientCallBehavior client_call_behavior,
664645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::SingleThreadTaskRunner* current_task_runner) {
665645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
666645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
667645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = task->endpoint_to_notify.get();
668645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!endpoint->client())
669645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
670645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
671645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (client_call_behavior != ALLOW_DIRECT_CLIENT_CALLS ||
672645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      endpoint->task_runner() != current_task_runner) {
673645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MaybePostToProcessTasks(endpoint->task_runner());
674645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
675645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
676645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
677645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
678645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
679645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpointClient* client = endpoint->client();
680645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
681645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We must unlock before calling into |client| because it may call this
682645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // object within NotifyError(). Holding the lock will lead to deadlock.
683645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
684645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // It is safe to call into |client| without the lock. Because |client| is
685645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // always accessed on the same thread, including DetachEndpointClient().
686645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::AutoUnlock unlocker(lock_);
687645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    client->NotifyError();
688645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
689645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
690645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
691645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
692645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MultiplexRouter::ProcessIncomingMessage(
693645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Message* message,
694645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ClientCallBehavior client_call_behavior,
695645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::SingleThreadTaskRunner* current_task_runner) {
696645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!current_task_runner || current_task_runner->BelongsToCurrentThread());
697645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
698645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
699645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!message) {
700645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // This is a sync message and has been processed during sync handle
701645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // watching.
702645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
703645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
704645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
705645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (PipeControlMessageHandler::IsPipeControlMessage(message)) {
706645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!control_message_handler_.Accept(message))
707645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      RaiseErrorInNonTestingMode();
708645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
709645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
710645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
711645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceId id = message->interface_id();
712645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(IsValidInterfaceId(id));
713645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
714645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool inserted = false;
715645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint = FindOrInsertEndpoint(id, &inserted);
716645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (inserted) {
717645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Currently, it is legitimate to receive messages for an endpoint
718645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // that is not registered. For example, the endpoint is transferred in
719645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // a message that is discarded. Once we add support to specify all
720645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // enclosing endpoints in message header, we should be able to remove
721645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // this.
722645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UpdateEndpointStateMayRemove(endpoint, ENDPOINT_CLOSED);
723645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
724645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // It is also possible that this newly-inserted endpoint is the master
725645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // endpoint. When the master InterfacePtr/Binding goes away, the message
726645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // pipe is closed and we explicitly trigger a pipe connection error. The
727645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // error updates all the endpoints, including the master endpoint, with
728645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // PEER_ENDPOINT_CLOSED and removes the master endpoint from the
729645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // registration. We continue to process remaining tasks in the queue, as
730645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // long as there are refs keeping the router alive. If there are remaining
731645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // messages for the master endpoint, we will get here.
732645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!IsMasterInterfaceId(id))
733645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      control_message_proxy_.NotifyPeerEndpointClosed(id);
734645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
735645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
736645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
737645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (endpoint->closed())
738645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
739645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
740645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!endpoint->client()) {
741645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We need to wait until a client is attached in order to dispatch further
742645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // messages.
743645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
744645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
745645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
746645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool can_direct_call;
747645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (message->has_flag(Message::kFlagIsSync)) {
748645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    can_direct_call = client_call_behavior != NO_DIRECT_CLIENT_CALLS &&
749645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                      endpoint->task_runner()->BelongsToCurrentThread();
750645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else {
751645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    can_direct_call = client_call_behavior == ALLOW_DIRECT_CLIENT_CALLS &&
752645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                      endpoint->task_runner() == current_task_runner;
753645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
754645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
755645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!can_direct_call) {
756645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MaybePostToProcessTasks(endpoint->task_runner());
757645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
758645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
759645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
760645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(endpoint->task_runner()->BelongsToCurrentThread());
761645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
762645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpointClient* client = endpoint->client();
763645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool result = false;
764645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
765645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We must unlock before calling into |client| because it may call this
766645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // object within HandleIncomingMessage(). Holding the lock will lead to
767645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // deadlock.
768645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    //
769645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // It is safe to call into |client| without the lock. Because |client| is
770645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // always accessed on the same thread, including DetachEndpointClient().
771645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::AutoUnlock unlocker(lock_);
772645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result = client->HandleIncomingMessage(message);
773645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
774645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!result)
775645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    RaiseErrorInNonTestingMode();
776645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
777645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
778645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
779645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
780645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::MaybePostToProcessTasks(
781645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::SingleThreadTaskRunner* task_runner) {
782645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
783645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (posted_to_process_tasks_)
784645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
785645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
786645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  posted_to_process_tasks_ = true;
787645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  posted_to_task_runner_ = task_runner;
788645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  task_runner->PostTask(
789645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      FROM_HERE, base::Bind(&MultiplexRouter::LockAndCallProcessTasks, this));
790645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
791645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
792645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::LockAndCallProcessTasks() {
793645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // There is no need to hold a ref to this class in this case because this is
794645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // always called using base::Bind(), which holds a ref.
795645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock locker(lock_);
796645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  posted_to_process_tasks_ = false;
797645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<base::SingleThreadTaskRunner> runner(
798645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      std::move(posted_to_task_runner_));
799645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ProcessTasks(ALLOW_DIRECT_CLIENT_CALLS, runner.get());
800645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
801645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
802645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::UpdateEndpointStateMayRemove(
803645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceEndpoint* endpoint,
804645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EndpointStateUpdateType type) {
805645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  switch (type) {
806645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    case ENDPOINT_CLOSED:
807645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      endpoint->set_closed();
808645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
809645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    case PEER_ENDPOINT_CLOSED:
810645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      endpoint->set_peer_closed();
811645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // If the interface endpoint is performing a sync watch, this makes sure
812645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // it is notified and eventually exits the sync watch.
813645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      endpoint->SignalSyncMessageEvent();
814645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
815645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
816645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (endpoint->closed() && endpoint->peer_closed())
817645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    endpoints_.erase(endpoint->id());
818645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
819645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
820645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MultiplexRouter::RaiseErrorInNonTestingMode() {
821645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
822645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!testing_mode_)
823645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    RaiseError();
824645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
825645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
826645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMultiplexRouter::InterfaceEndpoint* MultiplexRouter::FindOrInsertEndpoint(
827645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    InterfaceId id,
828645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool* inserted) {
829645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  lock_.AssertAcquired();
830645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Either |inserted| is nullptr or it points to a boolean initialized as
831645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // false.
832645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!inserted || !*inserted);
833645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
834645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  auto iter = endpoints_.find(id);
835645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  InterfaceEndpoint* endpoint;
836645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (iter == endpoints_.end()) {
837645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    endpoint = new InterfaceEndpoint(this, id);
838645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    endpoints_[id] = endpoint;
839645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (inserted)
840645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      *inserted = true;
841645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else {
842645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    endpoint = iter->second.get();
843645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
844645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
845645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return endpoint;
846645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
847645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
848645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace internal
849645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
850