Home | History | Annotate | Download | only in java
      1 // Copyright 2014 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/android/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