OLD | NEW |
| (Empty) |
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 #include "services/service_manager/public/cpp/interface_registry.h" | |
6 | |
7 #include <iterator> | |
8 #include <sstream> | |
9 | |
10 #include "base/memory/ptr_util.h" | |
11 #include "mojo/public/cpp/bindings/message.h" | |
12 | |
13 namespace service_manager { | |
14 namespace { | |
15 | |
16 void SerializeIdentity(const Identity& identity, std::stringstream* stream) { | |
17 *stream << identity.name() << "@" << identity.instance() << " run as: " | |
18 << identity.user_id(); | |
19 } | |
20 | |
21 void SerializeSpec(const InterfaceProviderSpec& spec, | |
22 std::stringstream* stream) { | |
23 *stream << " Providing:\n"; | |
24 for (const auto& entry : spec.provides) { | |
25 *stream << " capability: " << entry.first << " containing interfaces:\n"; | |
26 for (const auto& interface_name : entry.second) | |
27 *stream << " " << interface_name << "\n"; | |
28 } | |
29 *stream << "\n Requiring:\n"; | |
30 for (const auto& entry : spec.requires) { | |
31 *stream << " From: " << entry.first << ":\n"; | |
32 for (const auto& capability_name : entry.second) | |
33 *stream << " " << capability_name << "\n"; | |
34 } | |
35 } | |
36 | |
37 } // namespace | |
38 | |
39 CapabilitySet GetRequestedCapabilities(const InterfaceProviderSpec& source_spec, | |
40 const Identity& target) { | |
41 CapabilitySet capabilities; | |
42 | |
43 // Start by looking for specs specific to the supplied identity. | |
44 auto it = source_spec.requires.find(target.name()); | |
45 if (it != source_spec.requires.end()) { | |
46 std::copy(it->second.begin(), it->second.end(), | |
47 std::inserter(capabilities, capabilities.begin())); | |
48 } | |
49 | |
50 // Apply wild card rules too. | |
51 it = source_spec.requires.find("*"); | |
52 if (it != source_spec.requires.end()) { | |
53 std::copy(it->second.begin(), it->second.end(), | |
54 std::inserter(capabilities, capabilities.begin())); | |
55 } | |
56 return capabilities; | |
57 } | |
58 | |
59 InterfaceSet GetInterfacesToExpose( | |
60 const InterfaceProviderSpec& source_spec, | |
61 const Identity& target, | |
62 const InterfaceProviderSpec& target_spec) { | |
63 InterfaceSet exposed_interfaces; | |
64 // TODO(beng): remove this once we can assert that an InterfaceRegistry must | |
65 // always be constructed with a valid identity. | |
66 if (!target.IsValid()) { | |
67 exposed_interfaces.insert("*"); | |
68 return exposed_interfaces; | |
69 } | |
70 CapabilitySet capabilities = GetRequestedCapabilities(source_spec, target); | |
71 for (const auto& capability : capabilities) { | |
72 auto it = target_spec.provides.find(capability); | |
73 if (it != target_spec.provides.end()) { | |
74 for (const auto& interface_name : it->second) | |
75 exposed_interfaces.insert(interface_name); | |
76 } | |
77 } | |
78 return exposed_interfaces; | |
79 } | |
80 | |
81 InterfaceRegistry::InterfaceRegistry(const std::string& name) | |
82 : binding_(this), | |
83 name_(name), | |
84 weak_factory_(this) {} | |
85 InterfaceRegistry::~InterfaceRegistry() {} | |
86 | |
87 void InterfaceRegistry::Bind( | |
88 mojom::InterfaceProviderRequest local_interfaces_request, | |
89 const Identity& local_identity, | |
90 const InterfaceProviderSpec& local_interface_provider_spec, | |
91 const Identity& remote_identity, | |
92 const InterfaceProviderSpec& remote_interface_provider_spec) { | |
93 DCHECK(!binding_.is_bound()); | |
94 local_identity_ = local_identity; | |
95 local_interface_provider_spec_ = local_interface_provider_spec; | |
96 remote_identity_ = remote_identity; | |
97 remote_interface_provider_spec_ = remote_interface_provider_spec; | |
98 RebuildExposedInterfaces(); | |
99 binding_.Bind(std::move(local_interfaces_request)); | |
100 binding_.set_connection_error_handler(base::Bind( | |
101 &InterfaceRegistry::OnConnectionError, base::Unretained(this))); | |
102 } | |
103 | |
104 void InterfaceRegistry::Serialize(std::stringstream* stream) { | |
105 *stream << "\n\nInterfaceRegistry(" << name_ << "):\n"; | |
106 if (!binding_.is_bound()) { | |
107 *stream << "\n --> InterfaceRegistry is not yet bound to a pipe.\n\n"; | |
108 return; | |
109 } | |
110 | |
111 *stream << "Owned by:\n "; | |
112 SerializeIdentity(local_identity_, stream); | |
113 *stream << "\n\n"; | |
114 SerializeSpec(local_interface_provider_spec_, stream); | |
115 | |
116 *stream << "\n"; | |
117 | |
118 *stream << "Bound to:\n "; | |
119 SerializeIdentity(remote_identity_, stream); | |
120 *stream << "\n\n"; | |
121 SerializeSpec(remote_interface_provider_spec_, stream); | |
122 | |
123 *stream << "\nBinders registered for:\n"; | |
124 bool found_exposed = false; | |
125 for (const auto& entry : name_to_binder_) { | |
126 bool exposed = exposed_interfaces_.count(entry.first) > 0; | |
127 found_exposed |= exposed; | |
128 *stream << " " << (exposed ? "* " : " ") << entry.first << "\n"; | |
129 } | |
130 if (found_exposed) | |
131 *stream << "\n * - denotes an interface exposed to remote per policy.\n"; | |
132 | |
133 *stream << "\n\n"; | |
134 if (expose_all_interfaces_) | |
135 *stream << "All interfaces exposed.\n\n"; | |
136 } | |
137 | |
138 base::WeakPtr<InterfaceRegistry> InterfaceRegistry::GetWeakPtr() { | |
139 return weak_factory_.GetWeakPtr(); | |
140 } | |
141 | |
142 bool InterfaceRegistry::AddInterface( | |
143 const std::string& name, | |
144 const base::Callback<void(mojo::ScopedMessagePipeHandle)>& callback, | |
145 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | |
146 return SetInterfaceBinderForName( | |
147 base::MakeUnique<internal::GenericCallbackBinder>(callback, task_runner), | |
148 name); | |
149 } | |
150 | |
151 void InterfaceRegistry::RemoveInterface(const std::string& name) { | |
152 auto it = name_to_binder_.find(name); | |
153 if (it != name_to_binder_.end()) | |
154 name_to_binder_.erase(it); | |
155 } | |
156 | |
157 void InterfaceRegistry::PauseBinding() { | |
158 DCHECK(!is_paused_); | |
159 is_paused_ = true; | |
160 } | |
161 | |
162 void InterfaceRegistry::ResumeBinding() { | |
163 DCHECK(is_paused_); | |
164 is_paused_ = false; | |
165 | |
166 while (!pending_interface_requests_.empty()) { | |
167 auto& request = pending_interface_requests_.front(); | |
168 GetInterface(request.first, std::move(request.second)); | |
169 pending_interface_requests_.pop(); | |
170 } | |
171 } | |
172 | |
173 void InterfaceRegistry::GetInterfaceNames( | |
174 std::set<std::string>* interface_names) { | |
175 DCHECK(interface_names); | |
176 for (auto& entry : name_to_binder_) | |
177 interface_names->insert(entry.first); | |
178 } | |
179 | |
180 void InterfaceRegistry::AddConnectionLostClosure( | |
181 const base::Closure& connection_lost_closure) { | |
182 connection_lost_closures_.push_back(connection_lost_closure); | |
183 } | |
184 | |
185 void InterfaceRegistry::BindInterface(const std::string& name, | |
186 mojo::ScopedMessagePipeHandle handle) { | |
187 // NOTE: We don't expose GetInterface() publicly so as to avoid confusion | |
188 // with local and remote binding requests. | |
189 GetInterface(name, std::move(handle)); | |
190 } | |
191 | |
192 // mojom::InterfaceProvider: | |
193 void InterfaceRegistry::GetInterface(const std::string& interface_name, | |
194 mojo::ScopedMessagePipeHandle handle) { | |
195 if (is_paused_) { | |
196 pending_interface_requests_.emplace(interface_name, std::move(handle)); | |
197 return; | |
198 } | |
199 | |
200 if (CanBindRequestForInterface(interface_name)) { | |
201 auto iter = name_to_binder_.find(interface_name); | |
202 if (iter != name_to_binder_.end()) { | |
203 iter->second->BindInterface(remote_identity_, | |
204 interface_name, | |
205 std::move(handle)); | |
206 } else if (!default_binder_.is_null()) { | |
207 default_binder_.Run(interface_name, std::move(handle)); | |
208 } else { | |
209 LOG(ERROR) << "Failed to locate a binder for interface: " | |
210 << interface_name << " requested by: " << remote_identity_.name() | |
211 << " exposed by: " << local_identity_.name() | |
212 << " via InterfaceProviderSpec \"" << name_ << "\"."; | |
213 | |
214 std::stringstream details; | |
215 Serialize(&details); | |
216 DVLOG(1) << details.str(); | |
217 } | |
218 } else { | |
219 std::stringstream error; | |
220 error << "InterfaceProviderSpec \"" << name_ << "\" prevented service: " | |
221 << remote_identity_.name() << " from binding interface: " | |
222 << interface_name << " exposed by: " << local_identity_.name(); | |
223 mojo::ReportBadMessage(error.str()); | |
224 LOG(ERROR) << error.str(); | |
225 | |
226 std::stringstream details; | |
227 Serialize(&details); | |
228 DVLOG(1) << details.str(); | |
229 } | |
230 } | |
231 | |
232 bool InterfaceRegistry::SetInterfaceBinderForName( | |
233 std::unique_ptr<InterfaceBinder> binder, | |
234 const std::string& interface_name) { | |
235 if (CanBindRequestForInterface(interface_name)) { | |
236 RemoveInterface(interface_name); | |
237 name_to_binder_[interface_name] = std::move(binder); | |
238 return true; | |
239 } | |
240 return false; | |
241 } | |
242 | |
243 bool InterfaceRegistry::CanBindRequestForInterface( | |
244 const std::string& interface_name) const { | |
245 // Any interface may be registered before the registry is bound to a pipe. At | |
246 // bind time, the interfaces exposed will be intersected with the requirements | |
247 // of the source. | |
248 if (!binding_.is_bound()) | |
249 return true; | |
250 return expose_all_interfaces_ || exposed_interfaces_.count(interface_name); | |
251 } | |
252 | |
253 void InterfaceRegistry::RebuildExposedInterfaces() { | |
254 exposed_interfaces_ = GetInterfacesToExpose(remote_interface_provider_spec_, | |
255 local_identity_, | |
256 local_interface_provider_spec_); | |
257 expose_all_interfaces_ = | |
258 exposed_interfaces_.size() == 1 && exposed_interfaces_.count("*") == 1; | |
259 } | |
260 | |
261 void InterfaceRegistry::OnConnectionError() { | |
262 std::list<base::Closure> closures = connection_lost_closures_; | |
263 for (const auto& closure : closures) | |
264 closure.Run(); | |
265 } | |
266 | |
267 } // namespace service_manager | |
OLD | NEW |