android使用android jni开发实例,能不能使用信号的

【转】Android与JNI(二) -- 不错 - wi100sh - 博客园
随笔 - 1370, 文章 - 1, 评论 - 12, 引用 - 0
原文网址:/eddy-he/archive//2629974.html
软件版本:  ubuntu10.04  java version "1.6.0_30-ea"  eclipse  android-ndk-r5b
  1. 简介  2. JNI 组件的入口函数  3. 使用 registerNativeMethods 方法  4. 测试  5. JNI 帮助方法  6. 参考资料
  已经简单介绍了如何在 android& 环境下使用 JNI 了。但是遵循&JNI 开发的基本步骤似乎有点死板,而且得到的本地函数名太丑了。所以非常有必要在这里介绍另外一种实现方法。
2. JNI 组件的入口函数
  前一篇文章说到 static {System.loadLibrary("HelloJNI");}&会在第一次使用该类的时候加载动态库 libHelloJNI.so 。当 Android 的 VM 执行到&System.loadLibrary() 这个函数时,首先会执行 JNI_OnLoad() 这个函数。与此对应的是卸载时调用 JNI_OnUnLoad() 。
  首先调用 c 组件中的 JNI_OnLoad()& 的意图包括:
  (1) 告诉 VM 此 c 组件使用那一个 JNI 版本。如果动态库中没有提供 JNI_OnLoad(),VM 默认该动态库使用最老的 JNI 1.1 版本。由于新版的 JNI 做了许多扩充,如果需要使用 JNI 的新版功能,例如 JNI 1.4的 java.nio.ByteBuffer,就必须藉由 JNI_OnLoad() 函数来告知 VM。  (2) 另外一个作用就是初始化,例如预先申请资源等。
  现在我们先现实一个非常简单的&JNI_OnLoad(),看是不是在真的有调用到它。在 HelloJNI.c 中加入代码:
1 jint JNI_OnLoad(JavaVM* vm, void *reserved)
LOGD("%s called.\n", __FUNCTION__);
return JNI_VERSION_1_4;  // 注意这里要返回 JNI 的版本,否则会出错喔。
  编译:
$ndk-build
Compile thumb
: HelloJNI &= HelloJNI.c
SharedLibrary
: libHelloJNI.so
/home/eddy/workspace/HelloJNI/obj/local/armeabi/objs/HelloJNI/HelloJNI.o: In function `JNI_OnLoad':
/home/eddy/workspace/HelloJNI/jni/HelloJNI.c:35: undefined reference to `LOGD'
collect2: ld returned 1 exit status
make: *** [/home/eddy/workspace/HelloJNI/obj/local/armeabi/libHelloJNI.so] Error 1
  加入头文件&#include &utils/Log.h& 之后再编译:
$ndk-build
Compile thumb
: HelloJNI &= HelloJNI.c
/home/eddy/workspace/HelloJNI/jni/HelloJNI.c:20:23: error: utils/Log.h: No such file or directory
make: *** [/home/eddy/workspace/HelloJNI/obj/local/armeabi/objs/HelloJNI/HelloJNI.o] Error 1
  提示找不到指定的头文件。由于我们没有把这个 jni 放到整个 android 的源码中编译,所以遇到这个错误是正常的,解决的方法是在 Android.mk 中加入源码中头文件的路径。
LOCAL_CFLAGS += -Iyour_path/android4.0/include/frameworks/base/include
LOCAL_CFLAGS += -Iyour_path/android4.0/include/system/core/include
LOCAL_CFLAGS += -Iyour_path/android4.0/include/frameworks/base/opengl/include
LOCAL_CFLAGS += -Iyour_path/android4.0/include/system/core/include
  再编译:
$ndk-build
Compile thumb
: HelloJNI &= HelloJNI.c
SharedLibrary
: libHelloJNI.so
/home/eddy/workspace/HelloJNI/obj/local/armeabi/objs/HelloJNI/HelloJNI.o: In function `JNI_OnLoad':
/home/eddy/workspace/HelloJNI/jni/HelloJNI.c:36: undefined reference to `__android_log_print'
collect2: ld returned 1 exit status
make: *** [/home/eddy/workspace/HelloJNI/obj/local/armeabi/libHelloJNI.so] Error 1
  好吧,又出错了。但已经不是编译出错了,是链接出错,这个很简单,只要链接 liblog.so 这个库就可以了。在 Android.mk 中添加:
LOCAL_LDLIBS += -lc -lm -llog
  再编译:
$ndk-build
Compile thumb
: HelloJNI &= HelloJNI.c
SharedLibrary
: libHelloJNI.so
: libHelloJNI.so =& libs/armeabi/libHelloJNI.so
  OK,大功告成。如无意外,运行后你会在 logcat 中找到这样的打印:
/dalvikvm( 1956): Trying to load lib /data/data/com.example.hellojni/lib/libHelloJNI.so 0x
D/dalvikvm( 1956): Added shared lib /data/data/com.example.hellojni/lib/libHelloJNI.so 0x
( 1956): JNI_OnLoad called.
  这说明了在加载 JNI 的动态库时,确实调用了 JNI_OnLoad() 。调用了这个库又有什么用呢?下面为你揭晓。
3. 使用 registerNativeMethods 方法
  说了这么多,终于来重点了。先把修改后的 HelloJNI.c 列出来,然后再慢慢分析。
* Copyright (C) 2009 The Android Open Source Project
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
17 #include &string.h&
18 #include &jni.h&
19 #include "com_example_hellojni_HelloJNI.h"
20 #include &utils/Log.h&
22 #ifdef __cplusplus
23 extern "C" {
26 static const char* className = "com/example/hellojni/HelloJNI";
28 /* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
34 //jstring Java_com_example_hellojni_HelloJNI_stringFromJNI(JNIEnv *env, jobject this)
return (*env)-&NewStringUTF(env, "Hello from JNI !");
//return "Hello from Jni !";
39 jstring stringFromJNI(JNIEnv* env, jobject this)
return (*env)-&NewStringUTF(env, "Hello form JNI!");
44 static JNINativeMethod gMethods[] = {
{ "stringFromJNI", "()Ljava/lang/S", (void *)stringFromJNI },
48 // This function only registers the native methods, and is called from JNI_OnLoad
49 int register_location_methods(JNIEnv *env)
/* look up the class */
clazz = (*env)-&FindClass(env, className );
//clazz = env-&FindClass(env, className);
if (clazz == NULL) {
LOGE("Can't find class %s\n", className);
return -1;
LOGD("register native methods");
/* register all the methods */
if ((*env)-&RegisterNatives(env, clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
//if (env-&RegisterNatives(env, clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
LOGE("Failed registering methods for %s\n", className);
return -1;
/* fill out the rest of the ID cache */
75 jint JNI_OnLoad(JavaVM* vm, void *reserved)
JNIEnv* env = NULL;
jint result = -1;
LOGD("%s: +", __FUNCTION__);
if ((*vm)-&GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// for c++
//if( vm-&GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed.\n");
if( register_location_methods(env) & 0 )
LOGE("ERROR: register location methods failed.\n");
return JNI_VERSION_1_4;
101 void JNI_OnUnload(JavaVM* vm, void *reserved)
106 #ifdef __cplusplus
108 #endif
  先说一说这段代码实现了什么,他与 [1] 的结果完全一样,实现了 JAVA 中声明的 stringFromJNI 本地方法,返回一个字符串。至于为什么不再需要以Java_com_example_hellojni_HelloJNI_stringFromJNI&命名,就要慢慢分析了。
  还是从 JNI_OnLoad() 这个函数开始说起。该函数的动作包括:获取 JNI 环境对象,登记本地方法,最后返回 JNI 版本。值得引起注意的是第83和85行,在 c 环境下编译,使用第83行,c++ 环境下,使用第85行,否则会编译出错。
  登记本地方法,作用是将 c/c++ 的函数映射到 JAVA 中,而在这里面起到关键作用的是结构体&JNINativeMethod 。他定义在 jni.h 中。
1 typedef struct {
const char*     /* java 中声明的本地方法名称 */
const char*  /* 描述了函数的参数和返回值 */
fnP    /* c/c++的函数指针 */
5 } JNINativeM
  声明实例就是第44到46行。
1 static JNINativeMethod gMethods[] = {
{ "stringFromJNI", "()Ljava/lang/S", (void *)stringFromJNI },
  参数分析:
  "stringFromJNI":Java 中声明的本地方法名;  (void&*)stringFromJNI:映射对象,本地 c/c++ 函数,名字可以与 Java 中声明的本地方法名不一致。  "()Ljava/lang/S":这个应该是最难理解的,也就是结构体中的 signature 。他描述了本地方法的参数和返回值。例如  "()V"  "(II)V"  "(Ljava/lang/SLjava/lang/S)V"  实际上这些字符是与函数的参数类型一一对应的。  "()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();  "(II)V" 表示 void Func(int, int);  具体的每一个字符的对应关系如下  字符&& Java类型&&&& C类型  V&&&&& void&&&&&&&& void  Z&&&&& jboolean&&&& boolean  I&&&&&& jint&&&&&&&& int  J&&&&&& jlong&&&&&&& long  D&&&&& jdouble&&&&&& double  F&&&&& jfloat&&&&&&&&&&& float  B&&&&& jbyte&&&&&&&&&&& byte  C&&&&& jchar&&&&&&&&&& char  S&&&&& jshort&&&&&&&&& short  数组则以"["开始,用两个字符表示  [I&&&& jintArray&&&&&& int[]  [F&&&& jfloatArray&&&& float[]  [B&&&& jbyteArray&&&& byte[]  [C&&& jcharArray&&&&& char[]  [S&&& jshortArray&&&&& short[]  [D&&& jdoubleArray&&& double[]  [J&&&& jlongArray&&&&& long[]  [Z&&& jbooleanArray&&& boolean[]  上面的都是基本类型,如果参数是 Java 类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,而其对应的 C 函数的参数则为 jobject,一个例外是 String 类,它对应的 c 类型为 jstring 。  Ljava/lang/S&&&& String&&&& jstring  Ljava/net/S & && Socket && jobject  如果 JAVA 函数位于一个嵌入类(也被称为内部类),则用$作为类名间的分隔符,例如:"Landroid/os /FileUtils$FileS"。
  最终是通过第64行代码登记所有记录在&JNINativeMethod&结构体中的 JNI 本地方法。
  使用 registerNativeMethods 方法不仅仅是为了改变那丑陋的长方法名,最重要的是可以提高效率,因为当 Java 类透过 VM 呼叫到本地函数时,通常是依靠 VM 去动态寻找动态库中的本地函数(因此它们才需要特定规则的命名格式),如果某方法需要连续呼叫很多次,则每次都要寻找一遍,所以使用 RegisterNatives 将本地函数向 VM 进行登记,可以让其更有效率的找到函数。
  registerNativeMethods 方法的另一个重要用途是,运行时动态调整本地函数与 Java 函数值之间的映射关系,只需要多次调用 registerNativeMethods 方法,并传入不同的映射表参数即可。
  为了对&registerNativeMethods有更好的理解,我在 Java 中再添加一个本地方法。
1 package com.example.
3 import android.os.B
4 import android.app.A
5 import android.util.L
6 import android.view.M
7 import android.view.MenuI
8 import android.widget.TextV
9 import android.support.v4.app.NavU
11 public class HelloJNI extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hello_jni);
getActionBar().setDisplayHomeAsUpEnabled(true);
/* Create a TextView and set its content.
* the text is retrieved by calling a native
* function.
tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
Log.d("JNI", "max = " + max(10, 100));
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.hello_jni, menu);
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return super.onOptionsItemSelected(item);
/* A native method that is implemented by the
* 'HelloJNI' native library, which is packaged
* with this application.
public native String
stringFromJNI();
/* This is another native method declaration that is *not*
* implemented by 'HelloJNI'. This is simply to show that
* you can declare as many native methods in your Java code
* as you want, their implementation is searched in the
* currently loaded native libraries only the first time
* you call them.
* Trying to call this function will result in a
* java.lang.UnsatisfiedLinkError exception !
public native String
unimplementedStringFromJNI();
public native int max(int a,int b);
/* this is used to load the 'HelloJNI' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.HelloJni/lib/libHelloJNI.so at
* installation time by the package manager.
System.loadLibrary("HelloJNI");
  在 HellocJNI.c 中添加 max 的实现方法。
1 int native_max(JNIEnv* env, jobject this, int a, int b)
(a & b ? a:b);
6 static JNINativeMethod gMethods[] = {
{ "stringFromJNI", "()Ljava/lang/S", (void *)stringFromJNI },
{ "max", "(II)I", (void *)native_max },
  用 ndk 编译生成动态库。
$ndk-build
Compile thumb
: HelloJNI &= HelloJNI.c
SharedLibrary
: libHelloJNI.so
: libHelloJNI.so =& libs/armeabi/libHelloJNI.so
  在模拟器上 run as ---& Android Application 。可以看到打印:
D/dalvikvm( 2174): Trying to load lib /data/data/com.example.hellojni/lib/libHelloJNI.so 0x
D/dalvikvm( 2174): Added shared lib /data/data/com.example.hellojni/lib/libHelloJNI.so 0x
( 2174): JNI_OnLoad: +
( 2174): register native methods
( 2174): max = 100
  证明 max 调用成功。
  通过 registerNativeMethods 这种方法,我们可以看到操作的过程中,不需要再使用 javah -jni 生成 jni 头文件。c/c++ 的函数名也可以自由取名。
5. JNI 帮助方法
  在 Android 源码中&your_path/dalvik/libnativehelper/include/nativehelper/JNIHelp.h 这个头文件提供了一些关于 JNI 的帮助函数,包括本地方法注册、异常处理等函数。但是使用这些函数需要链接动态库 libnativehelper.so 。还提供了一个计算方法映射表长度的宏定义。
1 #ifndef NELEM
2 # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
  有了这个宏之后,我们就可以这样子写:
1 (*env)-&RegisterNatives(env, clazz, gMethods, NELEM(gMethods));
  6. 参考资料
  [1].&  [2].&  [3].&  [4].&Android在JNI中使用ByteBuffer的方法
作者:沧海一粟……
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android在JNI中使用ByteBuffer的方法,涉及Android中缓冲区的相关使用技巧,需要的朋友可以参考下
本文实例讲述了Android在JNI中使用ByteBuffer的方法。分享给大家供大家参考。具体如下:
一、ByteBuffer 定义
在NIO中,数据的读写操作始终是与缓冲区相关联的(读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区)
缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型。ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer。
ByteBuffer有以下几种常见属性:
mark:初始值为-1,标记索引地点;
position:初始值为0,索引下标;
limit:最好定义成bytebuffer的长度,即允许可读空间长度;
capacity:缓冲区能容纳的数据元素的最大数量,创建之后无法被改变;
二、ByteBuffer使用
1. 创建ByteBuffer
① 使用allocate()创建:
ByteBuffer buf = ByteBuffer.allocate(length);
//length表示buf的长度
② 使用数组创建:
ByteBuffer buf = ByteBuffer.wrap(byteArray);
//byteArray表示一个数组
2. 回绕缓冲区
buf.flip();
这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取。
3. 清除缓冲区
buf.clear();
这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区。
4. ByteBuffer与byte[]交互
byte[] bytearray = new byte[10];
ByteBuffer buf = ByteBuffer.wrap(bytearray);
//将数组写入buf
bytearray = new byte[buf.remaining()];
buf.get(bytearray,0,bytearray.length());
//将数据读到数组中
bytearray = new byte[buf.capacity()];
三、ByteBuffer与JNI交互
在Java1.4版本中引入的JNI有三个函数可以用于NIO的直接缓冲器。一个直接字节缓冲器是一个用于字节数据的容器,Java将尽力在它上面执行本机I/O操作。JNI定义了三个用于NIO操作的函数。
基于到存储器地址的指针以及存储器长度(容量),函数分配并且返回一个新的Java.nio.ByteBuffer。如果函数没有针对当前Java虚拟机实现,则返回NULL,或者抛出一个异常。如果没有存储器可用,则将会抛出一个OutOfMemoryException。
jobject NewDirectByteBuffer(void* address, jlong capacity);
GetDirectBufferAddress函数返回一个指向被传入的java.nio.ByteBuffer对象的地址指针。如果函数尚未针对当前虚拟机实现,或者如果buf不是java.nio.ByteBuffer的一个对象,又或者存储器区尚未定义,则都将返回NULL。
void* GetDirectBufferAddress(jobject buf);
GetDirectBufferCapacity函数返回被传入的java.nio.ByteBuffer对象的容量(以字节计数)。如果函数没有针对当前环境实现,或者如果buf不是java.nio.ByteBuffer类型的对象返回-1。
jlong GetDirectBufferCapacity(jobject buf);
1. Jni中调用
public final int processData(ByteBuffer data);
Native 接口:
private native long native_Process(ByteBuffer data);
static jlong native_Process(JNIEnv *env,jobject obj,jobject data);
注意ByteBuffer在JNI层中的签名:Ljava/nio/ByteB
2. 示例(C++):
jclass cls = env-&GetObjectClass(obj);
jfieldID fid = env-&GetFieldID(cls, "data","Ljava/nio/ByteB");
jobject bar = env-&GetObjectField(obj, fid);
pImageData-&data= (MByte*)env-&GetDirectBufferAddress(bar);
//data是结构体pImageData中的byte[];
希望本文所述对大家的Android程序设计有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具Android字符设备驱动及应用层从jni控制GPIO实战
&本文主要讲述从实际项目中一个GPIO口控制一个加密芯片上下电的功能,提供动态库给客户,并有Android应用层apk调用.so库文件的例子,希望能为大家字符设备驱动以及jni开发入门带来帮助!
以下描述参考摘录了别人的话:/blog/1424304
android应用层要访问驱动,一般有三种方法。&
1.应用层 ---& framwork层JNI ---& 驱动c&
2.应用层 ---& framwork层JNI ---& 硬件抽象层HAL ----& 驱动c&
3.应用层--&驱动c(读写字符设备)
三种方法,各有各的好处,第1种,方便与驱动调试实验,只要编译好ko文件和libxxx.so文件,放入系统中编译好就可以立即调试了。&
第2种JNI方法有些改变和增加了HAl,对驱动有了封装,简单来讲,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中。不要误会android把驱动分成两半了,其实android只是在驱动的调用接口上在增加一层对应接口功能来让framwork层JNI来调用。比如,驱动有read接口,HAl层就是封装read接口,做一个
hal_read接口,里面调用read接口,然后把hal_read接口给JNI调用。&
明白了吗?这方面有人讲得非常好,有兴趣的可以点击:&
http://blog.csdn.net/luoshengyang/article/details/6575988&
好处就是对对厂家来说能把商业秘密隐藏起来,我们做驱动实验的话,操作会极其复杂,不过对理解android整个系统都是极其用用的,因为它从下到上涉及到了android系统的硬件驱动层,硬件抽象层,运行时库和应用程序框架层等等。&
第3种涉及到Android上层读写设备节点,由于我们现在要讲的GPIO口是一个字符设备驱动,也会创建节点,所以可以通过此方法配置
这里由于客户需要我们的*.so库目前只讲第1种方法的实现:在此之前,请大家了解下JNI的编程方法,JNI是一种为JAVA和C、C++之间能互相访问所提供的编程接口(自行百度了解)
下面详细讲解开发过程(android系统大同小异),主要分为三部分:1.GPIO口字符设备驱动的实现,2.jni环境搭建及代码编写,3.应用层调用jni代码的实现
GPIO口字符设备驱动的实现
关于GPIO口字符设备驱动我们要做如下步骤:
1 &找到原理图对应的GPIO口并配置它为输出管脚
gpio口配置(不同平台配置不一样)但目的是一样的 设置GPIO口输出,并默认低电平,我们接的是57管脚
&&range 56 1 0x1500&
&&range 57 1 0x1500& & 代表57管脚做为gpio口使用,并默认低电平 & &
这个io口寄存器地址:0xe46002e4
但是调试过程中发现
#define gpio_lp 57&
gpio_request(gpio_lp,&pos_pwr&);
gpio_set_value(gpio_lp,1);
GPIO调用request报错,导致GPIO不能用但是换个GPIO口后换个gpio口就不报错了,
这种原因是由于intel的特殊性:gpio在vmm的地方被调用,在kernel下就不能操作它(一般平台这样操作没问题的)
后续,想到了另外一种方法
void __iomem *ldo_mmio_base = ioremap(0xe);
iowrite32(0x1700, ldo_mmio_base); & //1700代表设置寄存器(0xe46002e4)为GPIO口,输出 &为高
iowrite32(0x1500, ldo_mmio_base);//1500代表设置寄存器(0xe46002e4)为GPIO口,输出 为底 &
实现了IO口的控制
1.2 &源代码我们放到linux-3.10/drivers/char下面让系统生成设备节点:/dev/mypos
&linux-3.10依据自己的kernel名字不同而不同
linux-3.10/drivers/char/lp6252_switch.c & &
#include &linux/module.h&
/* For module specific items */
#include &linux/moduleparam.h&
/* For new moduleparam's */
#include &linux/types.h&
/* For standard types (like size_t) */
#include &linux/errno.h&
/* For the -ENODEV/... values */
#include &linux/kernel.h&
/* For printk/panic/... */
#include &linux/fs.h&
/* For file operations */^M
#include &linux/ioport.h&
/* For io-port access */
#include &linux/platform_device.h&
/* For platform_driver framework */
#include &linux/init.h&
/* For __init/__exit/... */
#include &linux/uaccess.h&
/* For copy_to_user/put_user/... */
#include &linux/io.h&
/* For inb/outb/... */
#include &linux/gpio.h&
#include &linux/device.h&
#include &linux/cdev.h&
#include &linux/slab.h&
/*kamlloc */
//#include &asm-generic/ioctl.h&
#define CMD_FLAG
'i'
#define POS_PWR_ON
_IOR(CMD_FLAG,0x,__u32)
#define POS_PWR_OFF
_IOR(CMD_FLAG,0x,__u32)
#define gpio_lp
static int
static struct class *pos_
struct cdev_pos {
struct cdev_pos *pos_
static int pos_ioctl(struct file* filp,unsigned int cmd,unsigned long argv)
printk(KERN_INFO &entry kernel.... \n&);
printk(KERN_INFO &%d\n&, POS_PWR_ON);
&span style=&color:#ff0000;&&void __iomem *ldo_mmio_base = ioremap(0xe);&/span&
switch(cmd)
case POS_PWR_ON:
gpio_set_value(gpio_lp,1);
printk(KERN_INFO &POS on\n&);
iowrite32(0x1700, ldo_mmio_base)
case POS_PWR_OFF:
gpio_set_value(gpio_lp,0);
printk(KERN_INFO &POS off \n&);
#endif&/span&
iowrite32(0x1500, ldo_mmio_base);
return -EINVAL;
static int pos_open(struct inode* i_node,struct file* filp)
printk(KERN_INFO &taosong open init.... \n&);
err = gpio_request(gpio_lp,&pos_pwr&);
printk(KERN_INFO &gpio request faile \n&);
gpio_direction_output(gpio_lp,1);
static void pos_close(struct inode* i_node,struct file* filp)
printk(KERN_INFO &taosong close init \n&);
gpio_free(gpio_lp);
/* file operations */
struct file_operations fops={
= THIS_MODULE,
= pos_open,
.unlocked_ioctl = pos_ioctl,
.release= pos_close,
static int __init pos_init(void)
printk(KERN_INFO &init .... \n&);
dev_t dev_
int result,
err = alloc_chrdev_region(&dev_no,0,1,&my_pos&); //dynamic request device number
printk(KERN_INFO &ERROR\n&);
major = MAJOR(dev_no);
pos_dev = kmalloc(sizeof(struct cdev_pos),GFP_KERNEL);
if(!pos_dev)
result = -ENOMEM;
goto fail_
memset(pos_dev,0,sizeof(pos_dev));
cdev_init(&pos_dev-&cdev,&fops);
pos_dev-&cdev.owner = THIS_MODULE;
result = cdev_add(&pos_dev-&cdev,dev_no,1);
if(result &0)
printk(KERN_INFO &error\n&);
goto fail_
pos_class = class_create(THIS_MODULE,&mypos&);
//in sys/class create sysfs file
device_create(pos_class,NULL,MKDEV(major,0),NULL,&mypos&); //dynamic create device file
/dev/mypos
kfree(pos_dev);
fail_malloc:
unregister_chrdev_region(dev_no,1);
static void __exit pos_exit(void)
dev_t dev_no=MKDEV(major,0);
unregister_chrdev_region(dev_no,1);
cdev_del(&pos_dev-&cdev);
kfree(pos_dev);
device_destroy(pos_class,dev_no);
class_destroy(pos_class);
printk(KERN_INFO &exit........ \n&);
module_init(pos_init);
module_exit(pos_exit);
MODULE_AUTHOR(&*@*.com&);
MODULE_DESCRIPTION(&control_pos_power&);
MODULE_LICENSE(&GPL&);
要让此代码生效编译进去:
在相应的makefile改过来
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index e562ed5..98e871f 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -2,6 +2,7 @@
&# Makefile for the kernel character device drivers.
+obj-y & & & & & & & & & & & & &+= lp6252_switch.o
&obj-y & & & & & & & & & & & & &+= mem.o random.o
&obj-$(CONFIG_TTY_PRINTK) & & & += ttyprintk.o
&obj-y & & & & & & & & & & & & &+= misc.o
这样加入lp6252_switch.c并修改Makefile后固件生成就会在 /dev/ 下生成节点 & /dev/mypos
要让这个节点让别人可读写,还必须修改节点的系统所有者以及他的权限,这个步骤我们一版在 init.rc中进行
我的代码是system/core/rootdir/init.rc
diff --git a/core/rootdir/init.rc b/core/rootdir/init.rc
index fc5d73f..b644
--- a/core/rootdir/init.rc
+++ b/core/rootdir/init.rc
@@ -308,6 +308,8 @@ on boot
& & &chmod 0777 /dev/ttyS1
& & &chmod 0777 /sys/devices/l68ie_switch/chip_switch
+ & &chown system system /dev/mypos
+ & &chmod 0766 /dev/mypos
& & &chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate
& & &chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate
至此一个可用的字符设备节点&/dev/mypos&已经生成并能供给上层可读写的权限
二.jni环境搭建及代码编写
2.1 NDK本地开发环境搭建
这里主要介绍在eclipse上搭建NDK开发环境。
以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin(模拟Linux环境用的),下载CDT(Eclipse C/C++开发插件),还要配置编译器,环境变量...
麻烦到不想说了,本人在网上查了一下资料,发现了一个超级快配置NDK的办法。
Step1:到Android官网下载Android的开发工具ADT(Android Development Tool的缩写),该工具集成了最新的ADT和NDK插件以及Eclipse,还有一个最新版本SDK。解压之后就可以用了,非常爽!
ADT插件:管理Android SDK和相关的开发工具的 & &
NDK插件:用于开发Android NDK的插件,ADT版本在20以上,就能安装NDK插件,另外NDK集成了CDT插件
也可以在线更新ADT、NDK插件,不过速度超级慢...所以果断在网上下载集成开发工具ADT,下载链接见:/sdk/index.html & 本地百度云地址链接:/s/1slcVhxF 密码:ucf9
Step2:到Android官网下载最新的NDK,注:NDK版本在r7(本文使用android-ndk-r9b)以上之后就集成了Cygwin,而且还是十分精简版。比起下载Cygwin要方便多啦!
下载链接见:/tools/sdk/ndk/index.html &
android-ndk-r9b&百度云地址链接:/s/1hrPGtKC
密码:od7o
Step3:打开Eclipse,点Window-&Preferences-&Android-&NDK,设置NDK路径,例如我的是E:\qf项目0\android-ndk-r9b-windows-x86\android-ndk-r9b
Step4:新建一个Android工程,在工程上右键点击Android
Tools-&Add Native Support...,然后给我们的.so文件取个名字,例如:poscontrol&
这时候工程就会多一个jni的文件夹,jni下有Android.mk和poscontrol.cpp(我这里改成.c文件了)文件。Android.mk是NDK工程的Makefile,poscontrol.cpp就是NDK的源文件。
Step5:右键项目工程点击Run
as &就会生成libposcontrol.so
Step6:完成了,然后运行。运行之前先编译NDK,然后在编译JAVA代码。编译也许会遇到Unable to launch cygpath. Is Cygwin on the path?错误,解决办法如下:
1.工程右键,点Properties-&C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd
2.在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录
3.再编译,问题就解决啦!
2.2 jni代码编写
poscontrol.c
#include&stdio.h&
#include&stdlib.h&
#include&fcntl.h&
#include&errno.h&
#include&unistd.h&
#include&sys/ioctl.h&
#include&jni.h&
// 一定要包含此文件
#include&string.h&
#include&sys/types.h&
#include&sys/stat.h&
#include &android/log.h&
//驱动里的命令码.
#define CMD_FLAG 'i'
#define LED_ON
_IOR(CMD_FLAG,0x,__u32)
#define LED_OFF
_IOR(CMD_FLAG,0x,__u32)
#define DEVICE_NAME &/dev/mypos&
static const char *TAG=&012&;
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,
TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
/* * Class:
* Signature: ()I
JNIEXPORT void JNICALL Java_com_idean_s600_pay_manage_IntelPosPowerManager_posPowerOn(JNIEnv* env, jclass mc)
LOGI(&POWER ON BY QINFENG&);
LOGI(&LED_ON:%d
LED_OFF:%d&,LED_ON,LED_OFF);
fd=open(DEVICE_NAME,O_RDWR);
LOGI(&don't open dev&);
ioctl(fd,LED_ON,NULL) ;
LOGI(&open success&);
/* * Class:
* Signature: ()V
JNIEXPORT void JNICALL Java_com_idean_s600_pay_manage_IntelPosPowerManager_posPowerOff(JNIEnv* env, jclass mc)
LOGI(&POWER Off BY QINFENG&);
ioctl(fd,LED_OFF,NULL) ;
close(fd);
关于驱动接口的说明:#define DEVICE_NAME &/dev/mypos&这个使我们驱动生成的节点,我们后面通过fd=open(DEVICE_NAME,O_RDWR);ioctl(fd,LED_ON,NULL) ;调用节点并通过底层相对应的CMD (LED_ON
OR LED_OFF)控制节点的高低电平(加密芯片的上电和下电)
主要提供两个接口给上层调用:
JNICALL Java_com_idean_s600_pay_manage_IntelPosPowerManager_posPowerOnJava_com_idean_s600_pay_manage_IntelPosPowerManager_posPowerOff
根据JNI的规则:
com_idean_s600_pay_manage_IntelPosPowerManager& & &包名:package com.idean.s600.pay.
类名:IntelPosPowerManager
而posPowerOn &posPowerOff &为上层要调用的本地接口
在这里特别说明下,JNI的格式规范要注意的地方:&
1.函数声明的格式:&
& 因JNI会把 '_' 转换成' . ' 所以在类名和函数接口中不要出现' _ ',以免应用层调用不到JNI接口,这方面对初学者来说极其重要,所以用eclipse生成的android类文件,最好改下类名。不了解对实验的热情打击比较重。&
2.JNI函数分本地方法和静态方法。&
& 本地方法:&
&&&&&&& public native int jni();& // 不带static 声明.&
& 对应的 JNI 函数中参数的定义有改动:&
&&&&&&& Java_xx_xx_LedControl_jni(JNIEnv*env, jobject obj)&
& 静态方法:&
&&&&&&&& public static native int jni();& // 带static 声明.&
& 对应的 JNI 函数中参数的定义有改动:&
&&&&&&& Java_xx_xx_LedControl_jni(JNIEnv*env, jclass cls)&
jobject 和jclass的变动。&
Android.mk代码如下:
LOCAL_PATH := $(call my-dir)
$(CLEAR_VARS)
LOCAL_LDLIBS
& &:= -lm -llog&
LOCAL_MODULE
& &:= poscontrol
LOCAL_SRC_FILES
:= poscontrol.c
$(BUILD_SHARED_LIBRARY)
注意LOCAL_MODULE & &:poscontrl 代表生成的是libposcontrol.so
& apk上层调用的库文件必须一致
(ndk目录路径)/JNI/(应用工程文件)/& 路径下 & (个人理解可以本地cmd输入命令编译)
输入命令 : ../../ndk-build&
会生成 libs 和obj 2个文件。 libposcontrol.so文件放在 libs /armeabi/ 下&
至此,JNI编译成功,连接上层关于GPIO的字符驱动节点和上层可调用的SO库文件
三.应用层调用jni代码的实现(apk编写)
关于这节主要贴一下源代码:
IntelPosPowerManager.java
package com.idean.s600.pay.
import android.media.AudioM
import android.os.B
import android.app.A
import android.content.I
import android.util.L
import android.view.M
import android.view.V
import android.view.View.OnClickL
import android.widget.B
public class IntelPosPowerManager extends Activity {
private Button power_
private Button power_
private OnClickL
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intel_pos_power_manager);
(Button)findViewById(R.id.power_on);
power_off= (Button)findViewById(R.id.power_off);
//成功点击事件
power_on.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d(&012&, &power_on by android\n&);
posPowerOn();
power_off.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d(&012&, &power_off by android\n&);
posPowerOff();
protected void onDestroy(){
super.onDestroy();
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater()
.inflate(R.menu.activity_intel_pos_power_manager, menu);
Log.i(&012&,&try to load poscontrol.so&);
System.loadLibrary(&poscontrol&);
//加载本地库,也就是JNI生成的libxxx.so文件,下面再说。
}catch (UnsatisfiedLinkError ule){
Log.e(&012&,&WARNING: Could not load poscontrol.so&);
* 控制金融芯片上电
public native static void posPowerOn();
* 控制金融芯片下电
public native static void posPowerOff();
注意的点: System.loadLibrary(&poscontrol&);
poscontrol名字要和.so库对应起来本地调用方法:
 控制金融芯片上电
public native static void posPowerOn();
控制金融芯片下电
public native static void posPowerOff();
附录xml文件布局:
activity_intel_pos_power_manager.xml
&?xml version=&1.0& encoding=&utf-8&?&
&RelativeLayout xmlns:android=&/apk/res/android&
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:id=&@+id/position&
android:layout_centerInParent=&true&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:textSize=&25sp&
android:textColor=&#ff0000&
android:text=& power control &
android:id=&@+id/power_on&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:textSize=&18sp&
android:text=&power_on&
android:layout_toLeftOf=&@+id/position&
android:layout_centerHorizontal=&true&
android:layout_alignTop=&@+id/position&
android:id=&@+id/power_off&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:textSize=&18sp&
android:text=&power_off&
android:layout_toRightOf=&@+id/position&
android:layout_alignTop=&@+id/position&
&/RelativeLayout&
至此,从底层GPIO字符设备驱动 到 JNI 库文件实现,到上层apk调用JNI本地接口功能全部实现
apk下载地址:http://download.csdn.net/detail/qf
通过按钮 power_on 和 power_off 就能够控制GPIO口的高低电平了
Android NDK开发篇(一):新版NDK环境搭建(免Cygwin,超级快)/kf/918.html
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?}

我要回帖

更多关于 android ndk jni开发 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信