Home | History | Annotate | Download | only in lib
      1 // Copyright 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
      7 
      8 #include <memory>
      9 #include <utility>
     10 
     11 #include "base/bind.h"
     12 #include "base/callback.h"
     13 #include "base/logging.h"
     14 #include "base/macros.h"
     15 #include "base/memory/ptr_util.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/single_thread_task_runner.h"
     18 #include "mojo/public/cpp/bindings/associated_group.h"
     19 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
     20 #include "mojo/public/cpp/bindings/interface_id.h"
     21 #include "mojo/public/cpp/bindings/interface_ptr.h"
     22 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
     23 #include "mojo/public/cpp/bindings/interface_request.h"
     24 #include "mojo/public/cpp/bindings/lib/filter_chain.h"
     25 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
     26 #include "mojo/public/cpp/bindings/lib/router.h"
     27 #include "mojo/public/cpp/bindings/message_header_validator.h"
     28 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
     29 #include "mojo/public/cpp/system/core.h"
     30 
     31 namespace mojo {
     32 namespace internal {
     33 
     34 template <typename Interface, bool use_multiplex_router>
     35 class BindingState;
     36 
     37 // Uses a single-threaded, dedicated router. If |Interface| doesn't have any
     38 // methods to pass associated interface pointers or requests, there won't be
     39 // multiple interfaces running on the underlying message pipe. In that case, we
     40 // can use this specialization to reduce cost.
     41 template <typename Interface>
     42 class BindingState<Interface, false> {
     43  public:
     44   explicit BindingState(Interface* impl) : impl_(impl) {
     45     stub_.set_sink(impl_);
     46   }
     47 
     48   ~BindingState() { Close(); }
     49 
     50   void Bind(ScopedMessagePipeHandle handle,
     51             scoped_refptr<base::SingleThreadTaskRunner> runner) {
     52     DCHECK(!router_);
     53     internal::FilterChain filters;
     54     filters.Append<MessageHeaderValidator>(Interface::Name_);
     55     filters.Append<typename Interface::RequestValidator_>();
     56 
     57     router_ =
     58         new internal::Router(std::move(handle), std::move(filters),
     59                              Interface::HasSyncMethods_, std::move(runner));
     60     router_->set_incoming_receiver(&stub_);
     61     router_->set_connection_error_handler(
     62         base::Bind(&BindingState::RunConnectionErrorHandler,
     63                    base::Unretained(this)));
     64   }
     65 
     66   bool HasAssociatedInterfaces() const { return false; }
     67 
     68   void PauseIncomingMethodCallProcessing() {
     69     DCHECK(router_);
     70     router_->PauseIncomingMethodCallProcessing();
     71   }
     72   void ResumeIncomingMethodCallProcessing() {
     73     DCHECK(router_);
     74     router_->ResumeIncomingMethodCallProcessing();
     75   }
     76 
     77   bool WaitForIncomingMethodCall(
     78       MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
     79     DCHECK(router_);
     80     return router_->WaitForIncomingMessage(deadline);
     81   }
     82 
     83   void Close() {
     84     if (!router_)
     85       return;
     86 
     87     router_->CloseMessagePipe();
     88     DestroyRouter();
     89   }
     90 
     91   InterfaceRequest<Interface> Unbind() {
     92     InterfaceRequest<Interface> request =
     93         MakeRequest<Interface>(router_->PassMessagePipe());
     94     DestroyRouter();
     95     return std::move(request);
     96   }
     97 
     98   void set_connection_error_handler(const base::Closure& error_handler) {
     99     DCHECK(is_bound());
    100     connection_error_handler_ = error_handler;
    101   }
    102 
    103   Interface* impl() { return impl_; }
    104 
    105   bool is_bound() const { return !!router_; }
    106 
    107   MessagePipeHandle handle() const {
    108     DCHECK(is_bound());
    109     return router_->handle();
    110   }
    111 
    112   AssociatedGroup* associated_group() { return nullptr; }
    113 
    114   void EnableTestingMode() {
    115     DCHECK(is_bound());
    116     router_->EnableTestingMode();
    117   }
    118 
    119  private:
    120   void DestroyRouter() {
    121     router_->set_connection_error_handler(base::Closure());
    122     delete router_;
    123     router_ = nullptr;
    124     connection_error_handler_.Reset();
    125   }
    126 
    127   void RunConnectionErrorHandler() {
    128     if (!connection_error_handler_.is_null())
    129       connection_error_handler_.Run();
    130   }
    131 
    132   internal::Router* router_ = nullptr;
    133   typename Interface::Stub_ stub_;
    134   Interface* impl_;
    135   base::Closure connection_error_handler_;
    136 
    137   DISALLOW_COPY_AND_ASSIGN(BindingState);
    138 };
    139 
    140 // Uses a multiplexing router. If |Interface| has methods to pass associated
    141 // interface pointers or requests, this specialization should be used.
    142 template <typename Interface>
    143 class BindingState<Interface, true> {
    144  public:
    145   explicit BindingState(Interface* impl) : impl_(impl) {
    146     stub_.set_sink(impl_);
    147   }
    148 
    149   ~BindingState() { Close(); }
    150 
    151   void Bind(ScopedMessagePipeHandle handle,
    152             scoped_refptr<base::SingleThreadTaskRunner> runner) {
    153     DCHECK(!router_);
    154 
    155     router_ = new internal::MultiplexRouter(false, std::move(handle), runner);
    156     router_->SetMasterInterfaceName(Interface::Name_);
    157     stub_.serialization_context()->group_controller = router_;
    158 
    159     endpoint_client_.reset(new InterfaceEndpointClient(
    160         router_->CreateLocalEndpointHandle(kMasterInterfaceId),
    161         &stub_, base::WrapUnique(new typename Interface::RequestValidator_()),
    162         Interface::HasSyncMethods_, std::move(runner)));
    163 
    164     endpoint_client_->set_connection_error_handler(
    165         base::Bind(&BindingState::RunConnectionErrorHandler,
    166                    base::Unretained(this)));
    167   }
    168 
    169   bool HasAssociatedInterfaces() const {
    170     return router_ ? router_->HasAssociatedEndpoints() : false;
    171   }
    172 
    173   void PauseIncomingMethodCallProcessing() {
    174     DCHECK(router_);
    175     router_->PauseIncomingMethodCallProcessing();
    176   }
    177   void ResumeIncomingMethodCallProcessing() {
    178     DCHECK(router_);
    179     router_->ResumeIncomingMethodCallProcessing();
    180   }
    181 
    182   bool WaitForIncomingMethodCall(
    183       MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE) {
    184     DCHECK(router_);
    185     return router_->WaitForIncomingMessage(deadline);
    186   }
    187 
    188   void Close() {
    189     if (!router_)
    190       return;
    191 
    192     endpoint_client_.reset();
    193     router_->CloseMessagePipe();
    194     router_ = nullptr;
    195     connection_error_handler_.Reset();
    196   }
    197 
    198   InterfaceRequest<Interface> Unbind() {
    199     endpoint_client_.reset();
    200     InterfaceRequest<Interface> request =
    201         MakeRequest<Interface>(router_->PassMessagePipe());
    202     router_ = nullptr;
    203     connection_error_handler_.Reset();
    204     return request;
    205   }
    206 
    207   void set_connection_error_handler(const base::Closure& error_handler) {
    208     DCHECK(is_bound());
    209     connection_error_handler_ = error_handler;
    210   }
    211 
    212   Interface* impl() { return impl_; }
    213 
    214   bool is_bound() const { return !!router_; }
    215 
    216   MessagePipeHandle handle() const {
    217     DCHECK(is_bound());
    218     return router_->handle();
    219   }
    220 
    221   AssociatedGroup* associated_group() {
    222     return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
    223   }
    224 
    225   void EnableTestingMode() {
    226     DCHECK(is_bound());
    227     router_->EnableTestingMode();
    228   }
    229 
    230  private:
    231   void RunConnectionErrorHandler() {
    232     if (!connection_error_handler_.is_null())
    233       connection_error_handler_.Run();
    234   }
    235 
    236   scoped_refptr<internal::MultiplexRouter> router_;
    237   std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
    238 
    239   typename Interface::Stub_ stub_;
    240   Interface* impl_;
    241   base::Closure connection_error_handler_;
    242 
    243   DISALLOW_COPY_AND_ASSIGN(BindingState);
    244 };
    245 
    246 }  // namesapce internal
    247 }  // namespace mojo
    248 
    249 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
    250