Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <string>
     18 
     19 #include "jni/jni_util.h"
     20 
     21 #include "base/logging.h"
     22 
     23 #if 0
     24 JavaObject::JavaObject()
     25     : object_(JNI_NULL),
     26       ref_count_(new int(0)) {
     27 }
     28 
     29 JavaObject::JavaObject(const JavaObject& java_obj)
     30     : object_(java_obj.object_),
     31       ref_count_(java_obj.ref_count_) {
     32   Retain();
     33 }
     34 
     35 JavaObject::JavaObject(jobject object, JNIEnv* env)
     36     : object_(NULL),
     37       ref_count_(new int(0)) {
     38   Retain();
     39   object_ = env->NewGlobalRef(object_);
     40 }
     41 
     42 JavaObject::~JavaObject() {
     43   Release();
     44 }
     45 
     46 JavaObject& JavaObject::operator=(const JavaObject& java_obj) {
     47   Release();
     48   object_ = java_obj.object_;
     49   ref_count_ = java_obj.ref_count_;
     50   Retain();
     51   return *this;
     52 }
     53 
     54 void JavaObject::Retain() {
     55   if (ref_count_)
     56     ++(*ref_count_);
     57   else
     58     LOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
     59 }
     60 
     61 void JavaObject::Release() {
     62   if (ref_count_) {
     63     if (*ref_count_ > 0)
     64       --(*ref_count_);
     65     if (*ref_count_ == 0) {
     66       JNIEnv* env = GetCurrentJNIEnv();
     67       if (!env)
     68         LOGE("JavaObject: Releasing outside of Java thread. Will just leak!");
     69       else if (object_)
     70         env->DeleteGlobalRef(object_);
     71       delete ref_count_;
     72       ref_count_ = NULL;
     73     }
     74   } else {
     75     LOGE("JavaObject: Reference count is NULL! JavaObject may be corrupted.");
     76   }
     77 }
     78 
     79 void JavaObject::Reset() {
     80   Release();
     81   object_ = NULL;
     82   ref_count_ = new int(0);
     83 }
     84 
     85 JavaVM* GetCurrentJavaVM() {
     86   return g_current_java_vm_;
     87 }
     88 
     89 JNIEnv* GetCurrentJNIEnv() {
     90   JavaVM* vm = GetCurrentJavaVM();
     91   JNIEnv* env = NULL;
     92   const jint result = vm->GetEnv(reinterpret_cast<void**>(&env),
     93                                  JNI_VERSION_1_4);
     94   return result == JNI_OK ? env : NULL;
     95 }
     96 #endif
     97 
     98 jstring ToJString(JNIEnv* env, const std::string& value) {
     99   return env->NewStringUTF(value.c_str());
    100 }
    101 
    102 std::string ToCppString(JNIEnv* env, jstring value) {
    103   jboolean isCopy;
    104   const char* c_value = env->GetStringUTFChars(value, &isCopy);
    105   std::string result(c_value);
    106   if (isCopy == JNI_TRUE)
    107     env->ReleaseStringUTFChars(value, c_value);
    108   return result;
    109 }
    110 
    111 jboolean ToJBool(bool value) {
    112   return value ? JNI_TRUE : JNI_FALSE;
    113 }
    114 
    115 bool ToCppBool(jboolean value) {
    116   return value == JNI_TRUE;
    117 }
    118 
    119 // TODO: We actually shouldn't use such a function as it requires a class name lookup at every
    120 // invocation. Instead, store the class objects and use those.
    121 bool IsJavaInstanceOf(JNIEnv* env, jobject object, const std::string& class_name) {
    122   jclass clazz = env->FindClass(class_name.c_str());
    123   return clazz ? env->IsInstanceOf(object, clazz) == JNI_TRUE : false;
    124 }
    125 
    126 template<typename T>
    127 jobject CreateJObject(JNIEnv* env, const std::string& class_name, const std::string& signature, T value) {
    128   jobject result = JNI_NULL;
    129 
    130   return result;
    131 }
    132 
    133 Value ToCValue(JNIEnv* env, jobject object) {
    134   Value result = MakeNullValue();
    135   if (object != NULL) {
    136     if (IsJavaInstanceOf(env, object, "java/lang/Boolean")) {
    137       jmethodID method = env->GetMethodID(env->GetObjectClass(object), "booleanValue", "()Z");
    138       result = MakeIntValue(env->CallBooleanMethod(object, method) == JNI_TRUE ? 1 : 0);
    139     } else if (IsJavaInstanceOf(env, object, "java/lang/Integer")) {
    140       jmethodID method = env->GetMethodID(env->GetObjectClass(object), "intValue", "()I");
    141       result = MakeIntValue(env->CallIntMethod(object, method));
    142     } else if (IsJavaInstanceOf(env, object, "java/lang/Float")) {
    143       jmethodID method = env->GetMethodID(env->GetObjectClass(object), "floatValue", "()F");
    144       result = MakeFloatValue(env->CallFloatMethod(object, method));
    145     } else if (IsJavaInstanceOf(env, object, "java/lang/String")) {
    146       result = MakeStringValue(ToCppString(env, static_cast<jstring>(object)).c_str());
    147     } else if (IsJavaInstanceOf(env, object, "[I")) {
    148       jint* elems = env->GetIntArrayElements(static_cast<jintArray>(object), NULL);
    149       const jint count = env->GetArrayLength(static_cast<jintArray>(object));
    150       result = MakeIntArrayValue(elems, count);
    151       env->ReleaseIntArrayElements(static_cast<jintArray>(object), elems, JNI_ABORT);
    152     } else if (IsJavaInstanceOf(env, object, "[F")) {
    153       jfloat* elems = env->GetFloatArrayElements(static_cast<jfloatArray>(object), NULL);
    154       const jint count = env->GetArrayLength(static_cast<jfloatArray>(object));
    155       result = MakeFloatArrayValue(elems, count);
    156       env->ReleaseFloatArrayElements(static_cast<jfloatArray>(object), elems, JNI_ABORT);
    157     }
    158   }
    159   return result;
    160 }
    161 
    162 jobject ToJObject(JNIEnv* env, const Value& value) {
    163   jobject result = JNI_NULL;
    164   if (ValueIsInt(value)) {
    165     jclass clazz = env->FindClass("java/lang/Integer");
    166     jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(I)V");
    167     result = env->NewObject(clazz, constructorID, GetIntValue(value));
    168   } else if (ValueIsFloat(value)) {
    169     jclass clazz = env->FindClass("java/lang/Float");
    170     jmethodID constructorID = env->GetMethodID(clazz, "<init>", "(F)V");
    171     result = env->NewObject(clazz, constructorID, GetFloatValue(value));
    172   } else if (ValueIsString(value)) {
    173     result = ToJString(env, GetStringValue(value));
    174   } else if (ValueIsIntArray(value)) {
    175     result = env->NewIntArray(GetValueCount(value));
    176     env->SetIntArrayRegion(static_cast<jintArray>(result),
    177                            0,
    178                            GetValueCount(value),
    179                            reinterpret_cast<const jint*>(GetIntArrayValue(value)));
    180   } else if (ValueIsFloatArray(value)) {
    181     result = env->NewFloatArray(GetValueCount(value));
    182     env->SetFloatArrayRegion(static_cast<jfloatArray>(result),
    183                              0,
    184                              GetValueCount(value),
    185                              reinterpret_cast<const jfloat*>(GetFloatArrayValue(value)));
    186   }
    187   return result;
    188 }
    189