您的位置:首页 > 移动开发 > Android开发

Android底层开发之JNI编程

2018-02-23 23:54 232 查看
Android中JNI编程—-android应用是如何与驱动进行交互

a, java代码调用jni的接口

b, jni代码的实现

jni: java native interface,java本地接口

或者是: java调用c/c++代码的接口

图1 JNI的实现原理



——————————————————————————————————————

app中: 与jni交互的接口;

1, 加载动态库

static{//优先执行

System.loadLibrary(“led_jni”); // /system/lib/libled_jni.so

}

2, 声明本地方法,名字和参数都是自定义

public native int openDev();

public native int devOn();

public native int devOff();

public native int closeDev();

3, 调用本地方法

LedNative myled;

myled = new LedNative();

myled.openDev();

接下来在eclipse中写相关代码:(功能:实现点灯)

创建new project



在UI中添加2个button



包名:com.example.ledcontrol

类:/LedControl/src/com/example/ledcontrol/LedActivity.java

package com.example.ledcontrol;
//这个程序不能直接在安卓模拟器运行
import com.example.lowlevel.LedNative;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.util.Log;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

//外加设置监听事件
public class LedActivity extends Activity implements OnClickListener{
final String TAG = "LedActivity";//写log
Button btn_led_on;
Button btn_led_off;
LedNative myled;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_led);

initUI();

// 3.调用本地方法
myled = new LedNative();
myled.openDev();    //这里有4个方法,这是其中之一

}
//实现
private void initUI() {
// TODO Auto-generated method stub
btn_led_on = (Button) findViewById(R.id.btn_led_on);//初始化
btn_led_on.setOnClickListener(this);//设置监听自己
btn_led_off = (Button) findViewById(R.id.btn_led_off);
btn_led_off.setOnClickListener(this);
}

@Override
//处理UI
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_led_on:
Toast.makeText(LedActivity.this, "亮灯啦-----", 1000).show();//显示效果
Log.d(TAG, "好亮啊-----");

myled.devOn();

break;
case R.id.btn_led_off:
Toast.makeText(LedActivity.this, "灭灯啦-----", 1000).show();
Log.d(TAG, "天黑请闭眼");

myled.devOff();

break;
default:
break;
}
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

myled.closeDev();
}
}


包名:com.example.lowlevel

类:/LedControl/src/com/example/lowlevel/LedNative.java

package com.example.lowlevel;
//这个程序不能直接在安卓模拟器运行
public class LedNative {
//1.加载动态库
static{ //优先执行
System.loadLibrary("led_jni");// /system/lib/libled_jni.so
}

//2, 声明本地方法,名字和参数都是自定义
public native int openDev();//在底层中先打开
public native int devOn();//控制过程
public native int devOff();
public native int closeDev();//最后关闭
}


——————————————————————————————————————————————————

在Ubuntu中去编写jni: 用sourceinsight

准备步骤:先把si_android404-android.tgz拷贝到目录下,并解压tar -xvf si_android404-android.tgz

接下来编写led_jni.cpp

编写方法:参考模板—development/samples/SimpleJNI/jni

实现JNI_onLoad()

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{

//获取到环境变量对象---提供各种操作方法---注册方法
JNIEnv *env = NULL;
jint vm->GetEnv(void * * env,jint version)

//构建映射表,注册给dvm

typedef struct {
const char* name; //java的方法名
const char* signature; //方法的描述
void*       fnPtr;//c/c++的函数名
} JNINativeMethod;

// 参数1-- java方法所在的包路径信息--通过env->FindClass得到
//参数2---映射表
//参数3--映射表中的项目个数
//返回值--错误为负数
jint env->RegisterNatives(jclass clazz,const JNINativeMethod * methods,jint nMethods)
}


代码led_jni.cpp

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

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

#include "jni.h"

static jint fd;
jint open_led(JNIEnv *env, jobject thiz)//记住参数
{
LOGD("-----------%s--------------\n", __FUNCTION__);

fd = open("/dev/led1", O_RDWR);
if(fd < 0)
{
LOGE("open error : %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);//第3个参数表示4字节
if(ret < 0)
{
LOGE("write on error : %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 off error : %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_jni_methods[] = {
{"openDev", "()I", (void*)open_led},
{"devOn", "()I", (void*)led_on},
{"devOff", "()I", (void*)led_off},
{"closeDev", "()I", (void*)close_led},
};

//实现JNI_onLoad()
//JNI_OnLoad返回值--正确为JNI_VERSION_1_4,错误为负数
jint JNI_OnLoad(JavaVM * vm,void * reserved)
{
LOGD("-----------%s--------------\n", __FUNCTION__);
JNIEnv *env = NULL;
jint ret;
//1.获取到环境变量对象---提供各种操作方法---注册方法
// 参数1--被初始化的env
//参数2--jni的版本
//返回值--正确为0,错误为负数
ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4);
if(ret != JNI_OK)
{
LOGE("vm->GetEnv error\n");
return -1;
}

//2.构建映射表,注册给dvm

jclass clz = env->FindClass("com/example/lowlevel/LedNative");
if(clz == NULL)
{
LOGE("env->FindClass error\n");
return -1;
}
// 参数1-- java方法所在的包路径信息--通过env->FindClass得到
//参数2---映射表
//参数3--映射表中的项目个数
//返回值--错误为负数
ret = env->RegisterNatives(clz,
led_jni_methods,
sizeof(led_jni_methods)/sizeof(led_jni_methods[0]));
if(ret < 0)
{
LOGE("env->RegisterNatives error\n");
return -1;
}

return JNI_VERSION_1_4;

}


代码Android.mk

1 LOCAL_PATH:= $(call my-dir)
2 include $(CLEAR_VARS)
3
4 LOCAL_MODULE_TAGS := optional
5
6 #编译后的目标文件,一定要和System.loadLibrary()名字保持一致
7 LOCAL_MODULE := libled_jni
8
9 #指定的原文件
10 LOCAL_SRC_FILES := led_jni.cpp
11
12 #因为使用了LOGD
13 LOCAL_SHARED_LIBRARIES := libutils
14
15 #因为使用了jni.h, LOCAL_C_INCLUDES用于jni.h的所在路径
16 LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
17
18 #把目标文件编译成动态库
19 include $(BUILD_SHARED_LIBRARY)


6 #编译后的目标文件,一定要和System.loadLibrary()名字保持一致

如图:



还要注意:JNI_H_INCLUDE



接下来执行程序

每次打开一个终端,先执行以下命令:



接着编译:



可以看到目标文件libled_jni.so安装到/system/lib…里面(这是安卓默认的路径,apk一般编译到system/app里面)

接着编写驱动程序 ko

需要用Makefile编译

在src_210目录下创建mydrv/led_drv/Makefile

ifeq ($(KERNELRELEASE),)
KERNELDIR = /home/george/src_210/linux-3.0.8-FS210
PWD =$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#arm-none-linux-gnueabi-gcc hello_test.c -o hello_test
#cp hello_test  hello.ko /opt/filesystem/s5pv210
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *_test  *.so *.o *.ko  .tmp_versions *.mod.c *.order *.symvers
else
obj-m :=s5pv210_led.o
endif




最后是运行:

apk—>安装到开发板

1,自动安装—/system/lib

2,手动安装—/mnt/sdcard/(需要重启)

vim init.fs210.rc

7 mkdir /mnt/sdcard 0777 system system

8 mkdir /mnt/ext_sd 0777 system system

9 mkdir /mnt/usb 0777 system system



jni.so --->  /system/lib
cp -raf out/target/product/fs210/system/lib/libled_jni.so  /opt/rootfs_dir/system/lib

drv.ko --> /system/lib/modules/
cp -raf s5pv210_led.ko  /opt/rootfs_dir/system/lib/modules/




接着把制作好的apk放到/opt/rootfs_dir/mnt/sdcard中





在开发板中:

logcat -c

logcat



I/ActivityManager( 2213): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.hq.ledcontrol cmp=com.hq.ledcontrol/.LedActivity} from pid 2884

D/dalvikvm( 3010): Not late-enabling CheckJNI (already on)

E/AudioHardware( 2139): AudioStreamOutALSA::write END WITH ERROR !!!!!!!!!(0x4667d0, 4096)

D/dalvikvm( 2213): GC_CONCURRENT freed 424K, 8% free 9263K/9991K, paused 14ms+45ms

I/ActivityManager( 2213): Start proc com.hq.ledcontrol for activity com.hq.ledcontrol/.LedActivity: pid=3010 uid=10053 gids={}

D/OpenGLRenderer( 2884): Flushing caches (mode 0)

D/led_jni_log( 3010): ———–JNI_OnLoad————–

D/led_jni_log( 3010): ———–open_led————–

E/led_jni_log( 3010): open error : No such file or directory // 驱动没有安装

解决:

/ # insmod /system/lib/modules/s5pv210_led.ko

再次启动:

/ # logcat

——— beginning of /dev/log/system

I/ActivityManager( 2213): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.hq.ledcontrol/.LedActivity} from pid 2487

——— beginning of /dev/log/main

D/dalvikvm( 2213): GC_FOR_ALLOC freed 317K, 10% free 9181K/10119K, paused 31ms

D/led_jni_log( 3010): ———–open_led————–

E/led_jni_log( 3010): open error : Permission denied //权限有问题

I/ActivityManager( 2213): Displayed com.hq.ledcontrol/.LedActivity: +240ms

W/IInputConnectionWrapper( 3010): showStatusIcon on inactive InputConnection

D/OpenGLRenderer( 2487): Flushing caches (mode 1)

D/OpenGLRenderer( 2487): Flushing caches (mode 0)

W/InputManagerService( 2213): Starting input on non-focused client com.android.internal.view.IInputMethodClientProxy@4139d230 (uid=10028 pid=2487)

D/LedActivity( 3010): 亮瞎了狗眼

D/led_jni_log( 3010): ———–led_on————–

E/led_jni_log( 3010): write on error : Bad file number

解决:

/ # chmod 777 /dev/led1

再次重启应用程序:



总结,每次打开应用程序都要装载驱动,修改权限,不方便,这时,我们可以

自动装载ko和修改权限: init.rc(/opt/rootfs_dir/)

283 insmod /system/lib/modules/s5pv210_led.ko

284 chmod 777 /dev/led1

285

286

287 on boot

288 # basic network init

程序链接地址:LED_CODE.zip(链接:https://pan.baidu.com/s/1dAGY2y 密码:os15)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: