PC机:ubuntu 12.04.5
开发板:tiny4412
Android版本:5.0.2
Android IDE:Android Studio

前提:
PC机已经搭建好 Android 开发环境,已经安装好交叉编译器,
已经编译好 Android 内核 以及 Android 源码,

编写 Android APP,实现以下功能:
1、一个 button 控制全部 LED,按一下全开,按一下全关
2、四个 CheckBox 分别单独控制每个LED,按一下对应的LED开,再按一下关
------------------------------------------------------------------------
------------------------------------------------------------------------
使用 Android Studio 建立 APP 工程,具体建立过程请 Google
界面建立完成后,开始编写操作 LED 的代码
在 F:\AndroidTest\APP_0001_LEDDemo\app\src\main\java\com\example\wenjs\目录下,建立一个 hardlibrary 目录
在 hardlibrary 目录下,建立一个 HardLibrary.java 文件,用来编写 ledOpen、ledCtrl、ledClose 等本地方法

新建一个文件夹,用来保存动态链接库的源代码,参考之前的 jni 教程,建立一个本地的 .c 文件
按照 jni 的规则,编写 hardlibrary.c 文件,完成本地的 led_open、led_ctrl、led_close 等函数

编写完成后,把 hardlibrary.c 上传到 Linux 并进行交叉编译,执行以下命令:
arm-linux-gcc -fPIC -shared hardlibrary.c -o libhardlibrary.so -I/usr/lib/jvm/java-7-openjdk-amd64/include/
编译参数解释:
-I 表示指定 jni.h 的文件路径位置
-fPIC 表示生成位置无关码,参考博客: http://blog.sina.com.cn/s/blog_54f82cc201011op1.html
-shared 表示生成动态链接库 .so 文件
-o 表示生成目标文件

编译完成后,生成 libhardlibrary.so 文件,在 F:\AndroidTest\APP_0001_LEDDemo\app\libs 目录下新建 armeabi 文件夹
把 libhardlibrary.so 上传到 armeabi 文件夹中
同时,修改APP工程的 build.gradle(Module:app),添加以下内容:
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
这个表示我们的 jni lib 文件存放在 libs 目录里面,这种方式是会把.so文件编译进APK文件里

以上工作完成后,把应用程序在开发板上运行,程序出现崩溃,
查看调试信息,发现 could not load library "libc.so.6" needed by "libhardlibrary.so"

libhardlibrary.so 的运行依赖于 libc.so.6

查看开发板的终端,ls /vendor/lib 或者 ls /system/lib/libc.* 发现没有 libc.so.6

在Android源码目录 /opt/work/source_code/android-5.0.2/,查找libc.so
find -iname "libc.so*"

修改一下 hardlibrary.c 的编译选项,改为如下:
arm-linux-gcc -fPIC -shared hardlibrary.c -o libhardlibrary.so -I/usr/lib/jvm/java-7-openjdk-amd64/include/ \
-nostdlib /opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so

nostdlib表示不使用标准库,而使用 Android 源码目录下的libc库:
/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so

修改完成后,重新编译运行 Android APP,程序运行正确。表明 Android APP 已经成功调用了本地的 c 库

继续修改 Android APP的代码,调用 ledOpen、ledCtrl、ledClose 等方法

修改 hardlibrary.c 文件,添加 Android 的打印信息,适用以下函数:
#include <android/log.h> //包含这个头文件

__android_log_print(ANDROID_LOG_INFO, "JniX431FileTest", "lsx_init"); //打印语句
ANDROID_LOG_INFO:是日志级别;
"JniX431FileTest":是要过滤的标签,可以在LogCat视图中过滤。
"lsx_init":是实际的日志内容。

再次执行以下命令编译 hardlibrary.c ,提示找不到 android/log.h

到 Android 源码目录查找一下,发现 android/log.h 在以下路径:
/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/android/log.h
更改编译选项为以下内容:
arm-linux-gcc -fPIC -shared hardlibrary.c -o libhardlibrary.so -I/usr/lib/jvm/java-7-openjdk-amd64/include/ \
-nostdlib /opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so \
-I/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/

hardlibrary.c 编译成功,重新上传到 Android APP的 armeabi 目录,再次运行 APP
运行失败,根据提示信息:dlopen failed: cannot locate symbol "__android_log_print" ,打开动态库失败

到 Android 源码目录查找一下,发现 liblog 在以下路径:
/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so
更改编译选项为以下内容:
arm-linux-gcc -fPIC -shared hardlibrary.c -o libhardlibrary.so -I/usr/lib/jvm/java-7-openjdk-amd64/include/ \
-nostdlib /opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so \
-I/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/ \
/opt/work/source_code/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

经过以上操作,Android APP 和 本地方法 libhardlibrary.so 编译成功
把 app 下载到开发板上运行,点击 button 和 checkbox,程序正确运行,但此时还没有编写硬件驱动,只有打印信息
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
编写 led 硬件驱动程序
参考韦东山Linux第二期视频,使用字符设备驱动模型,来开发led驱动程序,此处不再重复
以下是驱动源码:
#include <linux/kernel.h>#include <linux/module.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/delay.h>#include <linux/gpio.h>#include <mach/gpio.h>#include <plat/gpio-cfg.h>#include <device.h>static int major = 0;static struct class *led_class;static int led_gpios[] = {        EXYNOS4212_GPM4(0),        EXYNOS4212_GPM4(1),        EXYNOS4212_GPM4(2),        EXYNOS4212_GPM4(3),};static int led_open(void){        /* set gpio output */        int i = 0;                for(i=0;i<4;i++)        {                s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);                //gpio_set_value(led_gpios[i], 1);        }        return 0;}//app : ioctl(fd,cmd,arg)static long led_ioctl(struct file *filp, unsigned int cmd,unsigned long arg){       if((cmd != 0) && (cmd != 1))       return -EINVAL;       if(arg > 4)       return -EINVAL;       gpio_set_value(led_gpios[arg], !cmd);       return 0;}static struct file_operastions leds_fops = {        .owner= THIS_MODULE,        .open                = led_open,        .unlocked_ioctl        = led_ioctl,};int leds_init(void){        major = register_chrdev(0,"leds",&leds_fops);        led_class = class_create(THIS_MODULE,"leds");        device_create(led_class, NULL, MKDEV(major,0), NULL, "leds");        return 0;}void leds_exit(void){        device_destroy(led_class, MKDEV(major,0));        class_destroy(led_class);        unregister_chrdev(major,"leds");}module_init(leds_init);module_exit(leds_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("wenjs0620@163.com");

把led驱动放入 Android kernel 的 device/char目录。
修改Android 内核的makefile,添加编译选项,重新编译 make zImage
重新烧写内核到开发板。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
再次修改 hardlibrary.c 文件,修改里面的 led_open、led_close、led_ctrl 函数,
在里面的这些函数里,使用 open 、read 、write 函数来操作硬件
重新编译 hardlibrary.c 为 libhardlibrary.so ,并重新上传到Android app 的 armeabi 目录
重新编译 Android app 工程,运行,可以使用app操作开发板上的led了

整个层次关系如下:

Android APP ----> 加载 c 库
------------------------------------
JNI 本地接口函数(其实就是Linux的应用层)
--------------------------------------------
Linux 驱动程序


更多相关文章

  1. NPM 和webpack 的基础使用
  2. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  3. Android(安卓)根文件系统启动过程
  4. Android支持的资源
  5. cocos2d-x3.2 在Windows下打包Android平台APK
  6. Android中给Button加上selector——点击按钮后变成不一样的图片
  7. android cocos2d-x for Android安装和学习笔记(请用adt-bundle21.
  8. android 快速入门
  9. Android资源文件简介

随机推荐

  1. Kotlin让Android更简单~
  2. android网络编程——使用Android中的网络
  3. 启动app闪屏问题以及Android自带主题
  4. Android调用WCF
  5. Android滑动手势侦测方法介绍
  6. Android(安卓)中自定义View(三)
  7. Android(安卓)RelativeLayout 属性大全
  8. android 电容屏(一):电容屏基本原理篇
  9. android ndk 开发之 在 应用程序中使用 j
  10. Android(安卓)Studio:AndroidX的迁移