Tiny4412 led之build JNI实现

PC机平台:ubuntu 12.04.5

硬件平台:Tiny4412标准版+android5.0


上一篇:Tiny4412 led之NDK JNI实现,介绍的是通过NDK工具进行JNI开发,*.so文件是通过NDK工具进行编译生成的,这次就介绍如何通过arm-linux-gcc编译生成对应的*.so文件,深入了解JNI底层的开发流程;


驱动代码、JNI接口、android应用程序都是Tiny4412 led之NDK JNI实现的代码;需要重新编写的只有*.c文件;


新建tiny4412-leds.c

#include <jni.h>  
#include <stdio.h>
#include <android/log.h> 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>

#define DEVICE_NAME		"/dev/tiny4412-leds"

#define LED_0		1
#define LED_1		2
#define LED_2		3
#define LED_3		4

//幻数
#define LEDS_MAGIC	'a'
#define LEDS_PGM4_0_ON		_IO(LEDS_MAGIC, 1)
#define LEDS_PGM4_0_OFF	_IO(LEDS_MAGIC, 2)
#define LEDS_PGM4_1_ON		_IO(LEDS_MAGIC, 3)
#define LEDS_PGM4_1_OFF	_IO(LEDS_MAGIC, 4)
#define LEDS_PGM4_2_ON		_IO(LEDS_MAGIC, 5)
#define LEDS_PGM4_2_OFF	_IO(LEDS_MAGIC, 6)
#define LEDS_PGM4_3_ON		_IO(LEDS_MAGIC, 7)
#define LEDS_PGM4_3_OFF	_IO(LEDS_MAGIC, 8)

jint JNICALL leds_operation(JNIEnv *env, jobject cls, jint ledsNum, jboolean status)
{
	int leds_fd = 0;

	leds_fd = open(DEVICE_NAME, O_RDWR);
	if (leds_fd == -1) {
		__android_log_print(ANDROID_LOG_DEBUG, "tiny4412-leds", "leds_operation fail!");
		return 1;
	}
	
	__android_log_print(ANDROID_LOG_DEBUG, "tiny4412-leds", "leds_operation ledNum:%d,status:%d", ledsNum, status);

	switch (ledsNum) {
	case LED_0:
		if (status)
			ioctl(leds_fd, LEDS_PGM4_0_ON);
		else
			ioctl(leds_fd, LEDS_PGM4_0_OFF);
		break;
	case LED_1:
		if (status)
			ioctl(leds_fd, LEDS_PGM4_1_ON);
		else
			ioctl(leds_fd, LEDS_PGM4_1_OFF);
		break;
	case LED_2:
		if (status)
			ioctl(leds_fd, LEDS_PGM4_2_ON);
		else
			ioctl(leds_fd, LEDS_PGM4_2_OFF);
		break;
	case LED_3:
		if (status)
			ioctl(leds_fd, LEDS_PGM4_3_ON);
		else
			ioctl(leds_fd, LEDS_PGM4_3_OFF);
		break;
	defautl :
		break;
	}

	close(leds_fd);

	return 0;
}

static const JNINativeMethod methods[] = {   //本地方法列表
	{"ledsOperation", "(IZ)I", (void *)leds_operation},  //"ledsOperation"为tiny4412Leds.java中的jni接口
};

/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)   
{
	JNIEnv *env;
	jclass cls;

	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "com/example/Tiny4412_leds/tiny4412Leds");  //包名+类名,将‘.’换成‘/’
	if (cls == NULL) {
		return JNI_ERR;
	}

	if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)  //注册本地方法
		return JNI_ERR;

	return JNI_VERSION_1_4;
}

JNI的C代码不算特别复杂,就是简单的将本地方法注册java虚拟机中;当java调用System.loadLibrary("tiny4412-leds");时,就会调用JNI_OnLoad方法,通过JNI_OnLoad方法注册tiny4412Leds类的本地方法到java虚拟机中,就会虚拟机中为tiny4412Leds类中添加本地接口,之后应用程序才能正常使用tiny4412Leds类的本地方法;


编译libtiny4412-leds.so

在ubuntu下将tiny4412-leds.c编译成libtiny4412-leds.so

root@pc:/home/workplace/Tiny4412# arm-linux-gcc -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/-I ./android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/include/ -fPIC -shared -o libtiny4412-leds.so tiny4412-leds.c -nostdlib android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/lib/libc.so   android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/lib/liblog.so

选项:-fPIC

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code), 则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

选项:-nostdlib

-nostdlib作用于编译阶段,告诉编译器不使用标准的lib库;


    如果不加上 -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  就会出现找不到jni.h的错误提示;

    如果不加上 -I ./android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/include/ 就会出现找不到log.h的错误提示;

    如果不加上 android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/lib/libc.so 加载libtiny4412-leds.so 就会出现;dlopen("/data/app/com.example.Tiny4412_leds-2/lib/arm/libtiny4412-leds.so", RTLD_LAZY) failed: dlopen failed: could not load library "libc.so.6" needed by "libtiny4412-leds.so"; caused by library "libc.so.6" not found 的错误提示;系统中默认没有libc.so.6库,所以可以直接指定使用libc.so进行代替;

    如果不加上 android-5.0.2/prebuilts/ndk/8/platforms/android-14/arch-arm/usr/lib/liblog.so 就会出现java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__android_log_print" referenced by "libtiny4412-leds.so"... 的错误提示;使用打印接口需要使用到liblog.so否则就会出错,该liblog.so可以在android源码中查找得到;


编译完成后在libs目录下创建armeabi目录,并将libtiny4412-leds.so拷贝到armeabi目录下,然后就可以运行程序




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值