1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/renderer_host/java/jni_helper.h" 6 7 #include <map> 8 9 #include "base/android/jni_android.h" 10 #include "base/lazy_instance.h" 11 #include "base/threading/platform_thread.h" 12 13 namespace content { 14 15 namespace { 16 17 struct MethodIdentifier { 18 const char* class_name; 19 const char* method; 20 const char* jni_signature; 21 22 bool operator<(const MethodIdentifier& other) const { 23 int r = strcmp(class_name, other.class_name); 24 if (r < 0) { 25 return true; 26 } else if (r > 0) { 27 return false; 28 } 29 30 r = strcmp(method, other.method); 31 if (r < 0) { 32 return true; 33 } else if (r > 0) { 34 return false; 35 } 36 37 return strcmp(jni_signature, other.jni_signature) < 0; 38 } 39 }; 40 41 typedef std::map<MethodIdentifier, jmethodID> MethodIDMap; 42 43 const base::subtle::AtomicWord kUnlocked = 0; 44 const base::subtle::AtomicWord kLocked = 1; 45 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; 46 47 base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER; 48 49 } // namespace 50 51 jmethodID GetMethodIDFromClassName(JNIEnv* env, 52 const char* class_name, 53 const char* method, 54 const char* jni_signature) { 55 MethodIdentifier key; 56 key.class_name = class_name; 57 key.method = method; 58 key.jni_signature = jni_signature; 59 60 MethodIDMap* map = g_method_id_map.Pointer(); 61 bool found = false; 62 63 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, 64 kUnlocked, 65 kLocked) != kUnlocked) { 66 base::PlatformThread::YieldCurrentThread(); 67 } 68 MethodIDMap::const_iterator iter = map->find(key); 69 if (iter != map->end()) { 70 found = true; 71 } 72 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); 73 74 // Addition to the map does not invalidate this iterator. 75 if (found) { 76 return iter->second; 77 } 78 79 base::android::ScopedJavaLocalRef<jclass> clazz( 80 env, env->FindClass(class_name)); 81 jmethodID id = base::android::MethodID::Get< 82 base::android::MethodID::TYPE_INSTANCE>( 83 env, clazz.obj(), method, jni_signature); 84 85 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, 86 kUnlocked, 87 kLocked) != kUnlocked) { 88 base::PlatformThread::YieldCurrentThread(); 89 } 90 // Another thread may have populated the map already. 91 std::pair<MethodIDMap::const_iterator, bool> result = 92 map->insert(std::make_pair(key, id)); 93 DCHECK_EQ(id, result.first->second); 94 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); 95 96 return id; 97 } 98 99 } // namespace content 100