blob: 09026e77952a3f6ac44300a1e2abf336dfa20712 [file] [log] [blame]
// Copyright 2014 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/android/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