1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_PUBLIC_CPP_BINDINGS_REMOTE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_H_
#include <cstdint>
#include <tuple>
#include <utility>
#include "base/check.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/async_flusher.h"
#include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
#include "mojo/public/cpp/bindings/pending_flush.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/runtime_features.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
// A Remote is used to issue Interface method calls to a single connected
// Receiver or PendingReceiver. The Remote must be bound in order to issue those
// method calls, and it becomes bound by consuming a PendingRemote either at
// construction time or by calling |Bind()|.
//
// Remote is NOT thread- or sequence-safe and must be used on a single
// (but otherwise arbitrary) sequence. All bound Remote objects are associated
// with a base::SequenceTaskRunner which the Remote uses exclusively to schedule
// response callbacks and disconnection notifications.
//
// The most common ways to bind a Remote are to consume a PendingRemote received
// via some IPC, or to call |BindNewPipeAndPassReceiver()| and send the returned
// PendingReceiver somewhere useful (i.e., to a remote Receiver who will consume
// it). For example:
//
// mojo::Remote<mojom::Widget> widget;
// widget_factory->CreateWidget(widget.BindNewPipeAndPassReceiver());
// widget->Click();
//
// IMPORTANT: There are some things to be aware of regarding Interface method
// calls as they relate to Remote object lifetime:
//
// - Interface method calls issued immediately before the destruction of a
// Remote ARE guaranteed to be transmitted to the remote's receiver as long
// as the receiver itself remains alive, either as a Receiver or a
// PendingReceiver.
//
// - In the name of memory safety, Interface method response callbacks (and in
// general ANY tasks which can be scheduled by a Remote) will NEVER
// be dispatched beyond the lifetime of the Remote object. As such, if
// you make a call and you need its reply, you must keep the Remote alive
// until the reply is received.
template <typename Interface>
class Remote {
public:
using InterfaceType = Interface;
using PendingType = PendingRemote<Interface>;
// Constructs an unbound Remote. This object cannot issue Interface method
// calls and does not schedule any tasks.
Remote() = default;
Remote(Remote&& other) noexcept { *this = std::move(other); }
// Constructs a new Remote which is bound from |pending_remote| and which
// schedules response callbacks and disconnection notifications on the default
// SequencedTaskRunner (i.e., base::SequencedTaskRunner::GetCurrentDefault()
// at construction time).
explicit Remote(PendingRemote<Interface> pending_remote)
: Remote(std::move(pending_remote), nullptr) {}
// Constructs a new Remote which is bound from |pending_remote| and which
// schedules response callbacks and disconnection notifications on
// |task_runner|. |task_runner| must run tasks on the same sequence that owns
// this Remote.
Remote(PendingRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
Bind(std::move(pending_remote), std::move(task_runner));
}
Remote(const Remote&) = delete;
Remote& operator=(const Remote&) = delete;
~Remote() = default;
Remote& operator=(Remote&& other) noexcept {
internal_state_.Swap(&other.internal_state_);
return *this;
}
// Exposes access to callable Interface methods directed at this Remote's
// receiver. Must only be called on a bound Remote.
typename Interface::Proxy_* get() const {
DCHECK(is_bound())
<< "Cannot issue Interface method calls on an unbound Remote";
return internal_state_.instance();
}
// Shorthand form of |get()|. See above.
typename Interface::Proxy_* operator->() const { return get(); }
typename Interface::Proxy_& operator*() const { return *get(); }
// Indicates whether this Remote is bound and thus can issue Interface method
// calls via the above accessors.
//
// NOTE: The state of being "bound" should not be confused with the state of
// being "connected" (see |is_connected()| below). A Remote is NEVER passively
// unbound and the only way for it to become unbound is to explicitly call
// |reset()| or |Unbind()|. As such, unless you make explicit calls to those
// methods, it is always safe to assume that a Remote you've bound will remain
// bound and callable.
bool is_bound() const { return internal_state_.is_bound(); }
explicit operator bool() const { return is_bound(); }
// Indicates whether this Remote is connected to a receiver. Must only be
// called on a bound Remote. If this returns |true|, method calls made by this
// Remote may eventually end up at the connected receiver (though it's of
// course possible for this call to race with disconnection). If this returns
// |false| however, all future Interface method calls on this Remote will be
// silently dropped.
//
// A bound Remote becomes disconnected automatically either when its receiver
// is destroyed, or when it receives a malformed or otherwise unexpected
// response message from the receiver.
//
// NOTE: The state of being "bound" should not be confused with the state of
// being "connected". See |is_bound()| above.
bool is_connected() const {
DCHECK(is_bound());
return !internal_state_.encountered_error();
}
// Sets a Closure to be invoked if this Remote is cut off from its receiver.
// This can happen if the corresponding Receiver (or unconsumed
// PendingReceiver) is destroyed, or if the Receiver sends a malformed or
// otherwise unexpected response message to this Remote. Must only be called
// on a bound Remote object, and only remains set as long as the Remote is
// both bound and connected.
//
// If invoked at all, |handler| will be scheduled asynchronously using the
// Remote's bound SequencedTaskRunner.
void set_disconnect_handler(base::OnceClosure handler) {
if (is_connected())
internal_state_.set_connection_error_handler(std::move(handler));
}
// Like above but also receives extra user-defined metadata about why the
// receiving endpoint was closed.
void set_disconnect_with_reason_handler(
ConnectionErrorWithReasonCallback handler) {
internal_state_.set_connection_error_with_reason_handler(
std::move(handler));
}
// A convenient helper that resets this Remote on disconnect. Note that this
// replaces any previously set disconnection handler. Must be called on a
// bound Remote object. If the Remote is connected, a callback is set to reset
// it after it is disconnected. If Remote is bound but disconnected then reset
// is called immediately.
void reset_on_disconnect() {
if (!is_connected()) {
reset();
return;
}
set_disconnect_handler(
base::BindOnce(&Remote::reset, base::Unretained(this)));
}
// Sets a Closure to be invoked any time the receiving endpoint reports itself
// as idle and there are no in-flight messages it has yet to acknowledge, and
// this state occurs continuously for a duration of at least |timeout|. The
// first time this is called, it must be called BEFORE sending any interface
// messages to the receiver. It may be called any number of times after that
// to reconfigure the idle timeout period or assign a new idle handler.
//
// Once called, the interface connection incurs some permanent additional
// per-message overhead to help track idle state across the interface
// boundary.
//
// Whenever this callback is invoked, the following conditions are guaranteed
// to hold:
//
// - There are no messages sent on this Remote that have not already been
// dispatched by the receiver.
// - There are no interfaces which were bound directly or transitively
// through this Remote and are still connected.
// - The receiver has explicitly notified us that it considers itself to be
// "idle."
// - The receiver has not dispatched any additional messages since sending
// this idle notification.
// - The Remote does not have any outstanding reply callbacks that haven't
// been called yet.
// - All of the above has been true continuously for a duration of at least
// |timeout|.
//
void set_idle_handler(base::TimeDelta timeout,
base::RepeatingClosure handler) {
internal_state_.set_idle_handler(timeout, std::move(handler));
}
// A convenient helper for common idle timeout behavior. This is equivalent to
// calling |set_idle_handler| with a handler that only resets this Remote.
void reset_on_idle_timeout(base::TimeDelta timeout) {
set_idle_handler(
timeout, base::BindRepeating(&Remote::reset, base::Unretained(this)));
}
// Resets this Remote to an unbound state. To reset the Remote and recover an
// PendingRemote that can be bound again later, use |Unbind()| instead.
void reset() {
State doomed_state;
internal_state_.Swap(&doomed_state);
}
// Similar to the method above, but also specifies a disconnect reason.
void ResetWithReason(uint32_t custom_reason, const std::string& description) {
if (internal_state_.is_bound())
internal_state_.CloseWithReason(custom_reason, description);
reset();
}
// Returns the version of Interface used by this Remote. Defaults to 0 but can
// be adjusted either at binding time, or by invoking either |QueryVersion()|
// or |RequireVersion()|.
uint32_t version() const { return internal_state_.version(); }
// Binds this Remote, connecting it to a new PendingReceiver which is
// returned for transmission to some Receiver which can bind it. The Remote
// will schedule any response callbacks or disconnection notifications on the
// default SequencedTaskRunner (i.e.
// base::SequencedTaskRunner::GetCurrentDefault() at the time of this call).
// Must only be called on an unbound Remote.
[[nodiscard]] PendingReceiver<Interface> BindNewPipeAndPassReceiver() {
DCHECK(!is_bound()) << "Remote for " << Interface::Name_
<< " is already bound";
return BindNewPipeAndPassReceiver(nullptr);
}
// Like above, but the Remote will schedule response callbacks and
// disconnection notifications on |task_runner| instead of the default
// SequencedTaskRunner. |task_runner| must run tasks on the same sequence that
// owns this Remote.
[[nodiscard]] PendingReceiver<Interface> BindNewPipeAndPassReceiver(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
DCHECK(!is_bound()) << "Remote for " << Interface::Name_
<< " is already bound";
if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
reset();
return PendingReceiver<Interface>();
}
MessagePipe pipe;
Bind(PendingRemote<Interface>(std::move(pipe.handle0), 0),
std::move(task_runner));
return PendingReceiver<Interface>(std::move(pipe.handle1));
}
// Binds this Remote by consuming |pending_remote|, which must be valid. The
// Remote will schedule any response callbacks or disconnection notifications
// on the default SequencedTaskRunner (i.e.
// base::SequencedTaskRunner::GetCurrentDefault() at the time of this call).
// Must only be called on an unbound Remote.
void Bind(PendingRemote<Interface> pending_remote) {
DCHECK(!is_bound()) << "Remote for " << Interface::Name_
<< " is already bound";
DCHECK(pending_remote.is_valid());
Bind(std::move(pending_remote), nullptr);
}
// Like above, but the Remote will schedule response callbacks and
// disconnection notifications on |task_runner| instead of the default
// SequencedTaskRunner. Must only be called on an unbound Remote.
// |task_runner| must run tasks on the same sequence that owns this Remote.
void Bind(PendingRemote<Interface> pending_remote,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
DCHECK(!is_bound()) << "Remote for " << Interface::Name_
<< " is already bound";
if (!pending_remote) {
reset();
return;
}
if (!internal::GetRuntimeFeature_ExpectEnabled<Interface>()) {
reset();
return;
}
internal_state_.Bind(pending_remote.internal_state(),
std::move(task_runner));
// Force the internal state to configure its proxy. Unlike InterfacePtr we
// do not use Remote in transit, so binding to a pipe handle can also imply
// binding to a SequencedTaskRunner and observing pipe handle state. This
// allows for e.g. |is_connected()| to be a more reliable API than
// |InterfacePtr::encountered_error()|.
std::ignore = internal_state_.instance();
}
// Unbinds this Remote, rendering it unable to issue further Interface method
// calls. Returns a PendingRemote which may be passed across threads or
// processes and consumed by another Remote elsewhere.
//
// Note that it is an error (the bad, crashy kind of error) to attempt to
// |Unbind()| a Remote which is awaiting one or more responses to previously
// issued Interface method calls. Calling this method should only be
// considered in cases where satisfaction of that constraint can be proven.
//
// Must only be called on a bound Remote.
[[nodiscard]] PendingRemote<Interface> Unbind() {
DCHECK(is_bound());
CHECK(!internal_state_.has_pending_callbacks());
State state;
internal_state_.Swap(&state);
internal::PendingRemoteState pending_state = state.Unbind();
return PendingRemote<Interface>(std::move(pending_state.pipe),
pending_state.version);
}
// Queries the max version that the receiving endpoint supports. Once a
// response is received, |callback| will be invoked with the version number
// and the version number of this Remote object will also be updated.
void QueryVersion(base::OnceCallback<void(uint32_t)> callback) {
internal_state_.QueryVersion(std::move(callback));
}
// Requires the receiving endpoint to support at least the specified
// |version|. If it does not, it will close its end of the connection
// immediately.
void RequireVersion(uint32_t version) {
internal_state_.RequireVersion(version);
}
// Pauses the receiving endpoint until the flush corresponding to |flush| has
// completed. Any calls made on this Remote prior to this call will be
// dispatched at the receiving endpoint before pausing. The endpoint will not
// dispatch any subsequent calls until the flush operation corresponding to
// |flush| has been completed or canceled.
//
// See documentation for |FlushAsync()| on Remote and Receiver for how to
// acquire a PendingFlush object, and documentation on PendingFlush for
// example usage.
void PauseReceiverUntilFlushCompletes(PendingFlush flush) {
internal_state_.PauseReceiverUntilFlushCompletes(std::move(flush));
}
// Flushes the receiving endpoint asynchronously using |flusher|. Once all
// calls made on this Remote prior to this |FlushAsyncWithFlusher()| call have
// dispatched at the receiving endpoint, |flusher| will signal its
// corresponding PendingFlush, unblocking any endpoint waiting on the flush
// operation.
//
// NOTE: It is more common to use |FlushAsync()| defined below. If you really
// want to provide your own AsyncFlusher using this method, see the
// single-arugment constructor on PendingFlush. This would typically be used
// when code executing on the current sequence wishes to immediately pause
// one of its remote endpoints to wait on a flush operation that needs to be
// initiated on a separate sequence. Rather than bouncing to the second
// sequence to initiate a flush and then passing a PendingFlush back to the
// original sequence, the AsyncFlusher/PendingFlush can be created on the
// original sequence and a single task can be posted to pass the AsyncFlusher
// to the second sequence for use with this method.
void FlushAsyncWithFlusher(AsyncFlusher flusher) {
internal_state_.FlushAsync(std::move(flusher));
}
// Same as above but an AsyncFlusher/PendingFlush pair is created on the
// caller's behalf. The AsyncFlusher is immediately passed to a
// |FlushAsyncWithFlusher()| call on this object, while the PendingFlush is
// returned for use by the caller. See documentation on PendingFlush for
// example usage.
PendingFlush FlushAsync() {
AsyncFlusher flusher;
PendingFlush flush(&flusher);
FlushAsyncWithFlusher(std::move(flusher));
return flush;
}
// Sends a no-op message on the underlying message pipe and runs the current
// message loop until its response is received. This can be used in tests to
// verify that no message was sent on a message pipe in response to some
// stimulus.
void FlushForTesting() { internal_state_.FlushForTesting(); }
// Same as |FlushForTesting()| but will call |callback| when the flush is
// complete.
void FlushAsyncForTesting(base::OnceClosure callback) {
internal_state_.FlushAsyncForTesting(std::move(callback));
}
// Returns the number of unacknowledged messages sent by this Remote. Only
// non-zero when |set_idle_handler()| has been called.
unsigned int GetNumUnackedMessagesForTesting() const {
return internal_state_.GetNumUnackedMessagesForTesting();
}
// DO NOT USE. Exposed only for internal use and for testing.
internal::InterfacePtrState<Interface>* internal_state() {
return &internal_state_;
}
private:
using State = internal::InterfacePtrState<Interface>;
mutable State internal_state_;
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_H_
|