mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
162 lines
4.7 KiB
C++
162 lines
4.7 KiB
C++
// Copyright 2014 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "mojo/public/cpp/bindings/lib/router.h"
|
|
|
|
#include "mojo/public/cpp/environment/logging.h"
|
|
|
|
namespace mojo {
|
|
namespace internal {
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class ResponderThunk : public MessageReceiverWithStatus {
|
|
public:
|
|
explicit ResponderThunk(const SharedData<Router*>& router)
|
|
: router_(router), accept_was_invoked_(false) {}
|
|
~ResponderThunk() override {
|
|
if (!accept_was_invoked_) {
|
|
// The Mojo application handled a message that was expecting a response
|
|
// but did not send a response.
|
|
Router* router = router_.value();
|
|
if (router) {
|
|
// We close the pipe here as a way of signaling to the calling
|
|
// application that an error condition occurred. Without this the
|
|
// calling application would have no way of knowing it should stop
|
|
// waiting for a response.
|
|
router->CloseMessagePipe();
|
|
}
|
|
}
|
|
}
|
|
|
|
// MessageReceiver implementation:
|
|
bool Accept(Message* message) override {
|
|
accept_was_invoked_ = true;
|
|
MOJO_DCHECK(message->has_flag(kMessageIsResponse));
|
|
|
|
bool result = false;
|
|
|
|
Router* router = router_.value();
|
|
if (router)
|
|
result = router->Accept(message);
|
|
|
|
return result;
|
|
}
|
|
|
|
// MessageReceiverWithStatus implementation:
|
|
bool IsValid() override {
|
|
Router* router = router_.value();
|
|
return router && !router->encountered_error() && router->is_valid();
|
|
}
|
|
|
|
private:
|
|
SharedData<Router*> router_;
|
|
bool accept_was_invoked_;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router)
|
|
: router_(router) {
|
|
}
|
|
|
|
Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {
|
|
}
|
|
|
|
bool Router::HandleIncomingMessageThunk::Accept(Message* message) {
|
|
return router_->HandleIncomingMessage(message);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
Router::Router(ScopedMessagePipeHandle message_pipe,
|
|
FilterChain filters,
|
|
const MojoAsyncWaiter* waiter)
|
|
: thunk_(this),
|
|
filters_(filters.Pass()),
|
|
connector_(message_pipe.Pass(), waiter),
|
|
weak_self_(this),
|
|
incoming_receiver_(nullptr),
|
|
next_request_id_(0),
|
|
testing_mode_(false) {
|
|
filters_.SetSink(&thunk_);
|
|
connector_.set_incoming_receiver(filters_.GetHead());
|
|
}
|
|
|
|
Router::~Router() {
|
|
weak_self_.set_value(nullptr);
|
|
|
|
for (ResponderMap::const_iterator i = responders_.begin();
|
|
i != responders_.end();
|
|
++i) {
|
|
delete i->second;
|
|
}
|
|
}
|
|
|
|
bool Router::Accept(Message* message) {
|
|
MOJO_DCHECK(!message->has_flag(kMessageExpectsResponse));
|
|
return connector_.Accept(message);
|
|
}
|
|
|
|
bool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) {
|
|
MOJO_DCHECK(message->has_flag(kMessageExpectsResponse));
|
|
|
|
// Reserve 0 in case we want it to convey special meaning in the future.
|
|
uint64_t request_id = next_request_id_++;
|
|
if (request_id == 0)
|
|
request_id = next_request_id_++;
|
|
|
|
message->set_request_id(request_id);
|
|
if (!connector_.Accept(message))
|
|
return false;
|
|
|
|
// We assume ownership of |responder|.
|
|
responders_[request_id] = responder;
|
|
return true;
|
|
}
|
|
|
|
void Router::EnableTestingMode() {
|
|
testing_mode_ = true;
|
|
connector_.set_enforce_errors_from_incoming_receiver(false);
|
|
}
|
|
|
|
bool Router::HandleIncomingMessage(Message* message) {
|
|
if (message->has_flag(kMessageExpectsResponse)) {
|
|
if (incoming_receiver_) {
|
|
MessageReceiverWithStatus* responder = new ResponderThunk(weak_self_);
|
|
bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
|
|
if (!ok)
|
|
delete responder;
|
|
return ok;
|
|
}
|
|
|
|
// If we receive a request expecting a response when the client is not
|
|
// listening, then we have no choice but to tear down the pipe.
|
|
connector_.CloseMessagePipe();
|
|
} else if (message->has_flag(kMessageIsResponse)) {
|
|
uint64_t request_id = message->request_id();
|
|
ResponderMap::iterator it = responders_.find(request_id);
|
|
if (it == responders_.end()) {
|
|
MOJO_DCHECK(testing_mode_);
|
|
return false;
|
|
}
|
|
MessageReceiver* responder = it->second;
|
|
responders_.erase(it);
|
|
bool ok = responder->Accept(message);
|
|
delete responder;
|
|
return ok;
|
|
} else {
|
|
if (incoming_receiver_)
|
|
return incoming_receiver_->Accept(message);
|
|
// OK to drop message on the floor.
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
} // namespace internal
|
|
} // namespace mojo
|