Android之JNI总结笔记

由于项目中的APP都是与硬件交互,所以难免会与Kernel层交互,但上层软件又是有Java语言编写的,怎么和C/C++语言交互呢?这里就使用到了JNI(Java Native Interface)。

Java如何调用JNI:

1.需要在Java中定义本地函数,使用关键字Native。

private native boolean jniopenserial()。

2.需要在Java中声明System.loadLibrary("本地库名称"),去让程序加载本地库。

3.在JNI中声明与Java对应的函数,并实现函数的功能。

static jboolean android_avin_openSerial(JNIEnv *env, jobject thiz){
	fdTtyS3 = open(SEND_DEV_NODE, O_RDWR|O_NOCTTY|O_NONBLOCK);
	if(fdTtyS3 < 0){
		ALOGE("open %s failed,fdTtyS3=%d(%d,%s)\n", SEND_DEV_NODE, fdTtyS3, errno, strerror(errno));
		return JNI_FALSE;
	}

	fdAudio = open(AUDIO_CTRL_NODE, O_RDWR|O_NOCTTY|O_NONBLOCK);
	if(fdAudio < 0) {
		ALOGE("open %s failed,fdAudio=%d(%d,%s)\n", AUDIO_CTRL_NODE, fdAudio, errno, strerror(errno));
		close(fdTtyS3);
		fdTtyS3 = -1;
		return JNI_FALSE;
	}

	return JNI_TRUE;
}

4.将JNI本地函数与Java Native声明的函数进行映射

static JNINativeMethod sMethods[] = {
	{"jniopenserial","()Z", (void *)android_avin_openSerial},
	{"jniAvInSwitch", "(Z)Z", (void *)android_avin_switch},
	{"jniDVDSwitch", "(Z)Z", (void *)android_dvd_switch},
	{"jniDVDOperation", "(I)Z", (void *)android_dvd_operation},
	{"jnicloseserial", "()V", (void *)android_avin_closeSerial},
};
这个数组是什么时候被调用的呢?

首先我们需要知道Java中的System.loadLibray,它一般在类加载的时候或者构造函数之前被调用,经过层层关系,会调用到JNI的JNI_OnLoad函数:

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    UnionJNIEnvToVoid uenv;
    uenv.venv = NULL;
    jint result = -1;
    JNIEnv* env = NULL;

    ALOGI("JNI_OnLoad");

    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
        ALOGE("ERROR: GetEnv failed");
        goto bail;
    }
    env = uenv.env;

    if (registerNatives(env) != JNI_TRUE) {
        ALOGE("ERROR: registerNatives failed");
        goto bail;
    }

    result = JNI_VERSION_1_6;

bail:
    return result;
}

这个函数又会调用:

static int registerNatives(JNIEnv* env)
{
  if (!registerNativeMethods(env, classPathName,
          sMethods, sizeof(sMethods) / sizeof(sMethods[0]))) {
    return JNI_FALSE;
  }

  return JNI_TRUE;
}

这里我们看到了registerNativeMethods这个函数,并且发现了sMethods数组的身影。

/*
 * Register several native methods for one class.
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* methods, int numMethods)
{
    jclass clazz;

    clazz = env->FindClass(className);
    if (clazz == NULL) {
        ALOGE("Native registration unable to find class '%s'", className);
        return JNI_FALSE;
    }

    if (env->RegisterNatives(clazz, methods, numMethods) < 0) {
        ALOGE("RegisterNatives failed for '%s'", className);
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

通过上述调用关系我们可以知道,当加载本地库的时候,JNI和Java声明的本地函数就对应了起来。


JNI调用Java成员变量流程:

1.获取Java类

FindClass

2.获取成员变量的FieldID

GetFieldID

3.获取成员变量

GetXXXField


JNI调用Java对象:

1.获取Java类

FindClass/GetObjectClass

2.获取构造方法ID

GetMethodID

3 生成对象

NewObject


JNI改变Java成员变量值:

JNI调用Java成员变量流程一样,只不过第三部变为SetXXXField


JNI调用Java方法

1.获取Java类或者对象

FindClass

2.获取方法的ID

GetMethodID

3.调用方法

CallXXXMethod

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值