summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authormichaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 16:11:16 +0000
committermichaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 16:11:16 +0000
commit61c86c6a23ab32e81337f66f1b958d8ec3e8bd45 (patch)
tree64f18cd34be5ad9ec1140c3e334f5483af8af462 /base
parenteccefee0229e222c0130dca22412b4dccfa3f181 (diff)
downloadchromium_src-61c86c6a23ab32e81337f66f1b958d8ec3e8bd45.zip
chromium_src-61c86c6a23ab32e81337f66f1b958d8ec3e8bd45.tar.gz
chromium_src-61c86c6a23ab32e81337f66f1b958d8ec3e8bd45.tar.bz2
Android's paths and message loop implementation with JNI
BUG= TEST= Review URL: http://codereview.chromium.org/7518032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95085 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/DEPS1
-rw-r--r--base/android/jni_android.cc69
-rw-r--r--base/android/jni_android.h45
-rw-r--r--base/android/jni_array.cc52
-rw-r--r--base/android/jni_array.h25
-rw-r--r--base/android/jni_string.cc44
-rw-r--r--base/android/jni_string.h31
-rw-r--r--base/android/path_utils.cc39
-rw-r--r--base/android/path_utils.h29
-rw-r--r--base/base_paths.h3
-rw-r--r--base/base_paths_android.cc28
-rw-r--r--base/message_loop.cc37
-rw-r--r--base/message_loop.h22
-rw-r--r--base/message_pump_android.cc147
-rw-r--r--base/message_pump_android.h38
-rw-r--r--base/threading/platform_thread_posix.cc9
16 files changed, 598 insertions, 21 deletions
diff --git a/base/DEPS b/base/DEPS
index 790e939..81e9cda 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+jni",
"+third_party/ashmem",
"+third_party/apple_apsl",
"+third_party/libevent",
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
new file mode 100644
index 0000000..05df348
--- /dev/null
+++ b/base/android/jni_android.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 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 "base/android/jni_android.h"
+
+#include "base/android/auto_jobject.h"
+#include "base/logging.h"
+
+namespace {
+JavaVM* g_jvm = 0;
+jobject g_application_context = NULL;
+}
+
+namespace base {
+namespace android {
+
+JNIEnv* AttachCurrentThread() {
+ if (!g_jvm)
+ return NULL;
+
+ JNIEnv* env = NULL;
+ jint ret = g_jvm->AttachCurrentThread(&env, NULL);
+ DCHECK_EQ(ret, JNI_OK);
+ return env;
+}
+
+void DetachFromVM() {
+ // Ignore the return value, if the thread is not attached, DetachCurrentThread
+ // will fail. But it is ok as the native thread may never be attached.
+ if (g_jvm)
+ g_jvm->DetachCurrentThread();
+}
+
+void InitVM(JavaVM* vm) {
+ DCHECK(!g_jvm);
+ g_jvm = vm;
+}
+
+void InitApplicationContext(jobject context) {
+ DCHECK(!g_application_context);
+ g_application_context = context;
+}
+
+jobject GetApplicationContext() {
+ DCHECK(g_application_context);
+ return g_application_context;
+}
+
+jmethodID GetMethodID(JNIEnv* env,
+ jclass clazz,
+ const char* const method,
+ const char* const jni_signature) {
+ jmethodID id = env->GetMethodID(clazz, method, jni_signature);
+ DCHECK(id) << method;
+ CheckException(env);
+ return id;
+}
+
+bool CheckException(JNIEnv* env) {
+ if (env->ExceptionCheck() == JNI_FALSE)
+ return false;
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return true;
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
new file mode 100644
index 0000000..0e34724
--- /dev/null
+++ b/base/android/jni_android.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 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 BASE_ANDROID_JNI_ANDROID_H_
+#define BASE_ANDROID_JNI_ANDROID_H_
+
+#include <jni.h>
+#include <sys/types.h>
+
+namespace base {
+namespace android {
+
+// Attach the current thread to the VM (if necessary) and return the JNIEnv*.
+JNIEnv* AttachCurrentThread();
+
+// Detach the current thread from VM if it is attached.
+void DetachFromVM();
+
+// Initializes the global JVM. It is not necessarily called before
+// InitApplicationContext().
+void InitVM(JavaVM* vm);
+
+// Initializes the global application context object. The |context| should be
+// the global reference of application context object. It is not necessarily
+// called after InitVM().
+// TODO: We might combine InitVM() and InitApplicationContext() into one method.
+void InitApplicationContext(jobject context);
+
+jobject GetApplicationContext();
+
+// Get the method ID for a method. Will clear the pending Java
+// exception and return 0 if the method is not found.
+jmethodID GetMethodID(JNIEnv* env,
+ jclass clazz,
+ const char* const method,
+ const char* const jni_signature);
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+// If an exception is pending, it is printed.
+bool CheckException(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+#endif
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
new file mode 100644
index 0000000..9555abc
--- /dev/null
+++ b/base/android/jni_array.cc
@@ -0,0 +1,52 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: michaelbai@google.com (Tao Bai)
+
+#include "base/android/jni_array.h"
+
+#include "base/android/auto_jobject.h"
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+
+jbyteArray ToJavaByteArray(JNIEnv* env,
+ const unsigned char* bytes,
+ size_t len) {
+ jbyteArray byte_array = env->NewByteArray(len);
+ if (!byte_array) {
+ return NULL;
+ }
+
+ jbyte* elements = env->GetByteArrayElements(byte_array, NULL);
+ DCHECK(elements);
+ memcpy(elements, bytes, len);
+ env->ReleaseByteArrayElements(byte_array, elements, 0);
+ CheckException(env);
+
+ return byte_array;
+}
+
+jobjectArray ToJavaArrayOfByteArray(JNIEnv* env,
+ const std::vector<std::string>& v) {
+ size_t count = v.size();
+ DCHECK_GT(count, 0U);
+ jclass byte_array_class = env->FindClass("[B");
+ jobjectArray joa = env->NewObjectArray(count, byte_array_class, NULL);
+ if (joa == NULL)
+ return NULL;
+
+ for (size_t i = 0; i < count; ++i) {
+ AutoJObject byte_array = AutoJObject::FromLocalRef(env, ToJavaByteArray(env,
+ reinterpret_cast<const uint8*>(v[i].data()), v[i].length()));
+ if (!byte_array.obj()) {
+ env->DeleteLocalRef(joa);
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, i, byte_array.obj());
+ }
+ return joa;
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
new file mode 100644
index 0000000..ad73256
--- /dev/null
+++ b/base/android/jni_array.h
@@ -0,0 +1,25 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: michaelbai@google.com (Tao Bai)
+
+
+#ifndef BASE_ANDROID_JNI_ARRAY_H_
+#define BASE_ANDROID_JNI_ARRAY_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+namespace base {
+namespace android {
+
+// Returns a new Java byte array converted from the given bytes array.
+jbyteArray ToJavaByteArray(JNIEnv* env, const unsigned char* bytes, size_t len);
+
+// Returns a array of Java byte array converted from |v|.
+jobjectArray ToJavaArrayOfByteArray(JNIEnv* env,
+ const std::vector<std::string>& v);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
new file mode 100644
index 0000000..3f3ba82
--- /dev/null
+++ b/base/android/jni_string.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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 "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+namespace android {
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+ // JNI's GetStringUTFChars() returns strings in Java-modified UTF8, so we
+ // instead get the String in UTF16 and convert using our own utility function.
+ return UTF16ToUTF8(ConvertJavaStringToUTF16(env, str));
+}
+
+jstring ConvertUTF8ToJavaString(JNIEnv* env, const std::string& str) {
+ jstring result = env->NewStringUTF(str.c_str());
+ CheckException(env);
+ return result;
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+ const jchar* chars = env->GetStringChars(str, NULL);
+ DCHECK(chars);
+ // GetStringChars isn't required to NULL-terminate the strings
+ // it returns, so the length must be explicitly checked.
+ string16 result(chars, env->GetStringLength(str));
+ env->ReleaseStringChars(str, chars);
+ CheckException(env);
+ return result;
+}
+
+jstring ConvertUTF16ToJavaString(JNIEnv* env, const string16& str) {
+ jstring result = env->NewString(str.data(), str.length());
+ CheckException(env);
+ return result;
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
new file mode 100644
index 0000000..7e45154
--- /dev/null
+++ b/base/android/jni_string.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 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 BASE_ANDROID_JNI_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/string16.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+
+// Convert a std string to Java string.
+jstring ConvertUTF8ToJavaString(JNIEnv* env, const std::string& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+
+// Convert a string16 to a Java string.
+jstring ConvertUTF16ToJavaString(JNIEnv* env, const string16& str);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_STRING_H_
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
new file mode 100644
index 0000000..b3065d57
--- /dev/null
+++ b/base/android/path_utils.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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 "base/android/path_utils.h"
+
+#include "base/android/auto_jobject.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+
+#include "jni/path_utils_jni.h"
+
+namespace base {
+namespace android {
+
+std::string GetDataDirectory() {
+ JNIEnv* env = AttachCurrentThread();
+ AutoJObject path = AutoJObject::FromLocalRef(
+ env, Java_PathUtils_getDataDirectory(
+ env, base::android::GetApplicationContext()));
+ return base::android::ConvertJavaStringToUTF8(
+ env, static_cast<jstring>(path.obj()));
+}
+
+std::string GetCacheDirectory() {
+ JNIEnv* env = AttachCurrentThread();
+ AutoJObject path = AutoJObject::FromLocalRef(
+ env, Java_PathUtils_getCacheDirectory(
+ env, base::android::GetApplicationContext()));
+ return base::android::ConvertJavaStringToUTF8(
+ env, static_cast<jstring>(path.obj()));
+}
+
+bool RegisterPathUtils(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
new file mode 100644
index 0000000..8015ed9
--- /dev/null
+++ b/base/android/path_utils.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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 BASE_ANDROID_PATH_UTILS_H_
+#define BASE_ANDROID_PATH_UTILS_H_
+
+#include <jni.h>
+#include <string>
+
+namespace base {
+namespace android {
+
+// Return the absolute path to the data directory of the current application.
+// This method is dedicated for base_paths_android.c, Using
+// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir.
+std::string GetDataDirectory();
+
+// Return the absolute path to the cache directory. This method is dedicated for
+// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the
+// cache dir.
+std::string GetCacheDirectory();
+
+bool RegisterPathUtils(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_PATH_UTILS_H_
diff --git a/base/base_paths.h b/base/base_paths.h
index 3c3c8ed..f724c3f 100644
--- a/base/base_paths.h
+++ b/base/base_paths.h
@@ -40,6 +40,9 @@ enum {
// This is $XDG_CACHE_HOME on Linux and
// ~/Library/Caches on Mac.
#endif
+#if defined(OS_ANDROID)
+ DIR_ANDROID_APP_DATA, // Directory where to put android app's data.
+#endif
PATH_END
};
diff --git a/base/base_paths_android.cc b/base/base_paths_android.cc
index 5a03cc0..9d04b76 100644
--- a/base/base_paths_android.cc
+++ b/base/base_paths_android.cc
@@ -6,13 +6,19 @@
#include <unistd.h>
+#include "base/android/jni_android.h"
+#include "base/android/path_utils.h"
+#include "base/file_path.h"
#include "base/logging.h"
-#include "base/android_os.h"
-namespace base {
+namespace {
const char kSelfExe[] = "/proc/self/exe";
+} // namespace
+
+namespace base {
+
bool PathProviderAndroid(int key, FilePath* result) {
switch (key) {
case base::FILE_EXE: {
@@ -27,14 +33,12 @@ bool PathProviderAndroid(int key, FilePath* result) {
return true;
}
case base::FILE_MODULE:
- // TODO(port): Find out whether we can use dladdr to implement this, and
- // then use DIR_MODULE's default implementation in base_file.cc.
+ // dladdr didn't work in Android as only the file name was returned.
NOTIMPLEMENTED();
return false;
case base::DIR_MODULE: {
- AndroidOS* aos = AndroidOS::GetSharedInstance();
- DCHECK(aos);
- *result = aos->GetLibDirectory();
+ *result = FilePath(base::android::GetDataDirectory()).DirName()
+ .Append("lib");
return true;
}
case base::DIR_SOURCE_ROOT:
@@ -42,12 +46,12 @@ bool PathProviderAndroid(int key, FilePath* result) {
// to the device via test script.
*result = FilePath(FILE_PATH_LITERAL("/data/local/tmp/"));
return true;
- case base::DIR_CACHE: {
- AndroidOS* aos = AndroidOS::GetSharedInstance();
- DCHECK(aos);
- *result = aos->GetCacheDirectory();
+ case base::DIR_CACHE:
+ *result = FilePath(base::android::GetCacheDirectory());
+ return true;
+ case base::DIR_ANDROID_APP_DATA:
+ *result = FilePath(base::android::GetDataDirectory());
return true;
- }
default:
// Note: the path system expects this function to override the default
// behavior. So no need to log an error if we don't support a given
diff --git a/base/message_loop.cc b/base/message_loop.cc
index e3f6ea3..9cef7bf 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -25,8 +25,10 @@
#if defined(OS_POSIX)
#include "base/message_pump_libevent.h"
#endif
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_ANDROID)
+#include "base/message_pump_android.h"
+#endif
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#if defined(TOUCH_UI)
@@ -85,6 +87,8 @@ const base::LinearHistogram::DescriptionPair event_descriptions_[] = {
bool enable_histogrammer_ = false;
+MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
+
} // namespace
//------------------------------------------------------------------------------
@@ -143,6 +147,9 @@ MessageLoop::MessageLoop(Type type)
#elif defined(OS_MACOSX)
#define MESSAGE_PUMP_UI base::MessagePumpMac::Create()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
+#elif defined(OS_ANDROID)
+#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
+#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
#elif defined(TOUCH_UI)
#define MESSAGE_PUMP_UI new base::MessagePumpX()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
@@ -159,7 +166,10 @@ MessageLoop::MessageLoop(Type type)
#endif
if (type_ == TYPE_UI) {
- pump_ = MESSAGE_PUMP_UI;
+ if (message_pump_for_ui_factory_)
+ pump_ = message_pump_for_ui_factory_();
+ else
+ pump_ = MESSAGE_PUMP_UI;
} else if (type_ == TYPE_IO) {
pump_ = MESSAGE_PUMP_IO;
} else {
@@ -221,6 +231,12 @@ void MessageLoop::EnableHistogrammer(bool enable) {
enable_histogrammer_ = enable;
}
+// static
+void MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
+ DCHECK(!message_pump_for_ui_factory_);
+ message_pump_for_ui_factory_ = factory;
+}
+
void MessageLoop::AddDestructionObserver(
DestructionObserver* destruction_observer) {
DCHECK_EQ(this, current());
@@ -410,7 +426,7 @@ void MessageLoop::RunInternal() {
StartHistogrammer();
-#if !defined(OS_MACOSX)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
if (state_->dispatcher && type() == TYPE_UI) {
static_cast<base::MessagePumpForUI*>(pump_.get())->
RunWithDispatcher(this, state_->dispatcher);
@@ -724,7 +740,7 @@ MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
// Initialize the other fields:
quit_received = false;
-#if !defined(OS_MACOSX)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
dispatcher = NULL;
#endif
}
@@ -780,7 +796,14 @@ void MessageLoopForUI::DidProcessMessage(const MSG& message) {
}
#endif // defined(OS_WIN)
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
+#if defined(OS_ANDROID)
+void MessageLoopForUI::Start() {
+ // No Histogram support for UI message loop as it is managed by Java side
+ static_cast<base::MessagePumpForUI*>(pump_.get())->Start(this);
+}
+#endif
+
+#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
void MessageLoopForUI::AddObserver(Observer* observer) {
pump_ui()->AddObserver(observer);
}
@@ -794,7 +817,7 @@ void MessageLoopForUI::Run(Dispatcher* dispatcher) {
state_->dispatcher = dispatcher;
RunHandler();
}
-#endif // !defined(OS_MACOSX) && !defined(OS_NACL)
+#endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
//------------------------------------------------------------------------------
// MessageLoopForIO
diff --git a/base/message_loop.h b/base/message_loop.h
index 9d500d7..540c74d 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -115,6 +115,11 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
static void EnableHistogrammer(bool enable_histogrammer);
+ typedef base::MessagePump* (MessagePumpFactory)();
+ // Using the given base::MessagePumpForUIFactory to override the default
+ // MessagePump implementation for 'TYPE_UI'.
+ static void InitMessagePumpForUIFactory(MessagePumpFactory* factory);
+
// A DestructionObserver is notified when the current MessageLoop is being
// destroyed. These obsevers are notified prior to MessageLoop::current()
// being changed to return NULL. This gives interested parties the chance to
@@ -368,11 +373,16 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
// once it becomes idle.
bool quit_received;
-#if !defined(OS_MACOSX)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
Dispatcher* dispatcher;
#endif
};
+#if defined(OS_ANDROID)
+ // Android Java process manages the UI thread message loop. So its
+ // MessagePumpForUI needs to keep the RunState.
+ public:
+#endif
class BASE_API AutoRunState : RunState {
public:
explicit AutoRunState(MessageLoop* loop);
@@ -381,6 +391,9 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
MessageLoop* loop_;
RunState* previous_state_;
};
+#if defined(OS_ANDROID)
+ protected:
+#endif
// This structure is copied around by value.
struct PendingTask {
@@ -583,7 +596,12 @@ class BASE_API MessageLoopForUI : public MessageLoop {
void DidProcessMessage(const MSG& message);
#endif // defined(OS_WIN)
-#if !defined(OS_MACOSX)
+#if defined(OS_ANDROID)
+ // On Android, the UI message loop is handled by Java side. So Run() should
+ // never be called. Instead use Start(), which will forward all the native UI
+ // events to the Java message loop.
+ void Start();
+#elif !defined(OS_MACOSX)
// Please see message_pump_win/message_pump_glib for definitions of these
// methods.
void AddObserver(Observer* observer);
diff --git a/base/message_pump_android.cc b/base/message_pump_android.cc
new file mode 100644
index 0000000..d9fdf9c
--- /dev/null
+++ b/base/message_pump_android.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2011 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 "base/message_pump_android.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "jni/system_message_handler_jni.h"
+
+using base::android::AutoJObject;
+
+namespace {
+
+const char* kClassPathName = "com/android/chromeview/base/SystemMessageHandler";
+
+jobject g_system_message_handler_obj = NULL;
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+// Native JNI methods called by Java.
+// ----------------------------------------------------------------------------
+// This method can not move to anonymous namespace as it has been declared as
+// 'static' in system_message_handler_jni.h.
+static jboolean DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) {
+ base::MessagePump::Delegate* delegate =
+ reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
+ DCHECK(delegate);
+ // This is based on MessagePumpForUI::DoRunLoop() from desktop.
+ // Note however that our system queue is handled in the java side.
+ // In desktop we inspect and process a single system message and then
+ // we call DoWork() / DoDelayedWork().
+ // On Android, the java message queue may contain messages for other handlers
+ // that will be processed before calling here again.
+ bool more_work_is_plausible = delegate->DoWork();
+
+ // This is the time when we need to do delayed work.
+ base::TimeTicks delayed_work_time;
+ more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time);
+
+ // This is a major difference between android and other platforms: since we
+ // can't inspect it and process just one single message, instead we'll yeld
+ // the callstack, and post a message to call us back soon.
+ if (more_work_is_plausible)
+ return true;
+
+ more_work_is_plausible = delegate->DoIdleWork();
+ if (!more_work_is_plausible && !delayed_work_time.is_null()) {
+ // We only set the timer here as returning true would post a message.
+ jlong millis =
+ (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
+ Java_SystemMessageHandler_setDelayedTimer(env, obj, millis);
+ base::android::CheckException(env);
+ }
+ return more_work_is_plausible;
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+ : state_(NULL) {
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+ NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
+ " test_stub_android.h";
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+ state_ = new MessageLoop::AutoRunState(MessageLoop::current());
+
+ DCHECK(!g_system_message_handler_obj);
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ jclass clazz = env->FindClass(kClassPathName);
+ DCHECK(!clazz);
+
+ jmethodID constructor = base::android::GetMethodID(env, clazz, "<init>",
+ "(I)V");
+ AutoJObject client = AutoJObject::FromLocalRef(
+ env, env->NewObject(clazz, constructor, delegate));
+ DCHECK(!client.obj());
+
+ g_system_message_handler_obj = env->NewGlobalRef(client.obj());
+
+ base::android::CheckException(env);
+}
+
+void MessagePumpForUI::Quit() {
+ if (g_system_message_handler_obj) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ Java_SystemMessageHandler_removeTimer(env, g_system_message_handler_obj);
+ env->DeleteGlobalRef(g_system_message_handler_obj);
+ base::android::CheckException(env);
+ g_system_message_handler_obj = NULL;
+ }
+
+ if (state_) {
+ delete state_;
+ state_ = NULL;
+ }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ if (!g_system_message_handler_obj)
+ return;
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ Java_SystemMessageHandler_setTimer(env, g_system_message_handler_obj);
+ base::android::CheckException(env);
+
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ if (!g_system_message_handler_obj)
+ return;
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+
+ jlong millis =
+ (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
+ // Note that we're truncating to milliseconds as required by the java side,
+ // even though delayed_work_time is microseconds resolution.
+ Java_SystemMessageHandler_setDelayedTimer(env, g_system_message_handler_obj,
+ millis);
+ base::android::CheckException(env);
+}
+
+// Register native methods
+bool RegisterSystemMessageHandler(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace base
diff --git a/base/message_pump_android.h b/base/message_pump_android.h
new file mode 100644
index 0000000..7310db6
--- /dev/null
+++ b/base/message_pump_android.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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 BASE_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_PUMP_ANDROID_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/message_pump.h"
+#include "base/time.h"
+
+namespace base {
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_ANDROID platform.
+class MessagePumpForUI : public MessagePump {
+ public:
+ MessagePumpForUI();
+ virtual ~MessagePumpForUI();
+
+ virtual void Run(Delegate* delegate) OVERRIDE;
+ virtual void Quit() OVERRIDE;
+ virtual void ScheduleWork() OVERRIDE;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE;
+
+ virtual void Start(Delegate* delegate);
+
+ private:
+ MessageLoop::AutoRunState* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_ANDROID_H_
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 497acb5..baa3ab1 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -25,6 +25,10 @@
#include <unistd.h>
#endif
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif
+
#if defined(OS_NACL)
#include <sys/nacl_syscalls.h>
#endif
@@ -49,6 +53,9 @@ void* ThreadFunc(void* params) {
base::ThreadRestrictions::SetSingletonAllowed(false);
delete thread_params;
delegate->ThreadMain();
+#if defined(OS_ANDROID)
+ base::android::DetachFromVM();
+#endif
return NULL;
}
@@ -124,6 +131,8 @@ PlatformThreadId PlatformThread::CurrentId() {
return mach_thread_self();
#elif defined(OS_LINUX)
return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+ return gettid();
#elif defined(OS_FREEBSD)
// TODO(BSD): find a better thread ID
return reinterpret_cast<int64>(pthread_self());