| 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 |