1 // Copyright 2016 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_STRONG_ASSOCIATED_BINDING_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_
7
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "mojo/public/cpp/bindings/associated_binding.h"
18 #include "mojo/public/cpp/bindings/associated_interface_request.h"
19 #include "mojo/public/cpp/bindings/connection_error_callback.h"
20 #include "mojo/public/cpp/system/core.h"
21
22 namespace mojo {
23
24 template <typename Interface>
25 class StrongAssociatedBinding;
26
27 template <typename Interface>
28 using StrongAssociatedBindingPtr =
29 base::WeakPtr<StrongAssociatedBinding<Interface>>;
30
31 // This connects an interface implementation strongly to an associated pipe.
32 // When a connection error is detected the implementation is deleted. If the
33 // task runner that a StrongAssociatedBinding is bound on is stopped, the
34 // connection error handler will not be invoked and the implementation will not
35 // be deleted.
36 //
37 // To use, call StrongAssociatedBinding<T>::Create() (see below) or the helper
38 // MakeStrongAssociatedBinding function:
39 //
40 // mojo::MakeStrongAssociatedBinding(std::make_unique<FooImpl>(),
41 // std::move(foo_request));
42 //
43 template <typename Interface>
44 class StrongAssociatedBinding {
45 public:
46 using ImplPointerType =
47 typename AssociatedBinding<Interface>::ImplPointerType;
48
49 // Create a new StrongAssociatedBinding instance. The instance owns itself,
50 // cleaning up only in the event of a pipe connection error. Returns a WeakPtr
51 // to the new StrongAssociatedBinding instance.
Create(std::unique_ptr<Interface> impl,AssociatedInterfaceRequest<Interface> request)52 static StrongAssociatedBindingPtr<Interface> Create(
53 std::unique_ptr<Interface> impl,
54 AssociatedInterfaceRequest<Interface> request) {
55 StrongAssociatedBinding* binding =
56 new StrongAssociatedBinding(std::move(impl), std::move(request));
57 return binding->weak_factory_.GetWeakPtr();
58 }
59
60 // Note: The error handler must not delete the interface implementation.
61 //
62 // This method may only be called after this StrongAssociatedBinding has been
63 // bound to a message pipe.
set_connection_error_handler(base::OnceClosure error_handler)64 void set_connection_error_handler(base::OnceClosure error_handler) {
65 DCHECK(binding_.is_bound());
66 connection_error_handler_ = std::move(error_handler);
67 connection_error_with_reason_handler_.Reset();
68 }
69
set_connection_error_with_reason_handler(ConnectionErrorWithReasonCallback error_handler)70 void set_connection_error_with_reason_handler(
71 ConnectionErrorWithReasonCallback error_handler) {
72 DCHECK(binding_.is_bound());
73 connection_error_with_reason_handler_ = std::move(error_handler);
74 connection_error_handler_.Reset();
75 }
76
77 // Forces the binding to close. This destroys the StrongBinding instance.
Close()78 void Close() { delete this; }
79
impl()80 Interface* impl() { return impl_.get(); }
81
82 // Sends a message on the underlying message pipe and runs the current
83 // message loop until its response is received. This can be used in tests to
84 // verify that no message was sent on a message pipe in response to some
85 // stimulus.
FlushForTesting()86 void FlushForTesting() { binding_.FlushForTesting(); }
87
88 // Allows test code to swap the interface implementation.
SwapImplForTesting(ImplPointerType new_impl)89 ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
90 return binding_.SwapImplForTesting(new_impl);
91 }
92
93 private:
StrongAssociatedBinding(std::unique_ptr<Interface> impl,AssociatedInterfaceRequest<Interface> request)94 StrongAssociatedBinding(std::unique_ptr<Interface> impl,
95 AssociatedInterfaceRequest<Interface> request)
96 : impl_(std::move(impl)),
97 binding_(impl_.get(), std::move(request)),
98 weak_factory_(this) {
99 binding_.set_connection_error_with_reason_handler(base::Bind(
100 &StrongAssociatedBinding::OnConnectionError, base::Unretained(this)));
101 }
102
~StrongAssociatedBinding()103 ~StrongAssociatedBinding() {}
104
OnConnectionError(uint32_t custom_reason,const std::string & description)105 void OnConnectionError(uint32_t custom_reason,
106 const std::string& description) {
107 if (connection_error_handler_) {
108 std::move(connection_error_handler_).Run();
109 } else if (connection_error_with_reason_handler_) {
110 std::move(connection_error_with_reason_handler_)
111 .Run(custom_reason, description);
112 }
113 Close();
114 }
115
116 std::unique_ptr<Interface> impl_;
117 base::OnceClosure connection_error_handler_;
118 ConnectionErrorWithReasonCallback connection_error_with_reason_handler_;
119 AssociatedBinding<Interface> binding_;
120 base::WeakPtrFactory<StrongAssociatedBinding> weak_factory_;
121
122 DISALLOW_COPY_AND_ASSIGN(StrongAssociatedBinding);
123 };
124
125 template <typename Interface, typename Impl>
MakeStrongAssociatedBinding(std::unique_ptr<Impl> impl,AssociatedInterfaceRequest<Interface> request)126 StrongAssociatedBindingPtr<Interface> MakeStrongAssociatedBinding(
127 std::unique_ptr<Impl> impl,
128 AssociatedInterfaceRequest<Interface> request) {
129 return StrongAssociatedBinding<Interface>::Create(std::move(impl),
130 std::move(request));
131 }
132
133 } // namespace mojo
134
135 #endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_
136