Use thread with looper and native message loop for vsync service.
This allows not to switch thread when communicating with the
choreographer.
This CL introduces NativeHandlerThread. This is a HandlerThread
(associated to an android Looper) that is also associated to a native
message loop to be able to receive mojo messages.
R=ppi@chromium.org
BUG=https://github.com/domokit/mojo/issues/535
Review URL: https://codereview.chromium.org/1456913002 .
diff --git a/services/vsync/src/org/chromium/mojo/vsync/VSyncProviderImpl.java b/services/vsync/src/org/chromium/mojo/vsync/VSyncProviderImpl.java
index adca2bc..3c8cc11 100644
--- a/services/vsync/src/org/chromium/mojo/vsync/VSyncProviderImpl.java
+++ b/services/vsync/src/org/chromium/mojo/vsync/VSyncProviderImpl.java
@@ -4,42 +4,21 @@
package org.chromium.mojo.vsync;
-import android.os.Handler;
-import android.os.Looper;
import android.view.Choreographer;
-import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MojoException;
-import org.chromium.mojo.system.RunLoop;
import org.chromium.mojom.vsync.VSyncProvider;
/**
* Android implementation of VSyncProvider.
*/
public class VSyncProviderImpl implements VSyncProvider, Choreographer.FrameCallback {
- private final RunLoop mRunLoop;
- private Choreographer mChoreographer;
+ private final Choreographer mChoreographer;
private AwaitVSyncResponse mCallback;
private Binding mBinding = null;
- public VSyncProviderImpl(Core core, Looper looper) {
- mRunLoop = core.getCurrentRunLoop();
- // The choreographer must be initialized on a thread with a looper.
- new Handler(looper).post(new Runnable() {
- @Override
- public void run() {
- final Choreographer choreographer = Choreographer.getInstance();
- mRunLoop.postDelayedTask(new Runnable() {
- @Override
- public void run() {
- mChoreographer = choreographer;
- if (mCallback != null) {
- mChoreographer.postFrameCallback(VSyncProviderImpl.this);
- }
- }
- }, 0);
- }
- });
+ public VSyncProviderImpl() {
+ mChoreographer = Choreographer.getInstance();
}
public void setBinding(Binding binding) {
@@ -62,20 +41,12 @@
return;
}
mCallback = callback;
- if (mChoreographer != null) {
- // Posting from another thread is allowed on a choreographer.
- mChoreographer.postFrameCallback(this);
- }
+ mChoreographer.postFrameCallback(this);
}
@Override
public void doFrame(final long frameTimeNanos) {
- mRunLoop.postDelayedTask(new Runnable() {
- @Override
- public void run() {
- mCallback.call(frameTimeNanos / 1000);
- mCallback = null;
- }
- }, 0);
+ mCallback.call(frameTimeNanos / 1000);
+ mCallback = null;
}
}
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 981df80..16d100f 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -227,6 +227,8 @@
"android/android_handler_loader.h",
"android/java_application_loader.cc",
"android/java_application_loader.h",
+ "android/native_handler_thread.cc",
+ "android/native_handler_thread.h",
"android/native_viewport_application_loader.cc",
"android/native_viewport_application_loader.h",
"android/ui_application_loader_android.cc",
@@ -291,6 +293,7 @@
"android/apk/src/org/chromium/mojo/shell/AndroidHandler.java",
"android/apk/src/org/chromium/mojo/shell/Bootstrap.java",
"android/apk/src/org/chromium/mojo/shell/JavaApplicationRegistry.java",
+ "android/apk/src/org/chromium/mojo/shell/NativeHandlerThread.java",
"android/apk/src/org/chromium/mojo/shell/ShellService.java",
"android/tests/src/org/chromium/mojo/shell/ShellTestBase.java",
]
@@ -341,6 +344,7 @@
"android/apk/src/org/chromium/mojo/shell/KeyboardFactory.java",
"android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java",
"android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java",
+ "android/apk/src/org/chromium/mojo/shell/NativeHandlerThread.java",
"android/apk/src/org/chromium/mojo/shell/NativeViewportSupportApplicationDelegate.java",
"android/apk/src/org/chromium/mojo/shell/NfcApplicationDelegate.java",
"android/apk/src/org/chromium/mojo/shell/NfcDbManager.java",
diff --git a/shell/android/android_handler.h b/shell/android/android_handler.h
index 468d824..12bba72 100644
--- a/shell/android/android_handler.h
+++ b/shell/android/android_handler.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MOJO_SHELL_ANDROID_CONTENT_HANDLER_H_
-#define MOJO_SHELL_ANDROID_CONTENT_HANDLER_H_
+#ifndef SHELL_ANDROID_ANDROID_HANDLER_H_
+#define SHELL_ANDROID_ANDROID_HANDLER_H_
#include <jni.h>
@@ -53,4 +53,4 @@
} // namespace shell
-#endif // MOJO_SHELL_ANDROID_CONTENT_HANDLER_H_
+#endif // SHELL_ANDROID_ANDROID_HANDLER_H_
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/JavaApplicationRegistry.java b/shell/android/apk/src/org/chromium/mojo/shell/JavaApplicationRegistry.java
index 67241c1..49b5ff3 100644
--- a/shell/android/apk/src/org/chromium/mojo/shell/JavaApplicationRegistry.java
+++ b/shell/android/apk/src/org/chromium/mojo/shell/JavaApplicationRegistry.java
@@ -33,7 +33,7 @@
public class JavaApplicationRegistry {
private final Map<String, ApplicationDelegate> mApplicationDelegateMap = new HashMap<>();
// Thread with a Looper required to get callbacks from the android framework..
- private final HandlerThread mHandlerThread = new HandlerThread("FrameworkThread");
+ private final HandlerThread mHandlerThread = new NativeHandlerThread("FrameworkThread");
private static final class ApplicationRunnable implements Runnable {
private final ApplicationDelegate mApplicationDelegate;
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/NativeHandlerThread.java b/shell/android/apk/src/org/chromium/mojo/shell/NativeHandlerThread.java
new file mode 100644
index 0000000..334372e
--- /dev/null
+++ b/shell/android/apk/src/org/chromium/mojo/shell/NativeHandlerThread.java
@@ -0,0 +1,54 @@
+// 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.
+
+package org.chromium.mojo.shell;
+
+import android.os.HandlerThread;
+
+import org.chromium.base.JNINamespace;
+
+/**
+ * Handler thread associated with a native message loop.
+ */
+@JNINamespace("shell")
+public class NativeHandlerThread extends HandlerThread {
+ // The native message loop.
+ private long mNativeMessageLoop = 0;
+
+ /**
+ * Constructor.
+ */
+ public NativeHandlerThread(String name) {
+ super(name);
+ }
+
+ /**
+ * @see HandlerThread#run()
+ */
+ @Override
+ public void run() {
+ try {
+ super.run();
+ } finally {
+ if (mNativeMessageLoop != 0) {
+ nativeDeleteMessageLoop(mNativeMessageLoop);
+ }
+ }
+ }
+
+ /**
+ * @see HandlerThread#onLooperPrepared()
+ */
+ @Override
+ protected void onLooperPrepared() {
+ if (mNativeMessageLoop == 0) {
+ mNativeMessageLoop = nativeCreateMessageLoop();
+ }
+ super.onLooperPrepared();
+ }
+
+ native long nativeCreateMessageLoop();
+
+ native void nativeDeleteMessageLoop(long messageLoop);
+}
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/VsyncFactory.java b/shell/android/apk/src/org/chromium/mojo/shell/VsyncFactory.java
index b159ce2..c050af3 100644
--- a/shell/android/apk/src/org/chromium/mojo/shell/VsyncFactory.java
+++ b/shell/android/apk/src/org/chromium/mojo/shell/VsyncFactory.java
@@ -4,11 +4,11 @@
package org.chromium.mojo.shell;
+import android.os.Handler;
import android.os.Looper;
import org.chromium.mojo.application.ServiceFactoryBinder;
import org.chromium.mojo.bindings.InterfaceRequest;
-import org.chromium.mojo.system.impl.CoreImpl;
import org.chromium.mojo.vsync.VSyncProviderImpl;
import org.chromium.mojom.vsync.VSyncProvider;
@@ -16,16 +16,21 @@
* A ServiceFactoryBinder for the vsync service.
*/
final class VsyncFactory implements ServiceFactoryBinder<VSyncProvider> {
- private final Looper mLooper;
+ private final Handler mHandler;
public VsyncFactory(Looper looper) {
- mLooper = looper;
+ mHandler = new Handler(looper);
}
@Override
- public void bind(InterfaceRequest<VSyncProvider> request) {
- VSyncProviderImpl implementation = new VSyncProviderImpl(CoreImpl.getInstance(), mLooper);
- implementation.setBinding(VSyncProvider.MANAGER.bind(implementation, request));
+ public void bind(final InterfaceRequest<VSyncProvider> request) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ VSyncProviderImpl implementation = new VSyncProviderImpl();
+ implementation.setBinding(VSyncProvider.MANAGER.bind(implementation, request));
+ }
+ });
}
@Override
diff --git a/shell/android/library_loader.cc b/shell/android/library_loader.cc
index 4c4f38a..7a4f870 100644
--- a/shell/android/library_loader.cc
+++ b/shell/android/library_loader.cc
@@ -13,6 +13,7 @@
#include "shell/android/android_handler.h"
#include "shell/android/java_application_loader.h"
#include "shell/android/main.h"
+#include "shell/android/native_handler_thread.h"
namespace {
@@ -21,10 +22,11 @@
{"Core", mojo::android::RegisterCoreImpl},
{"BaseRunLoop", mojo::android::RegisterBaseRunLoop},
{"AndroidHandler", shell::RegisterAndroidHandlerJni},
+ {"JavaApplicationLoader", shell::JavaApplicationLoader::RegisterJni},
+ {"NativeHandlerThread", shell::RegisterNativeHandlerThreadJni},
{"PlatformViewportAndroid",
native_viewport::PlatformViewportAndroid::Register},
{"ShellService", shell::RegisterShellService},
- {"JavaApplicationLoader", shell::JavaApplicationLoader::RegisterJni},
};
bool RegisterJNI(JNIEnv* env) {
diff --git a/shell/android/native_handler_thread.cc b/shell/android/native_handler_thread.cc
new file mode 100644
index 0000000..9d1df59
--- /dev/null
+++ b/shell/android/native_handler_thread.cc
@@ -0,0 +1,28 @@
+// 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 "shell/android/native_handler_thread.h"
+
+#include "base/message_loop/message_loop.h"
+#include "jni/NativeHandlerThread_jni.h"
+
+namespace shell {
+
+jlong CreateMessageLoop(JNIEnv* env, jobject jcaller) {
+ scoped_ptr<base::MessageLoop> loop(new base::MessageLoopForUI);
+ base::MessageLoopForUI::current()->Start();
+ return reinterpret_cast<intptr_t>(loop.release());
+}
+
+void DeleteMessageLoop(JNIEnv* env, jobject jcaller, jlong message_loop) {
+ scoped_ptr<base::MessageLoop> loop(
+ reinterpret_cast<base::MessageLoop*>(message_loop));
+ loop->QuitNow();
+}
+
+bool RegisterNativeHandlerThreadJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace shell
diff --git a/shell/android/native_handler_thread.h b/shell/android/native_handler_thread.h
new file mode 100644
index 0000000..a953a9c
--- /dev/null
+++ b/shell/android/native_handler_thread.h
@@ -0,0 +1,16 @@
+// 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.
+
+#ifndef SHELL_ANDROID_NATIVE_HANDLER_THREAD_H_
+#define SHELL_ANDROID_NATIVE_HANDLER_THREAD_H_
+
+#include <jni.h>
+
+namespace shell {
+
+bool RegisterNativeHandlerThreadJni(JNIEnv* env);
+
+} // namespace shell
+
+#endif // SHELL_ANDROID_NATIVE_HANDLER_THREAD_H_