欢迎转载,务必注明出处。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 := libLedJni include $(BUILD_SHARED_LIBRARY)

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

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

Android 4.4.2 动态加入JNI库方法记录 (一 JNI库层)的更多相关文章

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

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

  2. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)

    Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...

  3. [置顶] android利用jni调用第三方库——第三篇——编写库android程序整合第三方库libhello.so到自己的库libhelloword.so

    0:前言: 在第二篇中,我们主要介绍了丙方android公司利用乙方C++公司给的动态库,直接调用库中的方法,但是这样方式受限于: 乙方C++公司开发的动态库是否符合jni的规范,如果不规范,则不能直 ...

  4. 【转载】cocos2dx 中 Android NDK 加载动态库的问题

     原文地址:http://blog.csdn.net/sozell/article/details/10551309 cocos2dx 中 Android NDK 加载动态库的问题 闲聊 最近在接入各 ...

  5. Android studio 下JNI编程实例并生成so库

    Android studio 下JNI编程实例并生成so库 因为公司需要为Android相机做美颜等图像后期处理,需要使用JNI编程,最近学了下JNI,并且在Android Studio下实现了一个小 ...

  6. 《android开发艺术探索》读书笔记(十四)--JNI和NDK编程

    接上篇<android开发艺术探索>读书笔记(十三)--综合技术 No1: Java JNI--Java Native Interface(java本地接口),它是为了方便java调用C. ...

  7. Android Studio中通过CMake使用NDK并编译自定义库和添加预编译库

    Note:这篇文章是基于Android Studio 3.01版本的,NDK是R16. step1:创建一个包含C++的项目 其他默认就可以了. C++ Standard 指定编译库的环境,其中Too ...

  8. Ubuntu系统下实现Android工程调用独立编译的C++程序和GMP、PBC库

    目的: 实现使用C++编写代码供Android工程调用.C++代码中可以使用STL库,也可以使用常用的由源码编译生成的库,如PBC.因为PBC是基于GMP库的,所以这里只记录了GMP和PBC库的编译安 ...

  9. Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

    一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...

随机推荐

  1. 第2节 mapreduce深入学习:4, 5

    第2节 mapreduce深入学习:4.mapreduce的序列化以及自定义排序 序列化(Serialization)是指把结构化对象转化为字节流. 反序列化(Deserialization)是序列化 ...

  2. C# WebService 的缓存机制

    C# WebService 的缓存机制   [转]WebService的缓存机制 2008年02月19日 星期二 11:22 WebService的缓存分为两种,一种是简单的输出缓存,一种是强大的数据 ...

  3. thinkphp5将一条数据以toArray()放入session

    直接将找出的数据赋予变量,列:$admin: 存入session:Session::set('user_info',$admin->toArray()); 如果数据中有时间字段: 如若有时间字段 ...

  4. source collection list

    1.Anaconda:http://www.cnblogs.com/xiaoming123abc/p/6970890.html https://conda.io/docs/help-support.h ...

  5. Android图像处理之BitMap(2)

    Bitmap 相关 1. Bitmap比较特别 因为其不可创建 而只能借助于BitmapFactory 而根据图像来源又可分以下几种情况: * png图片 如:R.drawable.tianjin J ...

  6. iOS sandbox

    iOS的沙盒机制,应用只能访问自己应用目录下的文件.iOS不像android,没有SD卡概念,不能直接访问图像.视频等内容.iOS应用产生的内容,如图像.文件.缓存内容等都必须存储在自己的沙盒内.默认 ...

  7. react-native 0.58版本打包图片问题 task ':app:mergeReleaseResources' Error: Duplicate resources

    debug没问题,在生成正式apk的时候就如下: google了一下在github上找到了解决方案: github问题指向 在node_modules/react-native/react.gradl ...

  8. [Python3网络爬虫开发实战] 2.1-HTTP基本原理

    在本节中,我们会详细了解HTTP的基本原理,了解在浏览器中敲入URL到获取网页内容之间发生了什么.了解了这些内容,有助于我们进一步了解爬虫的基本原理. 1. URI和URL 这里我们先了解一下URI和 ...

  9. [Python3网络爬虫开发实战] 1.3.2-Beautiful Soup的安装

    Beautiful Soup是Python的一个HTML或XML的解析库,我们可以用它来方便地从网页中提取数据.它拥有强大的API和多样的解析方式,本节就来了解下它的安装方式. 1. 相关链接 官方文 ...

  10. CSS——可视化格式模型

    CSS的可视化格式模型 CSS中规定每一个元素都有自己的盒子模型(相当一规定了这个元素如何显示): 然后可视化格式模型则是把这些盒子模型按照规则摆放到页面上,也就是如何布局: 换句话说,盒子模型规定了 ...