diff options
author | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-26 17:00:54 +0000 |
---|---|---|
committer | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-26 17:00:54 +0000 |
commit | 8e7415e446a2379aecead2903cbc96a34e02fe98 (patch) | |
tree | 95523928701276fdc2acfe4c0611daa4170bd3f1 /content/browser/renderer_host/java | |
parent | d29242852b7ed8e2009fd1641a53ef213c48065b (diff) | |
download | chromium_src-8e7415e446a2379aecead2903cbc96a34e02fe98.zip chromium_src-8e7415e446a2379aecead2903cbc96a34e02fe98.tar.gz chromium_src-8e7415e446a2379aecead2903cbc96a34e02fe98.tar.bz2 |
Android: cleanup jni_android to minimize external dependencies.
Other projects will be using the JNI bindings.
- Move GetMethodIDFromClassName down to content/browser/renderer_host/java,
the only place where it's used.
- Remove a few methods that are no longer in use.
- Trim down dependencies.
BUG=
Review URL: https://codereview.chromium.org/23835020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225471 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host/java')
5 files changed, 222 insertions, 2 deletions
diff --git a/content/browser/renderer_host/java/java_bound_object.cc b/content/browser/renderer_host/java/java_bound_object.cc index 4199cca..27b9f42 100644 --- a/content/browser/renderer_host/java/java_bound_object.cc +++ b/content/browser/renderer_host/java/java_bound_object.cc @@ -11,6 +11,7 @@ #include "base/strings/stringprintf.h" #include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h" #include "content/browser/renderer_host/java/java_type.h" +#include "content/browser/renderer_host/java/jni_helper.h" #include "content/public/browser/browser_thread.h" #include "third_party/WebKit/public/web/WebBindings.h" @@ -18,7 +19,6 @@ using base::StringPrintf; using base::android::AttachCurrentThread; using base::android::ConvertUTF8ToJavaString; using base::android::GetClass; -using base::android::GetMethodIDFromClassName; using base::android::JavaRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; diff --git a/content/browser/renderer_host/java/java_method.cc b/content/browser/renderer_host/java/java_method.cc index 3cc569f..ef2d097 100644 --- a/content/browser/renderer_host/java/java_method.cc +++ b/content/browser/renderer_host/java/java_method.cc @@ -9,11 +9,11 @@ #include "base/lazy_instance.h" #include "base/memory/singleton.h" #include "base/strings/string_util.h" // For ReplaceSubstringsAfterOffset +#include "content/browser/renderer_host/java/jni_helper.h" using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF8; using base::android::GetClass; -using base::android::GetMethodIDFromClassName; using base::android::MethodID; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; diff --git a/content/browser/renderer_host/java/jni_helper.cc b/content/browser/renderer_host/java/jni_helper.cc new file mode 100644 index 0000000..86874b0 --- /dev/null +++ b/content/browser/renderer_host/java/jni_helper.cc @@ -0,0 +1,99 @@ +// Copyright 2013 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/browser/renderer_host/java/jni_helper.h" + +#include <map> + +#include "base/android/jni_android.h" +#include "base/lazy_instance.h" +#include "base/threading/platform_thread.h" + +namespace content { + +namespace { + +struct MethodIdentifier { + const char* class_name; + const char* method; + const char* jni_signature; + + bool operator<(const MethodIdentifier& other) const { + int r = strcmp(class_name, other.class_name); + if (r < 0) { + return true; + } else if (r > 0) { + return false; + } + + r = strcmp(method, other.method); + if (r < 0) { + return true; + } else if (r > 0) { + return false; + } + + return strcmp(jni_signature, other.jni_signature) < 0; + } +}; + +typedef std::map<MethodIdentifier, jmethodID> MethodIDMap; + +const base::subtle::AtomicWord kUnlocked = 0; +const base::subtle::AtomicWord kLocked = 1; +base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; + +base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +jmethodID GetMethodIDFromClassName(JNIEnv* env, + const char* class_name, + const char* method, + const char* jni_signature) { + MethodIdentifier key; + key.class_name = class_name; + key.method = method; + key.jni_signature = jni_signature; + + MethodIDMap* map = g_method_id_map.Pointer(); + bool found = false; + + while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, + kUnlocked, + kLocked) != kUnlocked) { + base::PlatformThread::YieldCurrentThread(); + } + MethodIDMap::const_iterator iter = map->find(key); + if (iter != map->end()) { + found = true; + } + base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); + + // Addition to the map does not invalidate this iterator. + if (found) { + return iter->second; + } + + base::android::ScopedJavaLocalRef<jclass> clazz( + env, env->FindClass(class_name)); + jmethodID id = base::android::MethodID::Get< + base::android::MethodID::TYPE_INSTANCE>( + env, clazz.obj(), method, jni_signature); + + while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, + kUnlocked, + kLocked) != kUnlocked) { + base::PlatformThread::YieldCurrentThread(); + } + // Another thread may have populated the map already. + std::pair<MethodIDMap::const_iterator, bool> result = + map->insert(std::make_pair(key, id)); + DCHECK_EQ(id, result.first->second); + base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); + + return id; +} + +} // namespace content diff --git a/content/browser/renderer_host/java/jni_helper.h b/content/browser/renderer_host/java/jni_helper.h new file mode 100644 index 0000000..aaba53b --- /dev/null +++ b/content/browser/renderer_host/java/jni_helper.h @@ -0,0 +1,27 @@ +// Copyright 2013 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 CONTENT_BROWSER_RENDERER_HOST_JAVA_JNI_HELPER_H_ +#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JNI_HELPER_H_ + +#include <jni.h> + +#include "content/common/content_export.h" + +namespace content { + +// Gets the method ID from the class name. Clears the pending Java exception +// and returns NULL if the method is not found. Caches results. +// Strings passed to this function are held in the cache and MUST remain valid +// beyond the duration of all future calls to this function, across all +// threads. In practice, this means that the function should only be used with +// string constants. +CONTENT_EXPORT jmethodID GetMethodIDFromClassName(JNIEnv* env, + const char* class_name, + const char* method, + const char* jni_signature); + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JNI_HELPER_H_ diff --git a/content/browser/renderer_host/java/jni_helper_unittest.cc b/content/browser/renderer_host/java/jni_helper_unittest.cc new file mode 100644 index 0000000..34b17c2 --- /dev/null +++ b/content/browser/renderer_host/java/jni_helper_unittest.cc @@ -0,0 +1,94 @@ +// Copyright 2013 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/browser/renderer_host/java/jni_helper.h" + +#include "base/android/jni_android.h" +#include "base/at_exit.h" +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { + +const char kJavaLangObject[] = "java/lang/Object"; +const char kGetClass[] = "getClass"; +const char kToString[] = "toString"; +const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; +const char kReturningJavaLangString[] = "()Ljava/lang/String;"; + +const char* g_last_method; +const char* g_last_jni_signature; +jmethodID g_last_method_id; + +const JNINativeInterface* g_previous_functions; + +jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method, + const char* jni_signature) { + g_last_method = method; + g_last_jni_signature = jni_signature; + g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method, + jni_signature); + return g_last_method_id; +} + +} // namespace + +class JNIAndroidTest : public testing::Test { + protected: + virtual void SetUp() { + JNIEnv* env = base::android::AttachCurrentThread(); + g_previous_functions = env->functions; + hooked_functions = *g_previous_functions; + env->functions = &hooked_functions; + hooked_functions.GetMethodID = &GetMethodIDWrapper; + } + + virtual void TearDown() { + JNIEnv* env = base::android::AttachCurrentThread(); + env->functions = g_previous_functions; + Reset(); + } + + void Reset() { + g_last_method = 0; + g_last_jni_signature = 0; + g_last_method_id = NULL; + } + // Needed to cleanup the cached method map in the implementation between + // runs (e.g. if using --gtest_repeat) + base::ShadowingAtExitManager exit_manager; + // From JellyBean release, the instance of this struct provided in JNIEnv is + // read-only, so we deep copy it to allow individual functions to be hooked. + JNINativeInterface hooked_functions; +}; + +TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) { + JNIEnv* env = base::android::AttachCurrentThread(); + + Reset(); + jmethodID id1 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass, + kReturningJavaLangClass); + EXPECT_STREQ(kGetClass, g_last_method); + EXPECT_STREQ(kReturningJavaLangClass, g_last_jni_signature); + EXPECT_EQ(g_last_method_id, id1); + + Reset(); + jmethodID id2 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass, + kReturningJavaLangClass); + EXPECT_STREQ(0, g_last_method); + EXPECT_STREQ(0, g_last_jni_signature); + EXPECT_EQ(NULL, g_last_method_id); + EXPECT_EQ(id1, id2); + + Reset(); + jmethodID id3 = GetMethodIDFromClassName(env, kJavaLangObject, kToString, + kReturningJavaLangString); + EXPECT_STREQ(kToString, g_last_method); + EXPECT_STREQ(kReturningJavaLangString, g_last_jni_signature); + EXPECT_EQ(g_last_method_id, id3); +} + +} // namespace content |