博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Freescale IMX6 Android (5): APP通过JNI控制LED
阅读量:4170 次
发布时间:2019-05-26

本文共 6293 字,大约阅读时间需要 20 分钟。

本篇博客接上一篇的:,上一篇是直接将控制程序放到了Toolbox,本篇则是通过JNI调用C库来完成LED的控制,即APP--> C --> HW。

APK的编写(源码见末尾)

编写主要需要注意下面个事项与步骤

1. 更改xml在layout中添加控件

2. Checkbox与Button的添加及其click与checked事件的handler

3. Toast的使用

4. API版本问题

5. 文档的查询

UI的layout如下:

然后添加checkbox与button的callback。

添加调用C语言native方法的java库

直接在App下的java中添加一个package,然后添加一个class,如下图的libledctrl中的HWLedCtrl:

图一

其中的内容也很简单,就是建立一个static代码块,同时将native函数声明为static函数,这样子因为static代码块是存在class中的,不需要new一个对象来操作,其中HWLedCtrl.java的内容如上图:

package libledctrl;/** * Created by hexiongjun on 12/11/15. */public class HWLedCtrl {    public static native int ledctrl(int which, int status);    public static native int ledopen();    public static native void ledclose();    static {        try {            System.loadLibrary("ledctrl");        } catch (Exception e) {            e.printStackTrace();        }    }}
可以看到这里面加载了libledctrl.so这个库,这个就是下面的内容。

有了native方法与class之后,我们就可以在APP更改checkbox与button的时候更改led状态了:

这里面首先是Open,然后是进行亮灭状态切换。

C库的制作

在前面博客中的C语言代码基础上,我们去掉main函数,将其改成符合JNI接口的C源码:

#include "jni.h"//#include "JNIHelp.h"//#include "android_runtime/AndroidRuntime.h"//#include 
//#include
//#include
#include
#include
#include
#include
#include
#include
#define ALOGI printf#define LED_NUM 3int leds_fd[LED_NUM];char path_buff[255];static jint ledctrl(JNIEnv *env, jobject clazz, jint which, jint status){ int ret = -1; if(status == 1) { ret = write(leds_fd[which], "255", 3); } else { ret = write(leds_fd[which], "0", 1); } if(ret < 0){ return -1; } ALOGI("Native ctrl fd = [%d]\n", which); return 0;}static jint ledopen(JNIEnv *env, jobject clazz){ int i = 0; printf("Native Open\n"); for(i=0; i
GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) { printf("Version Error in JNI OnLoad\n"); return JNI_ERR; /* JNI version not supported */ } // Package/ClassName // The package is define in the java first line cls = (*env)->FindClass(env, "libledctrl/HWLedCtrl"); if (cls == NULL) { return JNI_ERR; } /* 2. map java hello <-->c c_hello */ if ((*env)->RegisterNatives(env, cls, method_table, sizeof(method_table)/sizeof(JNINativeMethod)) < 0) return JNI_ERR; return JNI_VERSION_1_4;}
需要注意的是:

cls = (*env)->FindClass(env, "libledctrl/HWLedCtrl");
这里面需要填写正确的来调用的class,这个路径按照
Package/Class来写。

然后进行编译链接成动态库,要使用Android提供的ToolChain需要先lunch target,免去写长长的路径Prefix:

source build/ensetup.shlunch sabresd_6dq-eng
第一步是compile,将C源码(ledctrl_jni.c)编译成object(ledctrl_jni.o)文件:

arm-linux-androideabi-gcc -I bionic/libc/bionic -I libnativehelper/include/nativehelper  -isystem system/core/include -isystem hardware/libhardware/include -isystem hardware/libhardware_legacy/include -isystem hardware/ril/include -isystem libnativehelper/include -isystem frameworks/native/include -isystem frameworks/native/opengl/include -isystem frameworks/av/include -isystem frameworks/base/include -isystem external/skia/include -isystem out/target/product/sabresd_6dq/obj/include -isystem bionic/libc/arch-arm/include -isystem bionic/libc/include -isystem bionic/libstdc++/include -isystem bionic/libc/kernel/common -isystem bionic/libc/kernel/arch-arm -isystem bionic/libm/include -isystem bionic/libm/include/arm -isystem bionic/libthread_db/include  -fno-exceptions -Wno-multichar -msoft-float -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -D_FORTIFY_SOURCE=1 -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=neon -include build/core/combo/include/arch/linux-arm/AndroidConfig.h -I build/core/combo/include/arch/linux-arm/ -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -DNDEBUG -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -c ledctrl_jni.c -o ledctrl_jni.o
第二步则是完成链接
ledctrl_jni.o --> libledctrl.so

arm-linux-androideabi-g++ -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Lout/target/product/sabresd_6dq/obj/lib -Wl,-rpath-link=out/target/product/sabresd_6dq/obj/lib  ledctrl_jni.o   -Wl,--whole-archive   -Wl,--no-whole-archive  -lc -lstdc++ -lm  -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--icf=safe -Wl,--fix-cortex-a8   -Wl,--no-undefined  -shared -fPIC -o libledctrl.so

链接时候需要的注意

需要注意的是链接的时候需要写明-lc,即要链接libc,否则在加载的时候后出现问题,例如没有加入的话运行的时候会出现下面的提示:

这里提示的是找不到符号__sprintf_chk,而这个符号我们可以确定其来源于libc,操作命令如下:

readelf --syms libc.so
结果中可以看到这个函数的定义:

File: out/target/product/sabresd_6dq/system/lib/libc.soSymbol table '.dynsym' contains 1243 entries:   Num:    Value  Size Type    Bind   Vis      Ndx Name     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND      1: 0000c9d8    88 FUNC    GLOBAL DEFAULT    8 __init_tls     289: 000138bd    30 FUNC    GLOBAL DEFAULT    8 __sprintf_chk
这个是查找一个symbol的方法。

编译用的ToolChain的注意

另外,看到很多人直接使用了arm-linux-gnueabi-gcc来编译链接,这样子做并不合理,因为我们是需要运行在Android上面,而Android系统编译使用的是arm-linux-androideabi-gcc来编译的,所以最后Android系统打包的libc等各种库都是用这个toolchain里面的。否则容易出现问题。

添加Clib库到APK项目中

在app/libs中添加armeabi目录,并将libledctrl.so拷贝进来,然后project的structure如下:

添加完成后build project,并generate APK,然后我们可以解压APK看到lib库已经打包进去了:

然后就可以运行查看效果了。

class名字的一致性

前面提到C代码中需要查找(FindFlass)对应来调用其的java class,如果名字不对应,那么就会提示找不到对应的class,例如下面在C中要查找的是LedCtrl class,自然找不到:

native函数名字的一致性

如果java中native的函数声明与实际的C中的函数不一致也会报错,而且要注意函数的返回类型与传入的参数类型,例如下面这个就是不匹配的结果:

APK调试方法

查看so是否加载

这个可以通过adb中的log信息来查看,同时也可以查看加载器是否加载了so,例如我们可以去cat /proc/PROCESS/maps文件查看,也可以使用pmap命令来查看:

root@sabresd_6dq:/ # pmap 9196 | grep led                                      415a7000      16K r--s  /data/app/com.hexiongjun.led-1.apk65c6f000      16K r--s  /data/app/com.hexiongjun.led-1.apk6644b000     156K r--s  /data/app/com.hexiongjun.led-1.apk664a7000       4K r-xp  /data/app-lib/com.hexiongjun.led-1/libledctrl.so664a8000       4K r--p  /data/app-lib/com.hexiongjun.led-1/libledctrl.so664a9000       4K rw-p  /data/app-lib/com.hexiongjun.led-1/libledctrl.so
我们可以看到后面so被加载了。

logcat查看某个进程的log

一条命令,后面的30585就是process id:

logcat -v process | grep 30585

代码位置

你可能感兴趣的文章
工作流审批平台-审批功能
查看>>
商务智能-基本方法-特征与角度
查看>>
软件项目管理系统-项目管理-模块定义-开发笔记
查看>>
工作流审批平台-业务申请-申请书一览
查看>>
商务智能-基本方法-数据钻取
查看>>
C++程序员技术需求规划(发展方向)
查看>>
聊聊我当年在培训学校做开发的经历
查看>>
用Docker搭建Redis主从复制的集群
查看>>
盘点这些年我出的书,以及由此得到的收获
查看>>
用Python的Pandas和Matplotlib绘制股票KDJ指标线
查看>>
面试必问:对java多线程里Synchronized的思考
查看>>
最近接了本分布式组件面试书的选题,请大家一起来提意见
查看>>
Redis整合MySQL和MyCAT分库组件(来源是我的新书)
查看>>
Java程序员普遍存在的面试问题以及应对之道(新书第一章节摘录)
查看>>
程序员高效出书避坑和实践指南
查看>>
计算机方面毕业生怎样写简历
查看>>
从软件公司的异同点讲起,聊聊未来的程序员该如何选公司和谋规划
查看>>
我不想安于当前的限度,以达到所谓的幸福,回顾下2020年的我
查看>>
如何在面试中介绍自己的项目经验(面向java改进版)
查看>>
通过写n本书的积累,我似乎找到了写好技术文章的方法(回复送我写的python股票电子书)
查看>>