在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接口。实现这两者的目的是为了向更上一层提供硬件访问接口,即为Android的Application Frameworks层提供硬件服务。我们知道,Android系统的应用程序是用Java语言编写的,而硬件驱动程序是用C语言来实现的,那么,Java接口如何去访问C接口呢?众所周知,Java提供了JNI方法调用,同样,在Android系统中,Java应用程序通过JNI来调用硬件抽象层接口。在这一篇文章中,我们将介绍如何为Android硬件抽象层接口编写JNI方法,以便使得上层的Java应用程序能够使用下层提供的硬件服务。

JNI层总体思想请看下图:

一. 参照在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序一文,准备好硬件抽象层模块,确保Android系统镜像文件system.img已经包含hello.default模块。

二. 进入到frameworks/base/services/jni目录,新建com_android_server_HelloService.cpp文件:

USER-NAME@MACHINE-NAME:~/Android$ cd frameworks/base/services/jni

      USER-NAME@MACHINE-NAME:~/Android/frameworks/base/services/jni$ vi com_android_server_HelloService.cpp

      在com_android_server_HelloService.cpp文件中,实现JNI方法。注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。这里,我们暂时略去HelloService类的描述,在下一篇文章中,我们将回到HelloService类来。简单地说,HelloService是一个提供Java接口的硬件访问服务类

首先是包含相应的头文件:

  1. #define LOG_TAG "HelloService"       //
  2. #include "jni.h"   //jni层使用的一些函数定义 声明
  3. #include "JNIHelp.h" //??各个头文件作用,,求高人指点???????????? 谢谢
  4. #include "android_runtime/AndroidRuntime.h" //?
  5. #include <utils/misc.h> //?
  6. #include <utils/Log.h> //?
  7. #include <hardware/hardware.h>   //需调用底层接口 如:hello_device
  1. #include <hardware/hello.h> #include <stdio.h>

 /*---------------------

(一)从HAL层总包中获取接口信息,入口

----------------------*/

接着定义hello_init、hello_getVal和hello_setVal三个JNI方法:

  1. namespace android
  2. {

 /*---------------------

  1.  

(二)

  1. /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/
  2. struct hello_device_t* hello_device = NULL; //HAL部分接口信息结构体
  3. /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
       /* 写入 */
  4. static void hello_setVal(JNIEnv* env, jobject clazz, jint value) { //JNIEnv*,jobject,jint类型
  5. int val = value;
  6. LOGI("Hello JNI: set value %d to device.", val);
  7. if(!hello_device) {
  8. LOGI("Hello JNI: device is not open.");
  9. return;
  10. }
  11. hello_device->set_val(hello_device, val); //执行底层:set_val
  12. }
  13. /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
         /*--读取--*/
  14.   static jint hello_getVal(JNIEnv* env, jobject clazz) {
  15. int val = ;
  16. if(!hello_device) {
  17. LOGI("Hello JNI: device is not open.");
  18. return val;
  19. }
  20. hello_device->get_val(hello_device, &val); //执行底层:get_val(就是简单的运行一下)
  21.  
  22. LOGI("Hello JNI: get value %d from device.", val);
  23.  
  24. return val;
  25. }
  26. /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
  27. static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) { //inline:内置函数
  28. return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
  29. }
  30. /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
         /*--bool为C中变量类型,jboolean 为JNI中变量类型,boolean为Java中变量类型;
         jboolean在C语言的定义为:
         typedef unsigned char jboolean;--*/
  31. static jboolean hello_init(JNIEnv* env, jclass clazz) {
  32. hello_module_t* module;
  33.  
  34. LOGI("Hello JNI: initializing......");
  35. if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == ) { //加载模块
  36. LOGI("Hello JNI: hello Stub found.");
  37. if(hello_device_open(&(module->common), &hello_device) == ) { //调用hello_device_open()函数 //打开设备
  38. LOGI("Hello JNI: hello device is open.");
  39. return ;
  40. }
  41. LOGE("Hello JNI: failed to open hello device.");
  42. return -;
  43. }
  44. LOGE("Hello JNI: failed to get hello stub module.");
  45. return -;
  46. }
  47.  
  48. --------------------*/
  49. /*--------------------
    (三)
  50. /*JNI方法表*/
  51. static const JNINativeMethod method_table[] = { //顶层只用 /*——(三)本包出口——*/
  52. {"init_native", "()Z", (void*)hello_init},
  53. {"setVal_native", "(I)V", (void*)hello_setVal},
  54. {"getVal_native", "()I", (void*)hello_getVal},
  55. }; //这些可以理解成JNI为上层提供的API接口吗??
  56. /*注册JNI方法*/
  57. int register_android_server_HelloService(JNIEnv *env) { //http://blog.csdn.net/horkychen/article/details/10952249
  58. return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
  59. }
    --------------------*/
  60. };

      注意,在hello_init函数中,通过Android硬件抽象层提供的hw_get_module方法来加载模块ID为HELLO_HARDWARE_MODULE_ID的硬件抽象层模块,其中,HELLO_HARDWARE_MODULE_ID是在<hardware/hello.h>中定义的。Android硬件抽象层会根据HELLO_HARDWARE_MODULE_ID的值在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。在jniRegisterNativeMethods函数中,第二个参数的值必须对应HelloService所在的包的路径,即com.android.server.HelloService

三. 修改同目录下的onload.cpp文件,首先在namespace android增加register_android_server_HelloService函数声明:

namespace android {

..............................................................................................

int register_android_server_HelloService(JNIEnv *env);

};

      在JNI_onLoad增加register_android_server_HelloService函数调用:
      extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)
      {
       .................................................................................................
       register_android_server_HelloService(env);
       .................................................................................................
      }
      这样,在Android系统初始化时,就会自动加载该JNI方法调用表。
      四. 修改同目录下的Android.mk文件,在LOCAL_SRC_FILES变量中增加一行:
      LOCAL_SRC_FILES:= \
      com_android_server_AlarmManagerService.cpp \
      com_android_server_BatteryService.cpp \
      com_android_server_InputManager.cpp \
      com_android_server_LightsService.cpp \
      com_android_server_PowerManagerService.cpp \
      com_android_server_SystemServer.cpp \
      com_android_server_UsbService.cpp \
      com_android_server_VibratorService.cpp \
      com_android_server_location_GpsLocationProvider.cpp \
      com_android_server_HelloService.cpp /
      onload.cpp
      五. 编译和重新找亿system.img:
      USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/jni
      USER-NAME@MACHINE-NAME:~/Android$ make snod
      这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,也就是我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了。前面提到,在这篇文章中,我们暂时忽略了HelloService类的实现,在下一篇文章中,我们将描述如何实现硬件服务HelloService,敬请关注。
 
 
 

1.

make:进入目录'/opt/FriendlyARM/tiny4412/android/android-4.1.2'
make: *** 没有规则可以创建“out/target/product/generic/obj/SHARED_LIBRARIES/libandroid_servers_intermediates/import_includes”需要的目标“out/target/product/generic/obj/SHARED_LIBRARIES/libc_intermediates/export_includes”。 停止。
make:离开目录“/opt/FriendlyARM/tiny4412/android/android-4.1.2”
root@phone-desktop:/opt/FriendlyARM/tiny4412/android/android-4.1.2#

解决方法:

. setenv

输出:

out/target/product/tiny4412/system/lib/libandroid_servers.so

3

  1. make: *** [out/target/common/obj/APPS/CMParts_intermediates/classes-full-debug.jar] 错误 41 这个错误,解决方法,知道的话就很简单了,
  1. 只需打如下命令 即可:make update-api //$ make clobber       $ make   
 
局部程序修改:http://blog.csdn.net/oldmtn/article/details/9214143
 
原文:http://blog.csdn.net/luoshengyang/article/details/6575988
 
 
 

在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口(老罗学习笔记4)的更多相关文章

  1. 为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口

    在上两篇文章中,我们介绍了如何为Android系统的硬件编写驱动程序,包括如何在Linux内核空间实现内核驱动程序和在用户空间实现硬件抽象层接 口.实现这两者的目的是为了向更上一层提供硬件访问接口,即 ...

  2. 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务(老罗学习笔记6)

    一:Eclipse下 1.创建工程: ---- 2.创建后目录 3.添加java函数 4.在src下创建package,在package下创建file 5.res---layout下创建xml文件,命 ...

  3. 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务(老罗学习笔记5)

    在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行.今天大家对iOS和Android系统的趋之若鹜,一定程度上是由于这两个系统上有着丰富多彩的各种应用软件.因此,软件和硬件的关系 ...

  4. 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)

    简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中.接着,在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)一文中举例子说明了如何在 ...

  5. 在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)

    这里,我们不会为真实的硬件设备编写内核驱动程序.为了方便描述为Android系统编写内核驱动程序的过程,我们使用一个虚拟的硬件设备,这个设备只有一个4字节的寄存器,它可读可写.想起我们第一次学习程序语 ...

  6. 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序(老罗学习笔记2)

    在前一篇文章中,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序.在这个名为hello的Linux内核驱动程序中,创建三个不同的文件节点来供用户空间访问,分别是传统的设备文 ...

  7. Android架构分析之使用自定义硬件抽象层(HAL)模块

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29 在上一篇博 ...

  8. Android Studio Xposed模块编写(二)

    阅读本文前,假设读者已经看过Android Studio Xposed模块编写(一)  相关环境已经搭建完成.本文演示案例与上文环境一致,不在赘述. 1.概述 Xposed是非常牛叉的一款hook框架 ...

  9. 技术转载:Jni学习四:如何编写jni方法

    转载:http://blog.chinaunix.net/u1/38994/showart_1099528.html 一.概述: 在这篇文章中将会简单介绍如何编制一些简单的JNI 方法.我们都知道JN ...

随机推荐

  1. 从零开始学ios开发(二十):Application Settings and User Defaults(下)

    在上一篇的学习中,我们知道了如何为一个App添加它的Settings设置项,在Settings设置项中我们可以添加哪些类型的控件,这些控件都是通过一个plist来进行管理的,我们只需对plist进行修 ...

  2. Wireshark 入门

    1.过滤目的地是百度的IP包. 百度的ip: 命令:ip.src eq 61.135.169.125 过滤ip来源是61.135.169.125 ip.dst eq 61.135.169.125 过滤 ...

  3. cocos2dx中的触摸事件及触摸优先级

    1.只有CCLayer及其派生类才有触摸功能. 2.开启触摸 setTouchEnable(true); 3.设置触摸模式,单点,多点(仅IOS支持) setTouchMode(kCCTouchesO ...

  4. Linux Shell编程变量赋值和引用

    我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行):   #!/bin/sh  ...  注意:最好使用“! ...

  5. Careercup - Facebook面试题 - 4907555595747328

    2014-05-02 07:49 题目链接 原题: Given a set of n points (coordinate in 2d plane) within a rectangular spac ...

  6. 阿旭的php开发环境

    过了几年,php技术也日新月异,变化也挺多.哪么对于开发者,感觉有一些简单的方法,写下来,以备以后使用.我觉得吧,Linux写php不如windows写php,调试,查资料和各种功能比较全面,而lin ...

  7. 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

    // test20.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...

  8. Window 2008 R2 + IIS7.5 + VS2013 错误代码 0x80070002

    HTTP 错误 404.0 - Not Found 您要找的资源已被删除.已更名或暂时不可用.详细错误信息模块 IIS Web Core通知 MapRequest Handler处理程序 Static ...

  9. dom4j处理xml文件,读取xml字符串,格式化xml文件

    1.xml文件 <?xml version="1.0" encoding="UTF-8"?> <employees> <emplo ...

  10. Synchronized Methods

    Synchronized Methods The Java programming language provides two basic synchronization idioms: synchr ...