JNI编程

本文详细介绍了JNI(Java Native Interface)的基本概念和技术细节,包括如何通过JNI让Java与C/C++进行交互,具体步骤涉及JNI环境配置、本地方法声明、C/C++函数映射以及在Android平台上的实践案例。

这里写图片描述

JNI 的基本内容

  1. 理解JNI的作用
a java native interface ( 提供调用本地方法的接口)
b java 调用c/c++ 时是通过jni层间接调用
c jni的技术是在vm中实现

d java <----> c  数据间的转换
   java通过参数把数据传给c,c通过返回值把数据给到java。
e 整型 int == jint, 字符 2c == java
f java字符串转为c字符串
    char *temp = env->GetStringUTF(str,NULL);
g c字符串转为java字符串
    jstring jtemp = env->NewStringUTFChars("hello word");
                    env->ReleasestringUTFchars(str,jtemp);
  1. JNI的编程
1. 编写app:
    static{  //优先执行
            System.loadLibrary("led_jni");   // /system/lib/libled_jni.so
    } 
    //声明本地方法--自定义
    native  int openDev();
    native  int devOn();
    native  int devOff();.
    native  int closeDev();
  1. myjni.cpp
    说明:
    实例– development/samples/SimpleJNI
    注意– 用source insight写,并添加android源码。
a //jni代码的入口
    jint JNI_OnLoad(JavaVM * vm,void * reserved)
    {
        //正常返回JNI_VERSION_1_4, 错误返回负数
        return JNI_VERSION_1_4;
    }

b 从vm中获取到环境变量对象,包含了大量的方法
    int  GetEnv(void * * env,jint version);
    参数1:获取的环境变量对象
    参数2:测试jni的版本:JNI_VERSION_1_4
    返回值:正确返回0, 错误负数
        JNIEnv *env = NULL;
        jint ret;
        ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4);
        if(ret != 0)
        {
            LOGE("vm->GetEnv error");
            return -1;
        }

c  java代码中的本地方法包
    jclass  mycls = env->FindClass("com/hq/ledcontroltest/LedNative");
    if(mycls == NULL)
    {
        LOGE("env->FindClass error");
        return -1;
    }

d 实现映射表的功能
    //表示一个映射表:
    typedef struct {
        const char* name;  // java的方法名
        const char* signature; //java的方法的描述
        void*       fnPtr; //  c/c++的函数名
    } JNINativeMethod;


    JNINativeMethod   myMethods[] = {
        {"openDev",  "()I",   (void *)open_led},
        {"devOn",    "()I",   (void *)led_on},
        {"devOff",   "()I",   (void *)led_off},
        {"closeDev", "()I",   (void *)close_led},
    };

e  注册映射表
    参数1:给出java中本地方法所在的包,类路径
    参数2: 映射表
    参数3: 数组中元素的个数                   
    ret = env->RegisterNatives(mycls, led_Methods, 
                    sizeof(led_Methods)/sizeof(led_Methods[0]));
    if(ret < 0)
    {
        LOGE("env->RegisterNatives error");
        return -1;
    }

f  实现映射表的方法
    jint open_led(JNIEnv *env,  jobject thiz){
    }
    jint led_on(JNIEnv *env,  jobject thiz){
    }
    jint led_off(JNIEnv *env,  jobject thiz){
    }
    jint close_led(JNIEnv *env,  jobject thiz){ 
    }

没有HAL层

android.mk (mmm xxx.cpp 编译jni)

#获取当前路径
LOCAL_PATH:= $(call my-dir)

#清空以LOCAL_XX的变量,除了LOCAL_PATH
include $(CLEAR_VARS)

#在任何情况都会编译
LOCAL_MODULE_TAGS := optional

#依赖--指定源码
LOCAL_SRC_FILES:= myled_jni.cpp

#依赖动态库(-lpthread)
LOCAL_SHARED_LIBRARIES := \
        libcutils

#目标--指定目标文件名
LOCAL_MODULE:= libled_jni

#添加自定义的头文件
LOCAL_C_INCLUDES += \
        $(JNI_H_INCLUDE)

#编译规则---编译成可执行程序
include $(BUILD_SHARED_LIBRARY)

myjni.cpp

#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define LOG_TAG "LED_JNI_LOG"
#include <utils/Log.h>

#include "jni.h"

static int fd ;
jint open_led(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    fd = open("/dev/led1", O_RDWR);
    if(fd < 0)
    {
        LOGE("open : %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

jint led_on(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    jint on  = 1;
    jint ret;

    ret = write(fd, &on, 4);
    if(ret < 0)
    {
        LOGE("write on : %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

jint led_off(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    jint on  = 0;
    jint ret;

    ret = write(fd, &on, 4);
    if(ret < 0)
    {
        LOGE("write on : %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

jint close_led(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);
    close(fd);

    return 0;
}
const JNINativeMethod  led_Methods[] = {
    {"openDev", "()I",   (void *)open_led},
    {"devOn", "()I",   (void *)led_on},
    {"devOff", "()I",   (void *)led_off},
    {"closeDev", "()I",   (void *)close_led},

};
jint JNI_OnLoad(JavaVM * vm,void * reserved)
{
    JNIEnv *env = NULL;
    jint ret;

    ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4);
    if(ret != JNI_OK)
    {
        LOGE("vm->GetEnv error");
        return -1;
    }

    jclass  mycls = env->FindClass("com/hq/ledcontroltest/LedNative");
    if(mycls == NULL)
    {
        LOGE("env->FindClass error");
        return -1;
    }

    ret = env->RegisterNatives(mycls, led_Methods,
                sizeof(led_Methods)/sizeof(led_Methods[0]));
    if(ret < 0)
    {
        LOGE("env->RegisterNatives error");
        return -1;
    }

    //正常返回JNI_VERSION_1_4, 错误返回负数
    return JNI_VERSION_1_4;
}

有HAL层

//添加以下内容
#include "led_hal.h"


//定义两个指针
struct led_hw_module_t  *pModule;
struct led_hw_device_t *pDevice;

jint open_led(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);
    jint ret;

    ret = hw_get_module(LED_MODULE_ID,(const struct hw_module_t * * )&pModule);
    if(ret == 0)
    {
        LOGD("hw_get_module ok\n");
        if(pModule != NULL)
        {
            //调用hal中的module的open方法
            pModule->common.methods->open(&pModule->common, NULL,
                        (struct hw_device_t** )&pDevice);

            //如果调用成功pDevice会被初始化
            if(pDevice != NULL)
                pDevice->open();

        }

    }else{
        LOGE("hw_get_module error\n");
    }

    return 0;
}


//实现的方法修改为以下
jint led_on(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    if(pDevice != NULL)
                pDevice->control_dev(1);
    return 0;
}

jint led_off(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    if(pDevice != NULL)
                pDevice->control_dev(0);

    return 0;
}

jint close_led(JNIEnv *env,  jobject thiz)
{
    LOGD("---------%s-----------\n", __FUNCTION__);

    if(pDevice != NULL)
                pDevice->common.close((struct hw_device_t* )pDevice);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值