Index: content/public/common/static_mojo_application_loader.cc |
diff --git a/content/public/common/static_mojo_application_loader.cc b/content/public/common/static_mojo_application_loader.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c98a49e1b833b617519a75b66ee349052530eba1 |
--- /dev/null |
+++ b/content/public/common/static_mojo_application_loader.cc |
@@ -0,0 +1,141 @@ |
+// 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/public/common/static_mojo_application_loader.h" |
+ |
+#include "base/bind.h" |
+#include "base/lazy_instance.h" |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/task_runner.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/threading/thread.h" |
+#include "base/threading/thread_local.h" |
+#include "mojo/application/public/cpp/application_delegate.h" |
+#include "mojo/application/public/cpp/application_impl.h" |
+#include "mojo/application/public/interfaces/application.mojom.h" |
+#include "mojo/common/message_pump_mojo.h" |
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+class Runner; |
+ |
+// Tracks each application's Runner on its main thread. |
+base::LazyInstance<base::ThreadLocalPointer<Runner>> g_runner; |
+ |
+void TerminateCurrentApp(); |
+ |
+// Container for a single instance of the loaded application. This lives and |
+// dies on the app instance's own thread and kills itself either when the thread |
+// message loop is destroyed or the app terminates itself. |
+class Runner : public base::MessageLoop::DestructionObserver { |
+ public: |
+ Runner(mojo::InterfaceRequest<mojo::Application> request, |
+ scoped_refptr<base::TaskRunner> exit_task_runner, |
+ const base::Closure& exit_callback, |
+ scoped_ptr<mojo::ApplicationDelegate> delegate) |
+ : exit_task_runner_(exit_task_runner), |
+ exit_callback_(exit_callback), |
+ delegate_(delegate.Pass()) { |
+ DCHECK(base::MessageLoop::current()); |
+ DCHECK(!g_runner.Get().Get()); |
+ g_runner.Get().Set(this); |
+ base::MessageLoop::current()->AddDestructionObserver(this); |
+ application_.reset( |
+ new mojo::ApplicationImpl(delegate_.get(), request.Pass(), |
+ base::Bind(&TerminateCurrentApp))); |
+ } |
+ |
+ private: |
+ friend void TerminateCurrentApp(); |
+ |
+ ~Runner() override { |
+ g_runner.Get().Set(nullptr); |
+ base::MessageLoop::current()->RemoveDestructionObserver(this); |
+ exit_task_runner_->PostTask(FROM_HERE, exit_callback_); |
+ } |
+ |
+ // base::MessageLoop::DestructionObserver: |
+ void WillDestroyCurrentMessageLoop() override { |
+ DCHECK(base::MessageLoop::current()); |
+ delete this; |
+ } |
+ |
+ scoped_refptr<base::TaskRunner> exit_task_runner_; |
+ base::Closure exit_callback_; |
+ scoped_ptr<mojo::ApplicationDelegate> delegate_; |
+ scoped_ptr<mojo::ApplicationImpl> application_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Runner); |
+}; |
+ |
+void RunAppOnOwnThread( |
+ mojo::InterfaceRequest<mojo::Application> request, |
+ scoped_refptr<base::TaskRunner> exit_task_runner, |
+ const base::Closure& exit_callback, |
+ const StaticMojoApplicationLoader::ApplicationFactory& factory) { |
+ // This object either destroys itself when the current MessageLoop is |
+ // destroyed, or it is destroyed by TerminateCurrentApp (see below). |
+ new Runner(request.Pass(), exit_task_runner, exit_callback, factory.Run()); |
+} |
+ |
+// This is run on an app's own thread when its ApplicationImpl::Terminate() |
+// method is called. |
+void TerminateCurrentApp() { |
+ Runner* runner = g_runner.Get().Get(); |
+ DCHECK(runner); |
+ delete runner; |
+} |
+ |
+} // namespace |
+ |
+StaticMojoApplicationLoader::StaticMojoApplicationLoader( |
+ const ApplicationFactory& factory) |
+ : StaticMojoApplicationLoader(factory, base::Closure()) { |
+} |
+ |
+StaticMojoApplicationLoader::StaticMojoApplicationLoader( |
+ const ApplicationFactory& factory, |
+ const base::Closure& quit_callback) |
+ : factory_(factory), |
+ quit_callback_(quit_callback), |
+ weak_factory_(this) { |
+} |
+ |
+StaticMojoApplicationLoader::~StaticMojoApplicationLoader() { |
+} |
+ |
+void StaticMojoApplicationLoader::Load( |
+ const GURL& url, |
+ mojo::InterfaceRequest<mojo::Application> request) { |
+ threads_.insert(threads_.begin(), make_scoped_ptr(new base::Thread( |
+ "Mojo Application: " + url.spec()))); |
+ base::Thread::Options options; |
+ options.message_pump_factory = |
+ base::Bind(&mojo::common::MessagePumpMojo::Create); |
+ threads_.front()->StartWithOptions(options); |
+ |
+ // If the application's thread quits on its own before this loader dies, we |
+ // evict the Thread object from |threads_| and destroy it. |
+ auto exit_callback = base::Bind( |
+ &StaticMojoApplicationLoader::CleanUpAppThread, |
+ weak_factory_.GetWeakPtr(), threads_.begin()); |
+ threads_.front()->task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RunAppOnOwnThread, base::Passed(&request), |
+ base::ThreadTaskRunnerHandle::Get(), exit_callback, factory_)); |
+} |
+ |
+void StaticMojoApplicationLoader::CleanUpAppThread( |
+ typename ThreadList::iterator iter) { |
+ threads_.erase(iter); |
+ if (!quit_callback_.is_null()) |
+ quit_callback_.Run(); |
+} |
+ |
+} // namespace content |