Commit 86a03daa authored by qsr@chromium.org's avatar qsr@chromium.org

Have mojo_shell run in its custom thread on android.

The native viewport service on android must run on the main thread
of the application. Because it is expected at the moment to run on
its own thread, this CL move the shell thread on android to a
secondary background thread and use the main thread of the
application for the native viewport service.

Review URL: https://codereview.chromium.org/399663002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283764 0039d316-1c4b-4281-b951-d872f2087c98
parent c81f5b20
...@@ -585,6 +585,8 @@ ...@@ -585,6 +585,8 @@
'shell/task_runners.h', 'shell/task_runners.h',
'shell/test_child_process.cc', 'shell/test_child_process.cc',
'shell/test_child_process.h', 'shell/test_child_process.h',
'shell/ui_service_loader_android.cc',
'shell/ui_service_loader_android.h',
'shell/view_manager_loader.cc', 'shell/view_manager_loader.cc',
'shell/view_manager_loader.h', 'shell/view_manager_loader.h',
], ],
......
...@@ -31,13 +31,13 @@ public class MojoMain { ...@@ -31,13 +31,13 @@ public class MojoMain {
/** /**
* Starts the specified application in the specified context. * Starts the specified application in the specified context.
**/ **/
public static void start(Context context, String appUrl) { public static void start(final String appUrl) {
nativeStart(context, appUrl); nativeStart(appUrl);
} }
/** /**
* Initializes the native system. This API should be called only once per process. * Initializes the native system. This API should be called only once per process.
**/ **/
private static native void nativeInit(Context context); private static native void nativeInit(Context context);
private static native void nativeStart(Context context, String appUrl); private static native void nativeStart(String appUrl);
}; };
...@@ -61,7 +61,7 @@ public class MojoShellActivity extends Activity { ...@@ -61,7 +61,7 @@ public class MojoShellActivity extends Activity {
} }
private void startWithURL(String url) { private void startWithURL(String url) {
MojoMain.start(this, url); MojoMain.start(url);
Log.i(TAG, "Mojo started: " + url); Log.i(TAG, "Mojo started: " + url);
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "mojo/shell/android/mojo_main.h" #include "mojo/shell/android/mojo_main.h"
#include "base/android/java_handler_thread.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/bind.h" #include "base/bind.h"
...@@ -32,6 +33,18 @@ LazyInstance<scoped_ptr<base::MessageLoop> > g_java_message_loop = ...@@ -32,6 +33,18 @@ LazyInstance<scoped_ptr<base::MessageLoop> > g_java_message_loop =
LazyInstance<scoped_ptr<shell::Context> > g_context = LazyInstance<scoped_ptr<shell::Context> > g_context =
LAZY_INSTANCE_INITIALIZER; LAZY_INSTANCE_INITIALIZER;
LazyInstance<scoped_ptr<base::android::JavaHandlerThread> > g_shell_thread =
LAZY_INSTANCE_INITIALIZER;
void RunShell(std::vector<GURL> app_urls) {
shell::Context* shell_context = new shell::Context();
shell_context->set_activity(base::android::GetApplicationContext());
shell_context->set_ui_loop(g_java_message_loop.Get().get());
g_context.Get().reset(shell_context);
shell::Run(shell_context, app_urls);
}
} // namespace } // namespace
static void Init(JNIEnv* env, jclass clazz, jobject context) { static void Init(JNIEnv* env, jclass clazz, jobject context) {
...@@ -51,7 +64,7 @@ static void Init(JNIEnv* env, jclass clazz, jobject context) { ...@@ -51,7 +64,7 @@ static void Init(JNIEnv* env, jclass clazz, jobject context) {
gfx::GLSurface::InitializeOneOff(); gfx::GLSurface::InitializeOneOff();
} }
static void Start(JNIEnv* env, jclass clazz, jobject context, jstring jurl) { static void Start(JNIEnv* env, jclass clazz, jstring jurl) {
std::vector<GURL> app_urls; std::vector<GURL> app_urls;
#if defined(MOJO_SHELL_DEBUG_URL) #if defined(MOJO_SHELL_DEBUG_URL)
app_urls.push_back(GURL(MOJO_SHELL_DEBUG_URL)); app_urls.push_back(GURL(MOJO_SHELL_DEBUG_URL));
...@@ -62,14 +75,11 @@ static void Start(JNIEnv* env, jclass clazz, jobject context, jstring jurl) { ...@@ -62,14 +75,11 @@ static void Start(JNIEnv* env, jclass clazz, jobject context, jstring jurl) {
app_urls.push_back(GURL(base::android::ConvertJavaStringToUTF8(env, jurl))); app_urls.push_back(GURL(base::android::ConvertJavaStringToUTF8(env, jurl)));
#endif #endif
base::android::ScopedJavaGlobalRef<jobject> activity; g_shell_thread.Get().reset(
activity.Reset(env, context); new base::android::JavaHandlerThread("shell_thread"));
g_shell_thread.Get()->Start();
shell::Context* shell_context = new shell::Context(); g_shell_thread.Get()->message_loop()->PostTask(
shell_context->set_activity(activity.obj()); FROM_HERE, base::Bind(&RunShell, app_urls));
g_context.Get().reset(shell_context);
shell::Run(shell_context, app_urls);
} }
bool RegisterMojoMain(JNIEnv* env) { bool RegisterMojoMain(JNIEnv* env) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "mojo/shell/in_process_dynamic_service_runner.h" #include "mojo/shell/in_process_dynamic_service_runner.h"
#include "mojo/shell/out_of_process_dynamic_service_runner.h" #include "mojo/shell/out_of_process_dynamic_service_runner.h"
#include "mojo/shell/switches.h" #include "mojo/shell/switches.h"
#include "mojo/shell/ui_service_loader_android.h"
#include "mojo/spy/spy.h" #include "mojo/spy/spy.h"
#if defined(OS_LINUX) #if defined(OS_LINUX)
...@@ -103,6 +104,14 @@ Context::Context() ...@@ -103,6 +104,14 @@ Context::Context()
// The native viewport service synchronously waits for certain messages. If we // The native viewport service synchronously waits for certain messages. If we
// don't run it on its own thread we can easily deadlock. Long term native // don't run it on its own thread we can easily deadlock. Long term native
// viewport should run its own process so that this isn't an issue. // viewport should run its own process so that this isn't an issue.
#if defined(OS_ANDROID)
service_manager_.SetLoaderForURL(
scoped_ptr<ServiceLoader>(
new UIServiceLoader(
scoped_ptr<ServiceLoader>(new NativeViewportServiceLoader(this)),
this)),
GURL("mojo:mojo_native_viewport_service"));
#else
service_manager_.SetLoaderForURL( service_manager_.SetLoaderForURL(
scoped_ptr<ServiceLoader>( scoped_ptr<ServiceLoader>(
new BackgroundServiceLoader( new BackgroundServiceLoader(
...@@ -110,6 +119,7 @@ Context::Context() ...@@ -110,6 +119,7 @@ Context::Context()
"native_viewport", "native_viewport",
base::MessageLoop::TYPE_UI)), base::MessageLoop::TYPE_UI)),
GURL("mojo:mojo_native_viewport_service")); GURL("mojo:mojo_native_viewport_service"));
#endif
#if defined(USE_AURA) #if defined(USE_AURA)
// TODO(sky): need a better way to find this. It shouldn't be linked in. // TODO(sky): need a better way to find this. It shouldn't be linked in.
service_manager_.SetLoaderForURL( service_manager_.SetLoaderForURL(
......
...@@ -38,6 +38,8 @@ class Context { ...@@ -38,6 +38,8 @@ class Context {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
jobject activity() const { return activity_.obj(); } jobject activity() const { return activity_.obj(); }
void set_activity(jobject activity) { activity_.Reset(NULL, activity); } void set_activity(jobject activity) { activity_.Reset(NULL, activity); }
base::MessageLoop* ui_loop() const { return ui_loop_; }
void set_ui_loop(base::MessageLoop* ui_loop) { ui_loop_ = ui_loop; }
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
private: private:
...@@ -49,6 +51,7 @@ class Context { ...@@ -49,6 +51,7 @@ class Context {
scoped_ptr<Spy> spy_; scoped_ptr<Spy> spy_;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
base::android::ScopedJavaGlobalRef<jobject> activity_; base::android::ScopedJavaGlobalRef<jobject> activity_;
base::MessageLoop* ui_loop_;
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
KeepAliveCounter keep_alive_counter_; KeepAliveCounter keep_alive_counter_;
......
...@@ -116,11 +116,11 @@ class DBusServiceLoader::LoadContext { ...@@ -116,11 +116,11 @@ class DBusServiceLoader::LoadContext {
// and that would be superior? // and that would be superior?
void HandleNameOwnerChanged(const std::string& old_owner, void HandleNameOwnerChanged(const std::string& old_owner,
const std::string& new_owner) { const std::string& new_owner) {
DCHECK(loader_->context_->task_runners()->ui_runner()-> DCHECK(loader_->context_->task_runners()->shell_runner()->
BelongsToCurrentThread()); BelongsToCurrentThread());
if (new_owner.empty()) { if (new_owner.empty()) {
loader_->context_->task_runners()->ui_runner()->PostTask( loader_->context_->task_runners()->shell_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&DBusServiceLoader::ForgetService, base::Bind(&DBusServiceLoader::ForgetService,
base::Unretained(loader_), url_)); base::Unretained(loader_), url_));
...@@ -165,7 +165,7 @@ void DBusServiceLoader::OnServiceError(ServiceManager* manager, ...@@ -165,7 +165,7 @@ void DBusServiceLoader::OnServiceError(ServiceManager* manager,
} }
void DBusServiceLoader::ForgetService(const GURL& url) { void DBusServiceLoader::ForgetService(const GURL& url) {
DCHECK(context_->task_runners()->ui_runner()->BelongsToCurrentThread()); DCHECK(context_->task_runners()->shell_runner()->BelongsToCurrentThread());
DVLOG(2) << "Forgetting service (url: " << url << ")"; DVLOG(2) << "Forgetting service (url: " << url << ")";
LoadContextMap::iterator it = url_to_load_context_.find(url); LoadContextMap::iterator it = url_to_load_context_.find(url);
......
...@@ -11,12 +11,12 @@ namespace mojo { ...@@ -11,12 +11,12 @@ namespace mojo {
namespace shell { namespace shell {
KeepAlive::KeepAlive(Context* context) : context_(context) { KeepAlive::KeepAlive(Context* context) : context_(context) {
DCHECK(context_->task_runners()->ui_runner()->RunsTasksOnCurrentThread()); DCHECK(context_->task_runners()->shell_runner()->RunsTasksOnCurrentThread());
++context_->keep_alive_counter()->count_; ++context_->keep_alive_counter()->count_;
} }
KeepAlive::~KeepAlive() { KeepAlive::~KeepAlive() {
DCHECK(context_->task_runners()->ui_runner()->RunsTasksOnCurrentThread()); DCHECK(context_->task_runners()->shell_runner()->RunsTasksOnCurrentThread());
if (--context_->keep_alive_counter()->count_ == 0) { if (--context_->keep_alive_counter()->count_ == 0) {
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, FROM_HERE,
......
...@@ -23,8 +23,8 @@ scoped_ptr<base::Thread> CreateIOThread(const char* name) { ...@@ -23,8 +23,8 @@ scoped_ptr<base::Thread> CreateIOThread(const char* name) {
} // namespace } // namespace
TaskRunners::TaskRunners(base::SingleThreadTaskRunner* ui_runner) TaskRunners::TaskRunners(base::SingleThreadTaskRunner* shell_runner)
: ui_runner_(ui_runner), : shell_runner_(shell_runner),
io_thread_(CreateIOThread("io_thread")), io_thread_(CreateIOThread("io_thread")),
blocking_pool_(new base::SequencedWorkerPool(kMaxBlockingPoolThreads, blocking_pool_(new base::SequencedWorkerPool(kMaxBlockingPoolThreads,
"blocking_pool")) { "blocking_pool")) {
......
...@@ -22,11 +22,11 @@ namespace shell { ...@@ -22,11 +22,11 @@ namespace shell {
// process. // process.
class TaskRunners { class TaskRunners {
public: public:
explicit TaskRunners(base::SingleThreadTaskRunner* ui_runner); explicit TaskRunners(base::SingleThreadTaskRunner* shell_runner);
~TaskRunners(); ~TaskRunners();
base::SingleThreadTaskRunner* ui_runner() const { base::SingleThreadTaskRunner* shell_runner() const {
return ui_runner_.get(); return shell_runner_.get();
} }
base::SingleThreadTaskRunner* io_runner() const { base::SingleThreadTaskRunner* io_runner() const {
...@@ -38,8 +38,7 @@ class TaskRunners { ...@@ -38,8 +38,7 @@ class TaskRunners {
} }
private: private:
// TODO(beng): should this be named shell_runner_? scoped_refptr<base::SingleThreadTaskRunner> shell_runner_;
scoped_refptr<base::SingleThreadTaskRunner> ui_runner_;
scoped_ptr<base::Thread> io_thread_; scoped_ptr<base::Thread> io_thread_;
scoped_refptr<base::SequencedWorkerPool> blocking_pool_; scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
......
// Copyright 2014 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 "mojo/shell/ui_service_loader_android.h"
#include "base/bind.h"
#include "mojo/service_manager/service_manager.h"
#include "mojo/shell/context.h"
namespace mojo {
class UIServiceLoader::UILoader {
public:
explicit UILoader(ServiceLoader* loader) : loader_(loader) {}
~UILoader() {}
void LoadService(ServiceManager* manager,
const GURL& url,
ScopedMessagePipeHandle shell_handle) {
loader_->LoadService(manager, url, shell_handle.Pass());
}
void OnServiceError(ServiceManager* manager, const GURL& url) {
loader_->OnServiceError(manager, url);
}
private:
ServiceLoader* loader_; // Owned by UIServiceLoader
DISALLOW_COPY_AND_ASSIGN(UILoader);
};
UIServiceLoader::UIServiceLoader(scoped_ptr<ServiceLoader> real_loader,
shell::Context* context)
: loader_(real_loader.Pass()), context_(context) {
}
UIServiceLoader::~UIServiceLoader() {
context_->ui_loop()->PostTask(
FROM_HERE,
base::Bind(&UIServiceLoader::ShutdownOnUIThread, base::Unretained(this)));
}
void UIServiceLoader::LoadService(ServiceManager* manager,
const GURL& url,
ScopedMessagePipeHandle shell_handle) {
context_->ui_loop()->PostTask(
FROM_HERE,
base::Bind(
&UIServiceLoader::LoadServiceOnUIThread,
base::Unretained(this),
manager,
url,
base::Owned(new ScopedMessagePipeHandle(shell_handle.Pass()))));
}
void UIServiceLoader::OnServiceError(ServiceManager* manager, const GURL& url) {
context_->ui_loop()->PostTask(
FROM_HERE,
base::Bind(&UIServiceLoader::OnServiceErrorOnUIThread,
base::Unretained(this),
manager,
url));
}
void UIServiceLoader::LoadServiceOnUIThread(
ServiceManager* manager,
const GURL& url,
ScopedMessagePipeHandle* shell_handle) {
if (!ui_loader_)
ui_loader_ = new UILoader(loader_.get());
ui_loader_->LoadService(manager, url, shell_handle->Pass());
}
void UIServiceLoader::OnServiceErrorOnUIThread(ServiceManager* manager,
const GURL& url) {
if (!ui_loader_)
ui_loader_ = new UILoader(loader_.get());
ui_loader_->OnServiceError(manager, url);
}
void UIServiceLoader::ShutdownOnUIThread() {
delete ui_loader_;
// Destroy |loader_| on the thread it's actually used on.
loader_.reset();
}
} // namespace mojo
// Copyright 2014 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.
#ifndef MOJO_SHELL_UI_SERVICE_LOADER_ANDROID_H_
#define MOJO_SHELL_UI_SERVICE_LOADER_ANDROID_H_
#include "base/memory/scoped_ptr.h"
#include "mojo/service_manager/service_loader.h"
namespace mojo {
class ServiceManager;
namespace shell {
class Context;
}
// ServiceLoader implementation that creates a background thread and issues load
// requests there.
class UIServiceLoader : public ServiceLoader {
public:
UIServiceLoader(scoped_ptr<ServiceLoader> real_loader,
shell::Context* context);
virtual ~UIServiceLoader();
// ServiceLoader overrides:
virtual void LoadService(ServiceManager* manager,
const GURL& url,
ScopedMessagePipeHandle shell_handle) OVERRIDE;
virtual void OnServiceError(ServiceManager* manager,
const GURL& url) OVERRIDE;
private:
class UILoader;
// These functions are exected on the background thread. They call through
// to |background_loader_| to do the actual loading.
// TODO: having this code take a |manager| is fragile (as ServiceManager isn't
// thread safe).
void LoadServiceOnUIThread(ServiceManager* manager,
const GURL& url,
ScopedMessagePipeHandle* shell_handle);
void OnServiceErrorOnUIThread(ServiceManager* manager, const GURL& url);
void ShutdownOnUIThread();
scoped_ptr<ServiceLoader> loader_;
shell::Context* context_;
// Lives on the UI thread. Trivial interface that calls through to |loader_|.
UILoader* ui_loader_;
DISALLOW_COPY_AND_ASSIGN(UIServiceLoader);
};
} // namespace mojo
#endif // MOJO_SHELL_UI_SERVICE_LOADER_ANDROID_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment