1 // Copyright 2019 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 SERVICES_SERVICE_MANAGER_PUBLIC_CPP_BINDER_MAP_H_ 6 #define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_BINDER_MAP_H_ 7 8 #include <map> 9 #include <memory> 10 #include <string> 11 #include <type_traits> 12 #include <utility> 13 14 #include "base/callback.h" 15 #include "base/macros.h" 16 #include "base/memory/weak_ptr.h" 17 #include "mojo/public/cpp/system/message_pipe.h" 18 #include "services/service_manager/public/cpp/binder_map_internal.h" 19 20 namespace service_manager { 21 22 // Helper class which maps interface names to callbacks that know how to bind 23 // receivers of the corresponding interface type. This is useful for services 24 // which may bind many different types of interface receivers throughout their 25 // lifetime, given the generic name + receiver pipe handle inputs provided by 26 // an incoming |Service::OnConnect| message. 27 // 28 // New binders can be registered in the map by calling |Add()|. To handle an 29 // incoming request to bind a receiver, the owner of this BinderMap should call 30 // |TryBind()| with the given name and receiver pipe. If a suitable binder 31 // callback is registered in the map, it will be run with the receiver passed 32 // in. 33 // 34 // If a non-void ContextType is specified, registered callbacks must accept an 35 // additional ContextType argument, and each invocation of |TryBind()| must 36 // provide such a value. 37 // 38 // NOTE: Most common uses of BinderMapWithContext do not require a context value 39 // per bind request. Use the BinderMap alias defined below this class in such 40 // cases. 41 template <typename ContextType> 42 class BinderMapWithContext { 43 public: 44 using Traits = internal::BinderContextTraits<ContextType>; 45 using ContextValueType = typename Traits::ValueType; 46 using GenericBinderType = typename Traits::GenericBinderType; 47 48 template <typename Interface> 49 using BinderType = typename Traits::template BinderType<Interface>; 50 51 BinderMapWithContext() = default; 52 ~BinderMapWithContext() = default; 53 54 // Adds a new binder specifically for Interface receivers. This exists for the 55 // convenience of being able to register strongly-typed binding methods like: 56 // 57 // void OnBindFoo(mojo::PendingReceiver<Foo> receiver) { ... } 58 // 59 // more easily. 60 template <typename Interface> 61 void Add(BinderType<Interface> binder, 62 scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) { 63 binders_[Interface::Name_] = std::make_unique< 64 internal::GenericCallbackBinderWithContext<ContextType>>( 65 Traits::MakeGenericBinder(std::move(binder)), std::move(task_runner)); 66 } 67 68 // Passes |*receiver_pipe| to a registered binder for |interface_name| if any 69 // exists. Returns |true| if successful, or |false| if no binder is registered 70 // for the given interface. Upon returning |false|, |*receiver_pipe| is left 71 // intact for the caller. Only usable when ContextType is void. TryBind(const std::string & interface_name,mojo::ScopedMessagePipeHandle * receiver_pipe)72 bool TryBind(const std::string& interface_name, 73 mojo::ScopedMessagePipeHandle* receiver_pipe) { 74 static_assert(std::is_same<ContextType, void>::value, 75 "TryBind() must be called with a context value when " 76 "ContextType is non-void."); 77 auto it = binders_.find(interface_name); 78 if (it == binders_.end()) 79 return false; 80 81 it->second->BindInterface(std::move(*receiver_pipe)); 82 return true; 83 } 84 85 // Like above, but passes |context| to the binder if one exists. Only usable 86 // when ContextType is non-void. TryBind(ContextValueType context,const std::string & interface_name,mojo::ScopedMessagePipeHandle * receiver_pipe)87 bool TryBind(ContextValueType context, 88 const std::string& interface_name, 89 mojo::ScopedMessagePipeHandle* receiver_pipe) { 90 static_assert(!std::is_same<ContextType, void>::value, 91 "TryBind() must be called without a context value when " 92 "ContextType is void."); 93 auto it = binders_.find(interface_name); 94 if (it == binders_.end()) 95 return false; 96 97 it->second->BindInterface(std::move(context), std::move(*receiver_pipe)); 98 return true; 99 } 100 101 // Clears all registered binders from this map. Clear()102 void Clear() { binders_.clear(); } 103 104 private: 105 std::map< 106 std::string, 107 std::unique_ptr<internal::GenericCallbackBinderWithContext<ContextType>>> 108 binders_; 109 110 DISALLOW_COPY_AND_ASSIGN(BinderMapWithContext); 111 }; 112 113 // Common alias for BinderMapWithContext that has no context. Binders added to 114 // this type of map will only take a single PendingReceiver<T> argument (or a 115 // generic name+pipe combo). 116 using BinderMap = BinderMapWithContext<void>; 117 118 } // namespace service_manager 119 120 #endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_BINDER_MAP_H_ 121