JNI 使用淺談

Preview:

Citation preview

JNI 使用淺談 阿胖 2016.09.29

Android Taipei

Outline1. Java call c

2. c call java

3. c vs cpp

4. Data Type Mapping

5. Data Type Convert

6. JNIEnv

Java call c

HelloJni.java

hello-jni.c

HelloJni.java

public native String stringFromJNI();

static {

System.loadLibrary("hello-jni");

}

hello-jni.c

jtype Java_PATH_NAME_CLASSNAME_FUNCTIONNAME(

JNIEnv* env, jobject thiz [,… jparams] )

hello-jni.c

jstringJava_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ){ char msg[] = "Hello World from JNI !"; jstring jMsg = (*env)->NewStringUTF(env, msg);

return jMsg;}

c call java

HelloJni.java

hello-jni.c

HelloJni.java

private void callFromJni(String msg) {

Log.i(TAG,"123 "+msg);

}

hello-jni.cNativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

jclass GetObjectClass(JNIEnv *env, jobject obj);

hello-jni.cpp

jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { char msg[] = "Hello World from JNI !"; jstring jMsg = env->NewStringUTF(msg);

return jMsg;}

jclass jClass = env->GetObjectClass(thiz); jmethodID mid = env->GetMethodID(jClass, "callFromJni", "(Ljava/lang/String;)V" ); env->CallVoidMethod(thiz, mid, jMsg);

c vs cpp

jstring jMsg = (*env)->NewStringUTF(env, msg);

jstring jMsg = env->NewStringUTF(msg);

#ifdef __cplusplusextern "C" {#endif

#ifdef __cplusplus}#endif

Data Type Mapping

Java primitive data type Native primitive data type Description

void void None

byte jbyte 8-bit signed. Range is -2^7 to 2^7 - 1

int jint 32-bit signed. Range is -2^31 to 2^31 - 1

float jfloat 32 bits. Represent a real number as small as 1.4 x 10-45 and as big as 3.4 x 1038 (approx.), positive or negative

double jdouble 64 bits. Represent a real number as small as 4.9 x 10-324 and as big as 1.7 x 10308 (approx.), positive or negative

char jchar 16-bit unsigned. Range is 0 to 65535

long jlong 64-bit signed. Range -2^63 to 2^63 - 1

short jshort 16-bit signed. Range is -2^15 to 2^15 - 1

boolean jboolean Unsigned 8 bits. true and false

Data Type Mapping

Java Reference type JNI type Description

java.lang.object jobject Any Java object

java.lang.String jstring String representation

java.lang.Class jclass Java class object

java.lang.Throwable jthrowable Java throwable object

Data Type MappingType Signature Java TypeZ boolean

B byte

C char

S short

I int

J long

F float

D double

V void

[ []

L<packet>/object; object

Data Type Mapping

Function in java signature

int foo() “()I”

void foo(byte[] arg) “([B)V”

boolean foo(String arg) “(Ljava/lang/String;)Z”

"(parameterFieldDescriptor)returnFieldDescriptor"

Data Type Convert

NewStringUTFjstring NewStringUTF(JNIEnv *env, const char *bytes);jstring jstr = (*env)->NewStringUTF(env, "This comes from jni.");

GetStringUTFCharsconst char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);const char* str = (*env)->GetStringUTFChars(env, jstr , NULL);

ReleaseStringUTFCharsvoid ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);

String

Data Type Convert

New<PrimitiveType>Array RoutinesArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);

Set<PrimitiveType>ArrayRegion Routinesvoid Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, const NativeType *buf);

Array

Data Type Convert

Get<PrimitiveType>ArrayElements RoutinesNativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, jboolean *isCopy);

Release<PrimitiveType>ArrayElements Routinesvoid Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, NativeType *elems, jint mode);

Get<PrimitiveType>ArrayRegion Routinesvoid Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, NativeType *buf);

Array

Data Type Convert

struct{ char name[256]; int num;} Foo;

Object

class Foo { public String name; public int num;}

Data Type Convert

FindClassjclass FindClass(JNIEnv *env, const char *name);“your/java/path/name/class_name$inner_class_name”

jmethodID mid = env->GetMethodID(msgClass, "<init>", "()V" );

NewObjectjobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

GetFieldIDjfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

Set<type>Field Routinesvoid Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value);

Get<type>Field RoutinesNativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);

Object

Data Type Convert

NewGlobalRefjobject NewGlobalRef(JNIEnv *env, jobject obj);

DeleteGlobalRefvoid DeleteGlobalRef(JNIEnv *env, jobject globalRef);

DeleteLocalRefvoid DeleteLocalRef(JNIEnv *env, jobject localRef);

static_cast<type>

JNIEnv

jint JNI_OnLoad(JavaVM* vm, void* reserved){ LOGI("JNI_OnLoad"); JNIEnv* env = NULL; jint result = -1; if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { return result; }

jvm = vm; return JNI_VERSION_1_4;}

JNIEnv* getJNIEnv() { JNIEnv* env = NULL; int res = jvm->GetEnv((void**)&env, JNI_VERSION_1_4);

if (res == JNI_EDETACHED) { //LOGI("GetEnv: not attached"); if (jvm->AttachCurrentThread(&env, NULL) != 0) { LOGI("Failed to attach"); return NULL; } } else if (res == JNI_OK) { // } else if (res == JNI_EVERSION) { LOGI("GetEnv: version not supported"); return NULL; } return env;}

JNIEnv

JNIEnv* env = getJNIEnv();

/* do something */

jvm->DetachCurrentThread();

Reference

http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html

http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html

http://www.developer.com/java/data/jni-data-type-mapping-to-cc.html

source code : https://github.com/kentpon/hello-jni

QA