165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/*
265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project
365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License");
565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License.
665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at
765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *      http://www.apache.org/licenses/LICENSE-2.0
965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software
1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS,
1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and
1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License.
1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <string>
1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "jni/jni_util.h"
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "base/logging.h"
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#if 0
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaObject::JavaObject()
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    : object_(JNI_NULL),
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ref_count_(new int(0)) {
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaObject::JavaObject(const JavaObject& java_obj)
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    : object_(java_obj.object_),
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ref_count_(java_obj.ref_count_) {
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Retain();
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaObject::JavaObject(jobject object, JNIEnv* env)
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    : object_(NULL),
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ref_count_(new int(0)) {
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Retain();
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  object_ = env->NewGlobalRef(object_);
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaObject::~JavaObject() {
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Release();
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaObject& JavaObject::operator=(const JavaObject& java_obj) {
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Release();
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  object_ = java_obj.object_;
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ref_count_ = java_obj.ref_count_;
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Retain();
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return *this;
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid JavaObject::Retain() {
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (ref_count_)
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ++(*ref_count_);
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid JavaObject::Release() {
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (ref_count_) {
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (*ref_count_ > 0)
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      --(*ref_count_);
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (*ref_count_ == 0) {
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      JNIEnv* env = GetCurrentJNIEnv();
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (!env)
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        ALOGE("JavaObject: Releasing outside of Java thread. Will just leak!");
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      else if (object_)
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        env->DeleteGlobalRef(object_);
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      delete ref_count_;
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ref_count_ = NULL;
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else {
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid JavaObject::Reset() {
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Release();
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  object_ = NULL;
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ref_count_ = new int(0);
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJavaVM* GetCurrentJavaVM() {
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return g_current_java_vm_;
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennJNIEnv* GetCurrentJNIEnv() {
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  JavaVM* vm = GetCurrentJavaVM();
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  JNIEnv* env = NULL;
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const jint result = vm->GetEnv(reinterpret_cast<void**>(&env),
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                 JNI_VERSION_1_4);
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result == JNI_OK ? env : NULL;
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#endif
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennjstring ToJString(JNIEnv* env, const std::string& value) {
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return env->NewStringUTF(value.c_str());
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstd::string ToCppString(JNIEnv* env, jstring value) {
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  jboolean isCopy;
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const char* c_value = env->GetStringUTFChars(value, &isCopy);
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::string result(c_value);
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (isCopy == JNI_TRUE)
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    env->ReleaseStringUTFChars(value, c_value);
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennjboolean ToJBool(bool value) {
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return value ? JNI_TRUE : JNI_FALSE;
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ToCppBool(jboolean value) {
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return value == JNI_TRUE;
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// TODO: We actually shouldn't use such a function as it requires a class name lookup at every
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// invocation. Instead, store the class objects and use those.
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool IsJavaInstanceOf(JNIEnv* env, jobject object, const std::string& class_name) {
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  jclass clazz = env->FindClass(class_name.c_str());
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return clazz ? env->IsInstanceOf(object, clazz) == JNI_TRUE : false;
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renntemplate<typename T>
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennjobject CreateJObject(JNIEnv* env, const std::string& class_name, const std::string& signature, T value) {
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  jobject result = JNI_NULL;
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennValue ToCValue(JNIEnv* env, jobject object) {
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Value result = MakeNullValue();
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (object != NULL) {
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (IsJavaInstanceOf(env, object, "java/lang/Boolean")) {
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "booleanValue", "()Z");
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeIntValue(env->CallBooleanMethod(object, method) == JNI_TRUE ? 1 : 0);
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else if (IsJavaInstanceOf(env, object, "java/lang/Integer")) {
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "intValue", "()I");
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeIntValue(env->CallIntMethod(object, method));
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else if (IsJavaInstanceOf(env, object, "java/lang/Float")) {
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      jmethodID method = env->GetMethodID(env->GetObjectClass(object), "floatValue", "()F");
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeFloatValue(env->CallFloatMethod(object, method));
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else if (IsJavaInstanceOf(env, object, "java/lang/String")) {
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeStringValue(ToCppString(env, static_cast<jstring>(object)).c_str());
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else if (IsJavaInstanceOf(env, object, "[I")) {
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      jint* elems = env->GetIntArrayElements(static_cast<jintArray>(object), NULL);
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const jint count = env->GetArrayLength(static_cast<jintArray>(object));
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeIntArrayValue(elems, count);
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      env->ReleaseIntArrayElements(static_cast<jintArray>(object), elems, JNI_ABORT);
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else if (IsJavaInstanceOf(env, object, "[F")) {
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      jfloat* elems = env->GetFloatArrayElements(static_cast<jfloatArray>(object), NULL);
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const jint count = env->GetArrayLength(static_cast<jfloatArray>(object));
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      result = MakeFloatArrayValue(elems, count);
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      env->ReleaseFloatArrayElements(static_cast<jfloatArray>(object), elems, JNI_ABORT);
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennjobject ToJObject(JNIEnv* env, const Value& value) {
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  jobject result = JNI_NULL;
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (ValueIsInt(value)) {
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    jclass clazz = env->FindClass("java/lang/Integer");
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(I)V");
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    result = env->NewObject(clazz, constructorID, GetIntValue(value));
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (ValueIsFloat(value)) {
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    jclass clazz = env->FindClass("java/lang/Float");
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(F)V");
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    result = env->NewObject(clazz, constructorID, GetFloatValue(value));
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (ValueIsString(value)) {
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    result = ToJString(env, GetStringValue(value));
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (ValueIsIntArray(value)) {
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    result = env->NewIntArray(GetValueCount(value));
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    env->SetIntArrayRegion(static_cast<jintArray>(result),
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           0,
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           GetValueCount(value),
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           reinterpret_cast<const jint*>(GetIntArrayValue(value)));
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (ValueIsFloatArray(value)) {
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    result = env->NewFloatArray(GetValueCount(value));
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    env->SetFloatArrayRegion(static_cast<jfloatArray>(result),
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             0,
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             GetValueCount(value),
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             reinterpret_cast<const jfloat*>(GetFloatArrayValue(value)));
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
189