diff options
-rw-r--r-- | base/DEPS | 1 | ||||
-rw-r--r-- | base/android/jni_android.cc | 69 | ||||
-rw-r--r-- | base/android/jni_android.h | 45 | ||||
-rw-r--r-- | base/android/jni_array.cc | 52 | ||||
-rw-r--r-- | base/android/jni_array.h | 25 | ||||
-rw-r--r-- | base/android/jni_string.cc | 44 | ||||
-rw-r--r-- | base/android/jni_string.h | 31 | ||||
-rw-r--r-- | base/android/path_utils.cc | 39 | ||||
-rw-r--r-- | base/android/path_utils.h | 29 | ||||
-rw-r--r-- | base/base_paths.h | 3 | ||||
-rw-r--r-- | base/base_paths_android.cc | 28 | ||||
-rw-r--r-- | base/message_loop.cc | 37 | ||||
-rw-r--r-- | base/message_loop.h | 22 | ||||
-rw-r--r-- | base/message_pump_android.cc | 147 | ||||
-rw-r--r-- | base/message_pump_android.h | 38 | ||||
-rw-r--r-- | base/threading/platform_thread_posix.cc | 9 |
16 files changed, 598 insertions, 21 deletions
@@ -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()); |