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 |