jni之java和c通信



http://my.oschina.net/blackylin/blog/95176

这里用上面的例子介绍jni通信。

1.新建一个android_ril_jni.c文件,当然也可以源码或其他地方考一个jni文件来修改。

#define LOG_TAG "GSMService_JNI"

#include <jni.h>
//#include <android/log.h>
#include <assert.h>
#include <string.h>
//#include <nativehelper/JNIHelp.h>
#include <pthread.h>
#include <utils/Log.h>



typedef struct{
	jclass   cbclass;
    jmethodID native_proc;
    jobject  gsm;
}fields_t;

static fields_t fields;
static JavaVM*  g_vm = NULL;

// ----------------------------------------------------------------------------
#define GSM_PKG_NAME "com/app/gsm/GSMService"

extern int open_console();


static jboolean com_app_gsm_GSMService_init(JNIEnv *env, jobject thiz, jobject weak) {
	jclass clazz;

	clazz = (*env)->FindClass(env, GSM_PKG_NAME);
	if(clazz == NULL){
		LOGE("Can't find class com/app/gsm/GSMService");
		return 0;
	}

	fields.cbclass = (*env)->NewGlobalRef(env, clazz);
	fields.native_proc = (*env)->GetStaticMethodID(env, clazz,
				"native_proc", "(Ljava/lang/Object;IIILjava/lang/String;)I");
	if (fields.native_proc == NULL) {
		LOGE("Can't find method native_proc in com//app/gsm/GSMService native_proc");
		return 0;
	}
	if(fields.gsm == NULL){
		fields.gsm = (*env)->NewGlobalRef(env,weak);
	}
	//打开串口
	if(open_console() != 0){
		LOGE("open console err...");
		return 0;
	}
	return 1;
}

static JNIEnv* attach_jnienv() {
	jint result;
	JNIEnv *env = NULL;
	JavaVMAttachArgs args;
	args.version = JNI_VERSION_1_4;
	args.name = NULL;
	args.group = NULL;
	assert(g_vm != NULL);
	result = (*g_vm)->AttachCurrentThread(g_vm,&env,(void*)&args);
	if (result != JNI_OK) {
		LOGI("attach_jnienv attach thread failed\n");
		return NULL;
	}
	return env;
}

static void detach_jnienv() {
	assert(g_vm != NULL);
	(*g_vm)->DetachCurrentThread(g_vm);
}

int com_native_proc(int msg,int p1,int p2,const char *incoming_num) {
	int ret = 0;
	JNIEnv * env = attach_jnienv();
	LOGE("com_native_proc,msg=%d....start",msg);
	if (env && msg) {
		jstring jvalue = (*env)->NewStringUTF(env, incoming_num);
		ret = (*env)->CallStaticIntMethod(env,fields.cbclass, fields.native_proc,
				fields.gsm, msg,p1,p2,jvalue);
		detach_jnienv();
		LOGE("com_native_proc,end,ret=%d",ret);
	}
	return ret;
}

static int registerNativeMethods(JNIEnv* env, const char* className,
		JNINativeMethod* gMethods, int numMethods) {
	jclass clazz;

	clazz = (*env)->FindClass(env, className);
	if (clazz == NULL) {
		return JNI_FALSE;
	}
	if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
		return JNI_FALSE;
	}
	return JNI_TRUE;
}

static JNINativeMethod gMethods[] = {
	{ "native_init", "(Ljava/lang/ref/WeakReference;)Z",(void *) com_app_gsm_GSMService_init },
};

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env = NULL;
	jint result = -1;
	LOGE("zouxy Enter JNI_OnLoad");
	if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		LOGE("ERROR: GetEnv failed\n");
		goto bail;
	}
	assert(env != NULL);

	g_vm = vm;
	result = registerNativeMethods(env, GSM_PKG_NAME, gMethods,
			sizeof(gMethods) / sizeof(gMethods[0]));
	if (result < 0) {
		LOGE("ERROR: registerNativeMethods failed,result=%d...\n",result);
		goto bail;
	}
	LOGE(" Enter com_app_gsm_GSMService_init");
	result = JNI_VERSION_1_4;
	LOGE("Exit JNI_OnLoad");
	bail: return result;
}
启动GSMService服务,加载static中代码libril_jni.so.
接着调用JNI_OnLoad这个方法加载,这里实现初始化、注册native函数等操作
jint JNI_OnLoad(JavaVM* vm, void* reserved)

c映射对应java的函数:

static JNINativeMethod gMethods[] = {
	{ "native_init", "(Ljava/lang/ref/WeakReference;)Z",(void *) com_app_gsm_GSMService_init },
};

这里在之前GSMService构造方法中有调用native_init方法,就是调用这个jni里com_app_gsm_GSMService_init方法。需要注意的是对应的参数,其中Z表示返回值为boolean,其他对应的可以查找源码中jni.h中详细定义。此处就实现java调用c的过程。

2.C调用java

int com_native_proc(int msg,int p1,int p2,const char *incoming_num) {
	int ret = 0;
	JNIEnv * env = attach_jnienv();
	LOGE("com_native_proc,msg=%d....start",msg);
	if (env && msg) {
		jstring jvalue = (*env)->NewStringUTF(env, incoming_num);
		ret = (*env)->CallStaticIntMethod(env,fields.cbclass, fields.native_proc,
				fields.gsm, msg,p1,p2,jvalue);
		detach_jnienv();
		LOGE("com_native_proc,end,ret=%d",ret);
	}
	return ret;
}
这个jni里的函数,相当于一个透传作用,被其他c函数调用。
ret = (*env)->CallStaticIntMethod(env,fields.cbclass, fields.native_proc,
				fields.gsm, msg,p1,p2,jvalue);
通过CallStaticInitMethod函数掉用java里的方法,同样这里值得注意的是方法类型、参数和返回值,不然都会报错;c文件的jni和cpp的jni有些不同,就那这个函数来说,cpp的jni没有这个env这个参数,具体的可以参照源码中jni.h。
这个函数的参数在前面init函数中有映射,故同样实现C调java的过程

期待更多的补充O(∩_∩)O.......




你可能感兴趣的:(android,jni)