欢迎转载,务必注明出处。http://blog.csdn.net/wang_shuai_ww/article/details/44456755

本篇是继《s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录》之后的另外一种添加JNI和服务的方法。

前面的方法是直接把HAL和服务层添加到了,Android的api中,这样的方式好处是操作系统已开发完成,剩下做APP的开发,那么我们只需要一个classes.jar文件即可使用我们自己Android系统的被隐藏的PI了(在Android官方的sdk中没有的API和用户自己添加的API),在运行自己Android系统的平台可直接方便的测试。当然也可以做出自己的android.jar文件放到sdk的platforms对应的android版本中,替换之前的android.jar,那么以后选择该目标Android版本时,加载的就是我们自己的Android系统的API了,可以像android.os.xxx这样调用我们的接口。

本篇介绍的是动态加载JNI的方式,顾名思义,就是在apk运行的时候去加载我们写好的.so JNI库。本方法灵活,开发移植使用也很方便,也不用在源码树中进入framework等目录进行各种繁琐的操作,只需要写一个满足要求的.c文件,编译生成对应的.so文件就行了,而且对于存放的位置没有什么特别要求,我一般放在对应的板级目录下(/device/nexell/realarm)。

看起来比直接添加到Android的api中要方便多了,最起码简洁多了,没那么繁琐,只是该方法在eclipse中需要多建立一个类文件,不过也没什么大不了的,O(∩_∩)O。对于想快速学习,添加自己的led操作的朋友来说,本篇的方法非常合适。

对于动态JNI,首先引用 三篇博文,地址是http://blog.sina.com.cn/s/blog_4c451e0e0101339i.html、http://www.cnblogs.com/simonshi/archive/2011/01/25/1944910.html、http://blog.csdn.net/happy08god/article/details/11405607。朋友们可以多读读,看看他们介绍的相同和不同之处。

本篇文章是在参考多篇博文之后自己编写代码在开发板上测试通过后记录写下的,大家可以参考代码写出自己的程序。然后对比与其他博文的不同之处。

我的源码目录是/device/nexell/realarm/led2,在该目录下有两个文件led2.c和Android.mk。它们的源码如下:

led2.c:

#include <stdio.h>  #include "jni.h"
#include "JNIHelp.h"
#include <assert.h> // 引入log头文件
#include <android/log.h>
// log标签
#define  TAG    "Led_Load_JNI"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)<span style="color:#ff0000;">#define DEVICE_NAME     "/dev/real_led"#define NO_REGISTER</span><span style="color:#ff0000;">#ifndef NO_REGISTER</span>
static jint Java_realarm_hardware_HardwareControl_LedSetState(JNIEnv *env, jobject thiz,jint ledNum,jint ledState)
#else
JNIEXPORT jint JNICALL Java_realarm_hardware_HardwareControl_LedSetState(JNIEnv *env, jobject thiz,jint ledNum,jint ledState)
#endif
{int fd = open(DEVICE_NAME, 0);if (fd == -1){LOGE("led open error");return 1;  }if(ledState == 0)LOGD("Led close success");else if(ledState == 1)LOGD("Led open success");else {LOGD("Led ledState parameters ERROR.Only 0 or 1.");return 1;}ledState &= 0x01;ioctl(fd, ledState, 0);close(fd);return 0;
}
<span style="color:#ff0000;">#ifndef NO_REGISTER</span>
static JNINativeMethod gMethods[] = {  {"LedSetState", "(II)I", (void *)Java_realarm_hardware_HardwareControl_LedSetState},
}; static int register_android_test_led(JNIEnv *env)
{  jclass clazz;static const char* const kClassName =  "realarm/hardware/HardwareControl";/* look up the class */clazz = (*env)->FindClass(env, kClassName);//clazz = env->FindClass(env,kClassBoa);if (clazz == NULL) {LOGE("Can't find class %s\n", kClassName);return -1;}/* 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", kClassName);return -1;}/* fill out the rest of the ID cache */return 0;
}
#endif
jint JNI_OnLoad(JavaVM* vm, void* reserved) {<span style="color:#ff0000;">#ifndef NO_REGISTER</span>JNIEnv *env = NULL;if ((*vm)->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) {  //if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {  LOGI("Error GetEnv\n");  return -1;  } assert(env != NULL);  if (register_android_test_led(env) < 0) {  printf("register_android_test_led error.\n");  return -1;  }
#endif/* success -- return valid version number */LOGI("/*****************realarm**********************/");return JNI_VERSION_1_4;
}

本代码在了解其原理后做了一些处理,本代码可以使用两个方式来最终引用LedSetState的C/C++实现,具体的控制,就是上面代码的红色部分的宏。

1.如果定义了上面的宏,那么JNI_OnLoad函数里面有用的就是最后一句话,return JNI_VERSION_1_4;返回JNI版本,并没有对LedSetState的C/C++实现函数进行注册,那么Android又怎么识别呢。如果是这种情况的话,Android会根据java层对JNI引用的类里面的native定义自动搜索对应的JNI方法,那么这就对函数定义的名字有要求了,格式为java_包名_类名_函数名字,Android的app在调用HardwareControl类里面的LedSetState方法时,就会自动匹配到对应的JNI方法。这种方法有个缺点,就是需要消耗CPU资源去匹配函数,导致运行效率不高,当程序大时就麻烦了。

2.因此推荐使用不定义上面红色的宏的方式,这样的话,在调用这个库时,就会把LedSetState函数通过(*env)->RegisterNatives这个注册,把它与Java_realarm_hardware_HardwareControl_LedSetState绑定在一起,而apk在调用LedSetState方法时执行效率就高多了,不用去自动匹配了,因为已经明白告诉操作系统该调用哪个函数了。

Android.mk:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := led2.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE := libLedJniinclude $(BUILD_SHARED_LIBRARY)

从上面代码可知道,我编译生成的库名为libLedJni.so,注意LOCAL_MODULE_PATH要使用上图所示的路径,也就是/system/lib目录,在动态加载时,也是去这个目录下寻找。

好,到这里JNI库就完成了,我们使用adb push命令把它发到开发板的/system/lib目录下,在下一篇将介绍怎么使用它。

Android 4.4.2 动态添加JNI库方法记录 (一 JNI库层)相关推荐

  1. android 点动态显示图片,Android用RecyclerView实现动态添加本地图片

    本文介绍了Android用RecyclerView实现动态添加本地图片,分享给大家,具体如下: 简单介绍一下用法: 1.跳转到图片选择页面: Intent intent = new Intent(Pa ...

  2. 我的Python学习笔记(四):动态添加属性和方法

    一.动态语言相关概念 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C# ...

  3. Android编译调用FFmpeg API,自己写方法,编译so库

    作者:谭东 时间:2017年9月19日 环境:Windows 8.1专业版 NDK版本:android-ndk-r14b FFmpeg版本:FFmpeg 3.0.2 "Einstein&qu ...

  4. vue脚手架的安装、生命周期、文件导入格式、局部组件和全局组件、动态添加属性和方法、插槽、传值

    -----------------------------------    DOS命令 进入dos:  win+r 切换盘符: d: 查看: dir 打开文件夹: cd 文件夹的名字 返回上一级目录 ...

  5. ios 静态库合成_iOS生成静态库方法-iOS集成静态库-iOS合并静态库

    在iOS的开发过程中,我们常常用到第三方的库.尤其是QQ.百度地图.广告等. 那么,如何制作自己的库文件呢? 如果,将自己写的功能类编译成库文件,分发给其他人来使用呢? 静态库的优点 编译静态库的好处 ...

  6. Android 4.4.2 动态添加JNI库方法记录 (二 app应用层)

    欢迎转载,务必注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44458553 源码下载地址:http://download.csdn. ...

  7. Android开发之RecyclerView动态添加item长按删除item源码

    我们先看下效果图: 效果还是很不错的. 实现思路: 设置recyclerview为GridLayoutManager布局,单行个数为4个 GridLayoutManager linearLayoutM ...

  8. Android ListView分页,动态添加数据

    1.ListView分页的实现,重点在于实现OnScrollListener接口,判断滑动到最后一项时,是否还有数据可以加载, 我们可以利用listView.addFootView(View v)方法 ...

  9. Android开发之Android Studio依赖aar包的四种方法(附加第三方库依赖方式)

    使用AS任意版本: 方法一: repositories {flatDir {dirs 'libs'}} implementation (name: 'paylibrary_v1.0', ext: 'a ...

最新文章

  1. 面试官:连YOLO都搞不定,是自己走还是我送你
  2. bat修改文件内容_批量获取文件名,这几招太高效了!
  3. 对于这个函数const int func(const int a) const声明中,三个const分别是什么意思?...
  4. python中国大学排名爬虫写明详细步骤-Python之爬虫-中国大学排名
  5. BOOST_PREDEF_TESTED_AT宏相关的测试程序
  6. ansys命令流_ANSYS命令流建模3之划分单元+施加弹簧
  7. Oracle中不常用命令
  8. tracepro杂散光分析例子_光学系统杂散光分析(1)
  9. 三校生计算机word基础知识,三校生计算机第一次月考计算机基础、word.doc
  10. ssas 维度属性_Analysis Services(SSAS)多维数据集–维度属性和层次结构
  11. cloud源码-Feign
  12. numpy.ndarray.flat/flatten 与 Spark 下的 flatMap
  13. 关于FileAttributes
  14. ExoPlayer之SampleQueue
  15. Outlook 与企业微信邮箱通讯录同步
  16. 智慧城市同城小程序V4_1.0.86后端+双前端
  17. 基于Python实现的在线教育系统考试作业案例源代码APP大作业nodejs程序设计微信小程序计算机
  18. MVC三层架构各层含义
  19. 说文解字----矩阵分析(一)矩阵中的空间与秩
  20. 我向大家推荐一款手机APP——可可英语

热门文章

  1. Mxnet的.lst文件介绍
  2. csgo服务器linux云崖居,CSGO修改地图天气背景指令
  3. python前后端分离前端权限_Linux上搭建前后端分离项目
  4. 云服务器磁盘挂载_云小课 | 磁盘容量不够用?小课教你来扩容!
  5. gre可以用计算机,GRE数学能用计算器吗
  6. 陕西省铜川市计算机学校,铜川市计算机专业学校怎么样?好不好?
  7. java交换integer_Java比较和交换语义和性能
  8. 二维分类教案_大班数学二维分类教案
  9. Apache Flink 零基础入门(二):使用docker快速搭建Flink
  10. CentOS6.7安装mysql5.7