Chromium Code Reviews| Index: content/browser/mojo_shell_context_impl.cc |
| diff --git a/content/browser/mojo_shell_context_impl.cc b/content/browser/mojo_shell_context_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bd0bb764d6bfeed445b3ffb411b867a7e3befb65 |
| --- /dev/null |
| +++ b/content/browser/mojo_shell_context_impl.cc |
| @@ -0,0 +1,213 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/mojo_shell_context_impl.h" |
| + |
| +#include "base/lazy_instance.h" |
| +#include "base/macros.h" |
| +#include "base/memory/weak_ptr.h" |
| +#include "base/single_thread_task_runner.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "base/synchronization/lock.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/content_browser_client.h" |
| +#include "content/public/browser/mojo_app_connection.h" |
| +#include "content/public/browser/utility_process_host.h" |
| +#include "content/public/browser/utility_process_host_client.h" |
| +#include "content/public/common/content_client.h" |
| +#include "content/public/common/process_control.mojom.h" |
| +#include "content/public/common/service_registry.h" |
| +#include "content/public/common/static_mojo_application_loader.h" |
| +#include "mojo/application/public/cpp/application_delegate.h" |
| +#include "mojo/common/url_type_converters.h" |
| +#include "mojo/services/network/public/interfaces/url_loader.mojom.h" |
| +#include "mojo/shell/application_loader.h" |
| +#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" |
| +#include "third_party/mojo/src/mojo/public/cpp/bindings/string.h" |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +// Virtual app URL to use as the requestor identity when connecting from browser |
| +// code to a Mojo app via the shell proxy. |
| +const char kBrowserAppUrl[] = "system:content_browser"; |
|
jam
2015/05/27 16:05:36
i'm confused, how come this string is only referen
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
It would make sense for this to be a public consta
|
| + |
| +// An ApplicationRegistry instance used for testing to override builtin loaders. |
| +base::LazyInstance<base::Callback<void(ApplicationRegistry*)>> |
| +g_application_registry_initializer_for_testing; |
| + |
| +void StartProcessOnIOThread(mojo::InterfaceRequest<ProcessControl> request) { |
| + UtilityProcessHost* process_host = |
| + UtilityProcessHost::Create(nullptr, nullptr); |
| + // TODO(rockot): Make it possible for the embedder to associate app URLs with |
| + // app names so we can have more meaningful process names here. |
| + process_host->SetName(base::UTF8ToUTF16("Mojo Application")); |
|
jam
2015/05/27 16:05:36
all the other process names are localized..
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
It didn't seem worthwhile to localize a placeholde
|
| + if (process_host->StartMojoMode()) { |
| + ServiceRegistry* services = process_host->GetServiceRegistry(); |
| + services->ConnectToRemoteService(request.Pass()); |
| + } else { |
| + LOG(ERROR) << "Unable to start utility process."; |
|
jam
2015/05/27 16:05:36
do we really need all this error handling? i looke
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
Ah, you're right. I removed the error checking. I
|
| + } |
| +} |
| + |
| +void OnApplicationLoaded( |
| + const GURL& url, LoadApplicationResult result) { |
| + if (result != LOAD_APPLICATION_RESULT_OK) { |
| + LOG(ERROR) << "Failed to launch Mojo application for " << url.spec(); |
| + } |
| +} |
| + |
| +// The default loader to use for all applications. This launches a utility |
| +// process and forwards the Load request the ProcessControl service there. |
| +class UtilityProcessLoader : public mojo::shell::ApplicationLoader { |
| + public: |
| + UtilityProcessLoader() {} |
| + ~UtilityProcessLoader() override {} |
| + |
| + private: |
| + // mojo::shell::ApplicationLoader: |
| + void Load( |
| + const GURL& url, |
| + mojo::InterfaceRequest<mojo::Application> application_request) override { |
| + ProcessControlPtr process_control; |
| + auto process_request = mojo::GetProxy(&process_control); |
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO) |
|
jam
2015/05/27 16:05:36
nit:BrowserThread::PostTask(BrowserThread::IO, FRO
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
Done.
|
| + ->PostTask(FROM_HERE, |
| + base::Bind(&StartProcessOnIOThread, |
| + base::Passed(&process_request))); |
| + process_control->LoadApplication( |
| + mojo::String::From(url.spec()), application_request.Pass(), |
|
jam
2015/05/27 16:05:36
nit: I think url.spec() is enough since mojo::Stri
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
Done.
|
| + base::Bind(&OnApplicationLoaded, url)); |
| + } |
| + |
| + DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader); |
| +}; |
| + |
| +} // namespace |
| + |
| +// Thread-safe proxy providing global browser access to the shell context. |
|
jam
2015/05/27 16:05:36
what does "global browser access" mean? do you mea
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
Yes. Clarified.
|
| +class MojoShellContextImpl::Proxy { |
| + public: |
| + Proxy() {} |
| + ~Proxy() {} |
| + |
| + void Reset(base::WeakPtr<MojoShellContextImpl> weak_shell_context); |
|
jam
2015/05/27 16:05:36
nit: IMO this would be more readable if they were
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
Done.
|
| + void ConnectToApplication( |
| + const GURL& url, |
| + mojo::InterfaceRequest<mojo::ServiceProvider> request); |
| + |
| + private: |
| + base::Lock lock_; |
|
jam
2015/05/27 16:05:35
I don't understand why this locking is needed. i.e
Ken Rockot(use gerrit already)
2015/05/27 19:36:16
You're right, no need for the weakptr either. Thou
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| + base::WeakPtr<MojoShellContextImpl> weak_shell_context_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Proxy); |
| +}; |
| + |
| +// static |
| +base::LazyInstance<MojoShellContextImpl::Proxy> MojoShellContextImpl::proxy_ = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +void MojoShellContextImpl::Proxy::Reset( |
| + base::WeakPtr<MojoShellContextImpl> weak_shell_context) { |
| + base::AutoLock locker(lock_); |
| + DCHECK(!weak_shell_context_ || !weak_shell_context); |
| + weak_shell_context_ = weak_shell_context; |
| + if (weak_shell_context_) { |
| + task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| + } else { |
| + task_runner_ = nullptr; |
| + } |
| +} |
| + |
| +void MojoShellContextImpl::Proxy::ConnectToApplication( |
| + const GURL& url, |
| + mojo::InterfaceRequest<mojo::ServiceProvider> request) { |
| + base::AutoLock locker(lock_); |
| + if (!task_runner_) { |
| + LOG(ERROR) << "No shell context available to connect to " << url.spec(); |
| + return; |
| + } |
| + if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) { |
| + if (weak_shell_context_) { |
| + weak_shell_context_->ConnectToApplicationOnOwnThread( |
| + url, request.Pass()); |
| + } |
| + } else { |
| + task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MojoShellContextImpl::ConnectToApplicationOnOwnThread, |
| + weak_shell_context_, url, base::Passed(&request))); |
| + } |
| +} |
| + |
| +// static |
| +scoped_ptr<MojoShellContext> MojoShellContext::Create() { |
| + return scoped_ptr<MojoShellContext>(new MojoShellContextImpl); |
| +} |
| + |
| +void MojoShellContext::SetApplicationRegistryInitializerForTesting( |
| + const base::Callback<void(ApplicationRegistry*)>& registry) { |
| + g_application_registry_initializer_for_testing.Get() = registry; |
| +} |
| + |
| +MojoShellContextImpl::MojoShellContextImpl() |
| + : application_manager_(new mojo::shell::ApplicationManager(this)), |
| + weak_factory_(this) { |
| + proxy_.Get().Reset(weak_factory_.GetWeakPtr()); |
| + application_manager_->set_default_loader( |
| + scoped_ptr<mojo::shell::ApplicationLoader>(new UtilityProcessLoader)); |
| + GetContentClient()->browser()->RegisterMojoApplications(this); |
| + if (!g_application_registry_initializer_for_testing.Get().is_null()) |
| + g_application_registry_initializer_for_testing.Get().Run(this); |
| +} |
| + |
| +MojoShellContextImpl::~MojoShellContextImpl() { |
| + proxy_.Get().Reset(base::WeakPtr<MojoShellContextImpl>()); |
| +} |
| + |
| +// static |
| +void MojoShellContextImpl::ConnectToApplication( |
| + const GURL& url, |
| + mojo::InterfaceRequest<mojo::ServiceProvider> request) { |
| + proxy_.Get().ConnectToApplication(url, request.Pass()); |
| +} |
| + |
| +void MojoShellContextImpl::RegisterStaticAppForURL( |
| + const GURL& url, |
| + const StaticAppFactory& factory) { |
| + application_manager_->SetLoaderForURL( |
| + scoped_ptr<mojo::shell::ApplicationLoader>( |
| + new StaticMojoApplicationLoader(factory)), |
| + url); |
| +} |
| + |
| +void MojoShellContextImpl::ConnectToApplicationOnOwnThread( |
| + const GURL& url, |
| + mojo::InterfaceRequest<mojo::ServiceProvider> request) { |
| + mojo::URLRequestPtr url_request = mojo::URLRequest::New(); |
| + url_request->url = mojo::String::From(url); |
| + application_manager_->ConnectToApplication( |
| + url_request.Pass(), GURL(kBrowserAppUrl), request.Pass(), |
| + mojo::ServiceProviderPtr(), base::Bind(&base::DoNothing)); |
| +} |
| + |
| +GURL MojoShellContextImpl::ResolveMappings(const GURL& url) { |
| + return url; |
| +} |
| + |
| +GURL MojoShellContextImpl::ResolveMojoURL(const GURL& url) { |
| + return url; |
| +} |
| + |
| +bool MojoShellContextImpl::CreateFetcher( |
| + const GURL& url, |
| + const mojo::shell::Fetcher::FetchCallback& loader_callback) { |
| + return false; |
| +} |
| + |
| + |
| +} // namespace content |