| 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 "content/common/mojo/mojo_shell_connection_impl.h" | |
| 6 | |
| 7 #include <queue> | |
| 8 #include <utility> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/callback_helpers.h" | |
| 13 #include "base/lazy_instance.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/memory/ptr_util.h" | |
| 16 #include "base/message_loop/message_loop.h" | |
| 17 #include "base/threading/thread_checker.h" | |
| 18 #include "content/common/mojo/embedded_application_runner.h" | |
| 19 #include "content/public/common/connection_filter.h" | |
| 20 #include "mojo/public/cpp/bindings/binding_set.h" | |
| 21 #include "mojo/public/cpp/system/message_pipe.h" | |
| 22 #include "services/shell/public/cpp/service.h" | |
| 23 #include "services/shell/public/cpp/service_context.h" | |
| 24 #include "services/shell/public/interfaces/service_factory.mojom.h" | |
| 25 #include "services/shell/runner/common/client_util.h" | |
| 26 | |
| 27 namespace content { | |
| 28 namespace { | |
| 29 | |
| 30 base::LazyInstance<std::unique_ptr<MojoShellConnection>>::Leaky | |
| 31 g_connection_for_process = LAZY_INSTANCE_INITIALIZER; | |
| 32 | |
| 33 MojoShellConnection::Factory* mojo_shell_connection_factory = nullptr; | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 // A ref-counted object which owns the IO thread state of a | |
| 38 // MojoShellConnectionImpl. This includes Service and ServiceFactory | |
| 39 // bindings. | |
| 40 class MojoShellConnectionImpl::IOThreadContext | |
| 41 : public base::RefCountedThreadSafe<IOThreadContext>, | |
| 42 public shell::Service, | |
| 43 public shell::InterfaceFactory<shell::mojom::ServiceFactory>, | |
| 44 public shell::mojom::ServiceFactory { | |
| 45 public: | |
| 46 using InitializeCallback = base::Callback<void(const shell::Identity&)>; | |
| 47 using ServiceFactoryCallback = | |
| 48 base::Callback<void(shell::mojom::ServiceRequest, const std::string&)>; | |
| 49 | |
| 50 IOThreadContext(shell::mojom::ServiceRequest service_request, | |
| 51 scoped_refptr<base::SequencedTaskRunner> io_task_runner, | |
| 52 std::unique_ptr<shell::Connector> io_thread_connector, | |
| 53 shell::mojom::ConnectorRequest connector_request) | |
| 54 : pending_service_request_(std::move(service_request)), | |
| 55 io_task_runner_(io_task_runner), | |
| 56 io_thread_connector_(std::move(io_thread_connector)), | |
| 57 pending_connector_request_(std::move(connector_request)), | |
| 58 weak_factory_(this) { | |
| 59 // This will be reattached by any of the IO thread functions on first call. | |
| 60 io_thread_checker_.DetachFromThread(); | |
| 61 } | |
| 62 | |
| 63 // Safe to call from any thread. | |
| 64 void Start(const InitializeCallback& initialize_callback, | |
| 65 const ServiceFactoryCallback& create_service_callback, | |
| 66 const base::Closure& stop_callback) { | |
| 67 DCHECK(!started_); | |
| 68 | |
| 69 started_ = true; | |
| 70 callback_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
| 71 initialize_handler_ = initialize_callback; | |
| 72 create_service_callback_ = create_service_callback; | |
| 73 stop_callback_ = stop_callback; | |
| 74 io_task_runner_->PostTask( | |
| 75 FROM_HERE, base::Bind(&IOThreadContext::StartOnIOThread, this)); | |
| 76 } | |
| 77 | |
| 78 // Safe to call from whichever thread called Start() (or may have called | |
| 79 // Start()). Must be called before IO thread shutdown. | |
| 80 void ShutDown() { | |
| 81 if (!started_) | |
| 82 return; | |
| 83 | |
| 84 bool posted = io_task_runner_->PostTask( | |
| 85 FROM_HERE, base::Bind(&IOThreadContext::ShutDownOnIOThread, this)); | |
| 86 DCHECK(posted); | |
| 87 } | |
| 88 | |
| 89 // Safe to call any time before a message is received from a process. | |
| 90 // i.e. can be called when starting the process but not afterwards. | |
| 91 int AddConnectionFilter(std::unique_ptr<ConnectionFilter> filter) { | |
| 92 base::AutoLock lock(lock_); | |
| 93 | |
| 94 int id = ++next_filter_id_; | |
| 95 | |
| 96 // We should never hit this in practice, but let's crash just in case. | |
| 97 CHECK_NE(id, kInvalidConnectionFilterId); | |
| 98 | |
| 99 connection_filters_[id] = std::move(filter); | |
| 100 return id; | |
| 101 } | |
| 102 | |
| 103 void RemoveConnectionFilter(int filter_id) { | |
| 104 io_task_runner_->PostTask( | |
| 105 FROM_HERE, | |
| 106 base::Bind(&IOThreadContext::RemoveConnectionFilterOnIOThread, this, | |
| 107 filter_id)); | |
| 108 } | |
| 109 | |
| 110 // Safe to call any time before Start() is called. | |
| 111 void SetDefaultBinderForBrowserConnection( | |
| 112 const shell::InterfaceRegistry::Binder& binder) { | |
| 113 DCHECK(!started_); | |
| 114 default_browser_binder_ = base::Bind( | |
| 115 &IOThreadContext::CallBinderOnTaskRunner, | |
| 116 base::ThreadTaskRunnerHandle::Get(), binder); | |
| 117 } | |
| 118 | |
| 119 private: | |
| 120 friend class base::RefCountedThreadSafe<IOThreadContext>; | |
| 121 | |
| 122 class MessageLoopObserver : public base::MessageLoop::DestructionObserver { | |
| 123 public: | |
| 124 explicit MessageLoopObserver(base::WeakPtr<IOThreadContext> context) | |
| 125 : context_(context) { | |
| 126 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 127 } | |
| 128 | |
| 129 ~MessageLoopObserver() override { | |
| 130 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
| 131 } | |
| 132 | |
| 133 void ShutDown() { | |
| 134 if (!is_active_) | |
| 135 return; | |
| 136 | |
| 137 // The call into |context_| below may reenter ShutDown(), hence we set | |
| 138 // |is_active_| to false here. | |
| 139 is_active_ = false; | |
| 140 if (context_) | |
| 141 context_->ShutDownOnIOThread(); | |
| 142 | |
| 143 delete this; | |
| 144 } | |
| 145 | |
| 146 private: | |
| 147 void WillDestroyCurrentMessageLoop() override { | |
| 148 DCHECK(is_active_); | |
| 149 ShutDown(); | |
| 150 } | |
| 151 | |
| 152 bool is_active_ = true; | |
| 153 base::WeakPtr<IOThreadContext> context_; | |
| 154 | |
| 155 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); | |
| 156 }; | |
| 157 | |
| 158 ~IOThreadContext() override {} | |
| 159 | |
| 160 void StartOnIOThread() { | |
| 161 // Should bind |io_thread_checker_| to the context's thread. | |
| 162 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 163 service_context_.reset(new shell::ServiceContext( | |
| 164 this, std::move(pending_service_request_), | |
| 165 std::move(io_thread_connector_), | |
| 166 std::move(pending_connector_request_))); | |
| 167 | |
| 168 // MessageLoopObserver owns itself. | |
| 169 message_loop_observer_ = | |
| 170 new MessageLoopObserver(weak_factory_.GetWeakPtr()); | |
| 171 } | |
| 172 | |
| 173 void ShutDownOnIOThread() { | |
| 174 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 175 | |
| 176 weak_factory_.InvalidateWeakPtrs(); | |
| 177 | |
| 178 // Note that this method may be invoked by MessageLoopObserver observing | |
| 179 // MessageLoop destruction. In that case, this call to ShutDown is | |
| 180 // effectively a no-op. In any case it's safe. | |
| 181 if (message_loop_observer_) { | |
| 182 message_loop_observer_->ShutDown(); | |
| 183 message_loop_observer_ = nullptr; | |
| 184 } | |
| 185 | |
| 186 // Resetting the ServiceContext below may otherwise release the last | |
| 187 // reference to this IOThreadContext. We keep it alive until the stack | |
| 188 // unwinds. | |
| 189 scoped_refptr<IOThreadContext> keepalive(this); | |
| 190 | |
| 191 factory_bindings_.CloseAllBindings(); | |
| 192 service_context_.reset(); | |
| 193 | |
| 194 ClearConnectionFiltersOnIOThread(); | |
| 195 } | |
| 196 | |
| 197 void ClearConnectionFiltersOnIOThread() { | |
| 198 base::AutoLock lock(lock_); | |
| 199 connection_filters_.clear(); | |
| 200 } | |
| 201 | |
| 202 void RemoveConnectionFilterOnIOThread(int filter_id) { | |
| 203 base::AutoLock lock(lock_); | |
| 204 auto it = connection_filters_.find(filter_id); | |
| 205 DCHECK(it != connection_filters_.end()); | |
| 206 connection_filters_.erase(it); | |
| 207 } | |
| 208 | |
| 209 void OnBrowserConnectionLost() { | |
| 210 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 211 has_browser_connection_ = false; | |
| 212 } | |
| 213 | |
| 214 ///////////////////////////////////////////////////////////////////////////// | |
| 215 // shell::Service implementation | |
| 216 | |
| 217 void OnStart(const shell::Identity& identity) override { | |
| 218 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 219 DCHECK(!initialize_handler_.is_null()); | |
| 220 id_ = identity; | |
| 221 | |
| 222 InitializeCallback handler = base::ResetAndReturn(&initialize_handler_); | |
| 223 callback_task_runner_->PostTask(FROM_HERE, base::Bind(handler, identity)); | |
| 224 } | |
| 225 | |
| 226 bool OnConnect(const shell::Identity& remote_identity, | |
| 227 shell::InterfaceRegistry* registry) override { | |
| 228 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 229 std::string remote_app = remote_identity.name(); | |
| 230 if (remote_app == "service:shell") { | |
| 231 // Only expose the SCF interface to the shell. | |
| 232 registry->AddInterface<shell::mojom::ServiceFactory>(this); | |
| 233 return true; | |
| 234 } | |
| 235 | |
| 236 bool accept = false; | |
| 237 { | |
| 238 base::AutoLock lock(lock_); | |
| 239 for (auto& entry : connection_filters_) { | |
| 240 accept |= entry.second->OnConnect(remote_identity, registry, | |
| 241 service_context_->connector()); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 if (remote_identity.name() == "service:content_browser" && | |
| 246 !has_browser_connection_) { | |
| 247 has_browser_connection_ = true; | |
| 248 registry->set_default_binder(default_browser_binder_); | |
| 249 registry->SetConnectionLostClosure( | |
| 250 base::Bind(&IOThreadContext::OnBrowserConnectionLost, this)); | |
| 251 return true; | |
| 252 } | |
| 253 | |
| 254 // If no filters were interested, reject the connection. | |
| 255 return accept; | |
| 256 } | |
| 257 | |
| 258 bool OnStop() override { | |
| 259 ClearConnectionFiltersOnIOThread(); | |
| 260 callback_task_runner_->PostTask(FROM_HERE, stop_callback_); | |
| 261 return true; | |
| 262 } | |
| 263 | |
| 264 ///////////////////////////////////////////////////////////////////////////// | |
| 265 // shell::InterfaceFactory<shell::mojom::ServiceFactory> implementation | |
| 266 | |
| 267 void Create(const shell::Identity& remote_identity, | |
| 268 shell::mojom::ServiceFactoryRequest request) override { | |
| 269 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 270 factory_bindings_.AddBinding(this, std::move(request)); | |
| 271 } | |
| 272 | |
| 273 ///////////////////////////////////////////////////////////////////////////// | |
| 274 // shell::mojom::ServiceFactory implementation | |
| 275 | |
| 276 void CreateService(shell::mojom::ServiceRequest request, | |
| 277 const std::string& name) override { | |
| 278 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 279 callback_task_runner_->PostTask( | |
| 280 FROM_HERE, | |
| 281 base::Bind(create_service_callback_, base::Passed(&request), name)); | |
| 282 } | |
| 283 | |
| 284 static void CallBinderOnTaskRunner( | |
| 285 scoped_refptr<base::SequencedTaskRunner> task_runner, | |
| 286 const shell::InterfaceRegistry::Binder& binder, | |
| 287 const std::string& interface_name, | |
| 288 mojo::ScopedMessagePipeHandle request_handle) { | |
| 289 task_runner->PostTask(FROM_HERE, base::Bind(binder, interface_name, | |
| 290 base::Passed(&request_handle))); | |
| 291 } | |
| 292 | |
| 293 base::ThreadChecker io_thread_checker_; | |
| 294 bool started_ = false; | |
| 295 | |
| 296 // Temporary state established on construction and consumed on the IO thread | |
| 297 // once the connection is started. | |
| 298 shell::mojom::ServiceRequest pending_service_request_; | |
| 299 scoped_refptr<base::SequencedTaskRunner> io_task_runner_; | |
| 300 std::unique_ptr<shell::Connector> io_thread_connector_; | |
| 301 shell::mojom::ConnectorRequest pending_connector_request_; | |
| 302 | |
| 303 // TaskRunner on which to run our owner's callbacks, i.e. the ones passed to | |
| 304 // Start(). | |
| 305 scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; | |
| 306 | |
| 307 // Callback to run once Service::OnStart is invoked. | |
| 308 InitializeCallback initialize_handler_; | |
| 309 | |
| 310 // Callback to run when a new Service request is received. | |
| 311 ServiceFactoryCallback create_service_callback_; | |
| 312 | |
| 313 // Callback to run if the service is stopped by the service manager. | |
| 314 base::Closure stop_callback_; | |
| 315 | |
| 316 // Called once a connection has been received from the browser process & the | |
| 317 // default binder (below) has been set up. | |
| 318 bool has_browser_connection_ = false; | |
| 319 | |
| 320 shell::Identity id_; | |
| 321 | |
| 322 // Default binder callback used for the browser connection's | |
| 323 // InterfaceRegistry. | |
| 324 // | |
| 325 // TODO(rockot): Remove this once all interfaces exposed to the browser are | |
| 326 // exposed via a ConnectionFilter. | |
| 327 shell::InterfaceRegistry::Binder default_browser_binder_; | |
| 328 | |
| 329 std::unique_ptr<shell::ServiceContext> service_context_; | |
| 330 mojo::BindingSet<shell::mojom::ServiceFactory> factory_bindings_; | |
| 331 int next_filter_id_ = kInvalidConnectionFilterId; | |
| 332 | |
| 333 // Not owned. | |
| 334 MessageLoopObserver* message_loop_observer_ = nullptr; | |
| 335 | |
| 336 // Guards |connection_filters_|. | |
| 337 base::Lock lock_; | |
| 338 std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_; | |
| 339 | |
| 340 base::WeakPtrFactory<IOThreadContext> weak_factory_; | |
| 341 | |
| 342 DISALLOW_COPY_AND_ASSIGN(IOThreadContext); | |
| 343 }; | |
| 344 | |
| 345 //////////////////////////////////////////////////////////////////////////////// | |
| 346 // MojoShellConnection, public: | |
| 347 | |
| 348 // static | |
| 349 void MojoShellConnection::SetForProcess( | |
| 350 std::unique_ptr<MojoShellConnection> connection) { | |
| 351 DCHECK(!g_connection_for_process.Get()); | |
| 352 g_connection_for_process.Get() = std::move(connection); | |
| 353 } | |
| 354 | |
| 355 // static | |
| 356 MojoShellConnection* MojoShellConnection::GetForProcess() { | |
| 357 return g_connection_for_process.Get().get(); | |
| 358 } | |
| 359 | |
| 360 // static | |
| 361 void MojoShellConnection::DestroyForProcess() { | |
| 362 // This joins the shell controller thread. | |
| 363 g_connection_for_process.Get().reset(); | |
| 364 } | |
| 365 | |
| 366 // static | |
| 367 void MojoShellConnection::SetFactoryForTest(Factory* factory) { | |
| 368 DCHECK(!g_connection_for_process.Get()); | |
| 369 mojo_shell_connection_factory = factory; | |
| 370 } | |
| 371 | |
| 372 // static | |
| 373 std::unique_ptr<MojoShellConnection> MojoShellConnection::Create( | |
| 374 shell::mojom::ServiceRequest request, | |
| 375 scoped_refptr<base::SequencedTaskRunner> io_task_runner) { | |
| 376 if (mojo_shell_connection_factory) | |
| 377 return mojo_shell_connection_factory->Run(); | |
| 378 return base::MakeUnique<MojoShellConnectionImpl>( | |
| 379 std::move(request), io_task_runner); | |
| 380 } | |
| 381 | |
| 382 MojoShellConnection::~MojoShellConnection() {} | |
| 383 | |
| 384 //////////////////////////////////////////////////////////////////////////////// | |
| 385 // MojoShellConnectionImpl, public: | |
| 386 | |
| 387 MojoShellConnectionImpl::MojoShellConnectionImpl( | |
| 388 shell::mojom::ServiceRequest request, | |
| 389 scoped_refptr<base::SequencedTaskRunner> io_task_runner) | |
| 390 : weak_factory_(this) { | |
| 391 shell::mojom::ConnectorRequest connector_request; | |
| 392 connector_ = shell::Connector::Create(&connector_request); | |
| 393 | |
| 394 std::unique_ptr<shell::Connector> io_thread_connector = connector_->Clone(); | |
| 395 context_ = new IOThreadContext( | |
| 396 std::move(request), io_task_runner, std::move(io_thread_connector), | |
| 397 std::move(connector_request)); | |
| 398 } | |
| 399 | |
| 400 MojoShellConnectionImpl::~MojoShellConnectionImpl() { | |
| 401 context_->ShutDown(); | |
| 402 } | |
| 403 | |
| 404 //////////////////////////////////////////////////////////////////////////////// | |
| 405 // MojoShellConnectionImpl, MojoShellConnection implementation: | |
| 406 | |
| 407 void MojoShellConnectionImpl::Start() { | |
| 408 context_->Start( | |
| 409 base::Bind(&MojoShellConnectionImpl::OnContextInitialized, | |
| 410 weak_factory_.GetWeakPtr()), | |
| 411 base::Bind(&MojoShellConnectionImpl::CreateService, | |
| 412 weak_factory_.GetWeakPtr()), | |
| 413 base::Bind(&MojoShellConnectionImpl::OnConnectionLost, | |
| 414 weak_factory_.GetWeakPtr())); | |
| 415 } | |
| 416 | |
| 417 void MojoShellConnectionImpl::SetInitializeHandler( | |
| 418 const base::Closure& handler) { | |
| 419 DCHECK(initialize_handler_.is_null()); | |
| 420 initialize_handler_ = handler; | |
| 421 } | |
| 422 | |
| 423 shell::Connector* MojoShellConnectionImpl::GetConnector() { | |
| 424 return connector_.get(); | |
| 425 } | |
| 426 | |
| 427 const shell::Identity& MojoShellConnectionImpl::GetIdentity() const { | |
| 428 return identity_; | |
| 429 } | |
| 430 | |
| 431 void MojoShellConnectionImpl::SetConnectionLostClosure( | |
| 432 const base::Closure& closure) { | |
| 433 connection_lost_handler_ = closure; | |
| 434 } | |
| 435 | |
| 436 void MojoShellConnectionImpl::SetupInterfaceRequestProxies( | |
| 437 shell::InterfaceRegistry* registry, | |
| 438 shell::InterfaceProvider* provider) { | |
| 439 // It's safe to bind |registry| as a raw pointer because the caller must | |
| 440 // guarantee that it outlives |this|, and |this| is bound as a weak ptr here. | |
| 441 context_->SetDefaultBinderForBrowserConnection( | |
| 442 base::Bind(&MojoShellConnectionImpl::GetInterface, | |
| 443 weak_factory_.GetWeakPtr(), registry)); | |
| 444 | |
| 445 // TODO(beng): remove provider parameter. | |
| 446 } | |
| 447 | |
| 448 int MojoShellConnectionImpl::AddConnectionFilter( | |
| 449 std::unique_ptr<ConnectionFilter> filter) { | |
| 450 return context_->AddConnectionFilter(std::move(filter)); | |
| 451 } | |
| 452 | |
| 453 void MojoShellConnectionImpl::RemoveConnectionFilter(int filter_id) { | |
| 454 context_->RemoveConnectionFilter(filter_id); | |
| 455 } | |
| 456 | |
| 457 void MojoShellConnectionImpl::AddEmbeddedService( | |
| 458 const std::string& name, | |
| 459 const MojoApplicationInfo& info) { | |
| 460 std::unique_ptr<EmbeddedApplicationRunner> app( | |
| 461 new EmbeddedApplicationRunner(name, info)); | |
| 462 AddServiceRequestHandler( | |
| 463 name, base::Bind(&EmbeddedApplicationRunner::BindServiceRequest, | |
| 464 base::Unretained(app.get()))); | |
| 465 auto result = embedded_apps_.insert(std::make_pair(name, std::move(app))); | |
| 466 DCHECK(result.second); | |
| 467 } | |
| 468 | |
| 469 void MojoShellConnectionImpl::AddServiceRequestHandler( | |
| 470 const std::string& name, | |
| 471 const ServiceRequestHandler& handler) { | |
| 472 auto result = request_handlers_.insert(std::make_pair(name, handler)); | |
| 473 DCHECK(result.second); | |
| 474 } | |
| 475 | |
| 476 void MojoShellConnectionImpl::CreateService( | |
| 477 shell::mojom::ServiceRequest request, | |
| 478 const std::string& name) { | |
| 479 auto it = request_handlers_.find(name); | |
| 480 if (it != request_handlers_.end()) | |
| 481 it->second.Run(std::move(request)); | |
| 482 } | |
| 483 | |
| 484 void MojoShellConnectionImpl::OnContextInitialized( | |
| 485 const shell::Identity& identity) { | |
| 486 identity_ = identity; | |
| 487 if (!initialize_handler_.is_null()) | |
| 488 base::ResetAndReturn(&initialize_handler_).Run(); | |
| 489 } | |
| 490 | |
| 491 void MojoShellConnectionImpl::OnConnectionLost() { | |
| 492 if (!connection_lost_handler_.is_null()) | |
| 493 connection_lost_handler_.Run(); | |
| 494 } | |
| 495 | |
| 496 void MojoShellConnectionImpl::GetInterface( | |
| 497 shell::mojom::InterfaceProvider* provider, | |
| 498 const std::string& interface_name, | |
| 499 mojo::ScopedMessagePipeHandle request_handle) { | |
| 500 provider->GetInterface(interface_name, std::move(request_handle)); | |
| 501 } | |
| 502 | |
| 503 } // namespace content | |
| 504 | |
| OLD | NEW |