Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "JNIUtility.h"
     28 
     29 #if ENABLE(JAVA_BRIDGE)
     30 
     31 #include <dlfcn.h>
     32 
     33 namespace JSC {
     34 
     35 namespace Bindings {
     36 
     37 static jint KJSGetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
     38 {
     39     static void* javaVMFramework = 0;
     40     if (!javaVMFramework)
     41         javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
     42     if (!javaVMFramework)
     43         return JNI_ERR;
     44 
     45     typedef jint(*FunctionPointerType)(JavaVM**, jsize, jsize*);
     46     static FunctionPointerType functionPointer = 0;
     47     if (!functionPointer)
     48         functionPointer = reinterpret_cast<FunctionPointerType>(dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"));
     49     if (!functionPointer)
     50         return JNI_ERR;
     51     return functionPointer(vmBuf, bufLen, nVMs);
     52 }
     53 
     54 static JavaVM* jvm = 0;
     55 
     56 // Provide the ability for an outside component to specify the JavaVM to use
     57 // If the jvm value is set, the getJavaVM function below will just return.
     58 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
     59 // attached, the result is a no-op.
     60 void setJavaVM(JavaVM* javaVM)
     61 {
     62     jvm = javaVM;
     63 }
     64 
     65 JavaVM* getJavaVM()
     66 {
     67     if (jvm)
     68         return jvm;
     69 
     70     JavaVM* jvmArray[1];
     71     jsize bufLen = 1;
     72     jsize nJVMs = 0;
     73     jint jniError = 0;
     74 
     75     // Assumes JVM is already running ..., one per process
     76     jniError = KJSGetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
     77     if (jniError == JNI_OK && nJVMs > 0)
     78         jvm = jvmArray[0];
     79     else
     80         LOG_ERROR("JNI_GetCreatedJavaVMs failed, returned %ld", static_cast<long>(jniError));
     81 
     82     return jvm;
     83 }
     84 
     85 JNIEnv* getJNIEnv()
     86 {
     87     union {
     88         JNIEnv* env;
     89         void* dummy;
     90     } u;
     91     jint jniError = 0;
     92 
     93 #if OS(ANDROID)
     94     jniError = getJavaVM()->AttachCurrentThread(&u.env, 0);
     95 #else
     96     jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0);
     97 #endif
     98     if (jniError == JNI_OK)
     99         return u.env;
    100     LOG_ERROR("AttachCurrentThread failed, returned %ld", static_cast<long>(jniError));
    101     return 0;
    102 }
    103 
    104 jmethodID getMethodID(jobject obj, const char* name, const char* sig)
    105 {
    106     JNIEnv* env = getJNIEnv();
    107     jmethodID mid = 0;
    108 
    109     if (env) {
    110         jclass cls = env->GetObjectClass(obj);
    111         if (cls) {
    112             mid = env->GetMethodID(cls, name, sig);
    113             if (!mid) {
    114                 env->ExceptionClear();
    115                 mid = env->GetStaticMethodID(cls, name, sig);
    116                 if (!mid)
    117                     env->ExceptionClear();
    118             }
    119         }
    120         env->DeleteLocalRef(cls);
    121     }
    122     return mid;
    123 }
    124 
    125 const char* getCharactersFromJString(jstring aJString)
    126 {
    127     return getCharactersFromJStringInEnv(getJNIEnv(), aJString);
    128 }
    129 
    130 void releaseCharactersForJString(jstring aJString, const char* s)
    131 {
    132     releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s);
    133 }
    134 
    135 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
    136 {
    137     jboolean isCopy;
    138     const char* s = env->GetStringUTFChars(aJString, &isCopy);
    139     if (!s) {
    140         env->ExceptionDescribe();
    141         env->ExceptionClear();
    142         fprintf(stderr, "\n");
    143     }
    144     return s;
    145 }
    146 
    147 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s)
    148 {
    149     env->ReleaseStringUTFChars(aJString, s);
    150 }
    151 
    152 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
    153 {
    154     jboolean isCopy;
    155     const jchar* s = env->GetStringChars(aJString, &isCopy);
    156     if (!s) {
    157         env->ExceptionDescribe();
    158         env->ExceptionClear();
    159         fprintf(stderr, "\n");
    160     }
    161     return s;
    162 }
    163 
    164 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s)
    165 {
    166     env->ReleaseStringChars(aJString, s);
    167 }
    168 
    169 JavaType javaTypeFromClassName(const char* name)
    170 {
    171     JavaType type;
    172 
    173     if (!strcmp("byte", name))
    174         type = JavaTypeByte;
    175     else if (!strcmp("short", name))
    176         type = JavaTypeShort;
    177     else if (!strcmp("int", name))
    178         type = JavaTypeInt;
    179     else if (!strcmp("long", name))
    180         type = JavaTypeLong;
    181     else if (!strcmp("float", name))
    182         type = JavaTypeFloat;
    183     else if (!strcmp("double", name))
    184         type = JavaTypeDouble;
    185     else if (!strcmp("char", name))
    186         type = JavaTypeChar;
    187     else if (!strcmp("boolean", name))
    188         type = JavaTypeBoolean;
    189     else if (!strcmp("void", name))
    190         type = JavaTypeVoid;
    191     else if ('[' == name[0])
    192         type = JavaTypeArray;
    193 #if USE(V8)
    194     else if (!strcmp("java.lang.String", name))
    195         type = JavaTypeString;
    196 #endif
    197     else
    198         type = JavaTypeObject;
    199 
    200     return type;
    201 }
    202 
    203 const char* signatureFromJavaType(JavaType type)
    204 {
    205     switch (type) {
    206     case JavaTypeVoid:
    207         return "V";
    208 
    209     case JavaTypeArray:
    210         return "[";
    211 
    212     case JavaTypeObject:
    213 #if USE(V8)
    214     case JavaTypeString:
    215 #endif
    216         return "L";
    217 
    218     case JavaTypeBoolean:
    219         return "Z";
    220 
    221     case JavaTypeByte:
    222         return "B";
    223 
    224     case JavaTypeChar:
    225         return "C";
    226 
    227     case JavaTypeShort:
    228         return "S";
    229 
    230     case JavaTypeInt:
    231         return "I";
    232 
    233     case JavaTypeLong:
    234         return "J";
    235 
    236     case JavaTypeFloat:
    237         return "F";
    238 
    239     case JavaTypeDouble:
    240         return "D";
    241 
    242     case JavaTypeInvalid:
    243     default:
    244         break;
    245     }
    246     return "";
    247 }
    248 
    249 JavaType javaTypeFromPrimitiveType(char type)
    250 {
    251     switch (type) {
    252     case 'V':
    253         return JavaTypeVoid;
    254 
    255     case 'L':
    256         return JavaTypeObject;
    257 
    258     case '[':
    259         return JavaTypeArray;
    260 
    261     case 'Z':
    262         return JavaTypeBoolean;
    263 
    264     case 'B':
    265         return JavaTypeByte;
    266 
    267     case 'C':
    268         return JavaTypeChar;
    269 
    270     case 'S':
    271         return JavaTypeShort;
    272 
    273     case 'I':
    274         return JavaTypeInt;
    275 
    276     case 'J':
    277         return JavaTypeLong;
    278 
    279     case 'F':
    280         return JavaTypeFloat;
    281 
    282     case 'D':
    283         return JavaTypeDouble;
    284 
    285     default:
    286         break;
    287     }
    288     return JavaTypeInvalid;
    289 }
    290 
    291 jvalue getJNIField(jobject obj, JavaType type, const char* name, const char* signature)
    292 {
    293     JavaVM* jvm = getJavaVM();
    294     JNIEnv* env = getJNIEnv();
    295     jvalue result;
    296 
    297     memset(&result, 0, sizeof(jvalue));
    298     if (obj && jvm && env) {
    299         jclass cls = env->GetObjectClass(obj);
    300         if (cls) {
    301             jfieldID field = env->GetFieldID(cls, name, signature);
    302             if (field) {
    303                 switch (type) {
    304                 case JavaTypeArray:
    305                 case JavaTypeObject:
    306 #if USE(V8)
    307                 case JavaTypeString:
    308 #endif
    309                     result.l = env->functions->GetObjectField(env, obj, field);
    310                     break;
    311                 case JavaTypeBoolean:
    312                     result.z = env->functions->GetBooleanField(env, obj, field);
    313                     break;
    314                 case JavaTypeByte:
    315                     result.b = env->functions->GetByteField(env, obj, field);
    316                     break;
    317                 case JavaTypeChar:
    318                     result.c = env->functions->GetCharField(env, obj, field);
    319                     break;
    320                 case JavaTypeShort:
    321                     result.s = env->functions->GetShortField(env, obj, field);
    322                     break;
    323                 case JavaTypeInt:
    324                     result.i = env->functions->GetIntField(env, obj, field);
    325                     break;
    326                 case JavaTypeLong:
    327                     result.j = env->functions->GetLongField(env, obj, field);
    328                     break;
    329                 case JavaTypeFloat:
    330                     result.f = env->functions->GetFloatField(env, obj, field);
    331                     break;
    332                 case JavaTypeDouble:
    333                     result.d = env->functions->GetDoubleField(env, obj, field);
    334                     break;
    335                 default:
    336                     LOG_ERROR("Invalid field type (%d)", static_cast<int>(type));
    337                 }
    338             } else {
    339                 LOG_ERROR("Could not find field: %s", name);
    340                 env->ExceptionDescribe();
    341                 env->ExceptionClear();
    342                 fprintf(stderr, "\n");
    343             }
    344 
    345             env->DeleteLocalRef(cls);
    346         } else
    347             LOG_ERROR("Could not find class for object");
    348     }
    349 
    350     return result;
    351 }
    352 
    353 jvalue callJNIMethod(jobject object, JavaType returnType, const char* name, const char* signature, jvalue* args)
    354 {
    355     jmethodID methodId = getMethodID(object, name, signature);
    356     jvalue result;
    357     switch (returnType) {
    358     case JavaTypeVoid:
    359         callJNIMethodIDA<void>(object, methodId, args);
    360         break;
    361     case JavaTypeObject:
    362 #if USE(V8)
    363     case JavaTypeString:
    364 #endif
    365         result.l = callJNIMethodIDA<jobject>(object, methodId, args);
    366         break;
    367     case JavaTypeBoolean:
    368         result.z = callJNIMethodIDA<jboolean>(object, methodId, args);
    369         break;
    370     case JavaTypeByte:
    371         result.b = callJNIMethodIDA<jbyte>(object, methodId, args);
    372         break;
    373     case JavaTypeChar:
    374         result.c = callJNIMethodIDA<jchar>(object, methodId, args);
    375         break;
    376     case JavaTypeShort:
    377         result.s = callJNIMethodIDA<jshort>(object, methodId, args);
    378         break;
    379     case JavaTypeInt:
    380         result.i = callJNIMethodIDA<jint>(object, methodId, args);
    381         break;
    382     case JavaTypeLong:
    383         result.j = callJNIMethodIDA<jlong>(object, methodId, args);
    384         break;
    385     case JavaTypeFloat:
    386         result.f = callJNIMethodIDA<jfloat>(object, methodId, args);
    387         break;
    388     case JavaTypeDouble:
    389         result.d = callJNIMethodIDA<jdouble>(object, methodId, args);
    390         break;
    391     default:
    392         break;
    393     }
    394     return result;
    395 }
    396 
    397 } // namespace Bindings
    398 
    399 } // namespace JSC
    400 
    401 #endif // ENABLE(JAVA_BRIDGE)
    402