android JNI通过HAL层调用驱动程序

1、java APP

定义了三个native方法:getVal(),setVal(int val),init_jni().  

package com.android.zhang.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class JNIZhangFangTestActivity extends Activity {
	private static final String Tag = "zhangfang_JNI_TEST";
	
	private native int getVal();
	private native void setVal(int val);
	private native void init_jni();
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        init_jni();
    }
    
    static {
        System.loadLibrary("zf");
    }
    
    public boolean onCreateOptionsMenu(Menu menu)
    {
    	menu.add(0, 0, 0, "getVal");
    	menu.add(1, 1, 1, "setVal");
    	menu.add(2, 2, 2, "clear");
    	return true;
    }
   
	public boolean onOptionsItemSelected(MenuItem item)
    {
    	int item_id=item.getItemId();
    	switch(item_id){
    	case 0:{
    		getVal();
    		break;
    	}
    	case 1:{
    		setVal(20);
    		break;
    	}
    	case 2:{
    		setVal(0);
		break;
		}
    	
    	}
    	return true;
    }
}

2、JNI层

com_android_zhang_test_JNIZhangFangTestActivity.h

关于如何实现JNI,请参照android JNI实现步骤

该文件实现了三个native方法,注意native方法的命名,与上面APP的函数相对应。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_android_zhang_test_JNIZhangFangTestActivity */

#ifndef _Included_com_android_zhang_test_JNIZhangFangTestActivity
#define _Included_com_android_zhang_test_JNIZhangFangTestActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_zhang_test_JNIZhangFangTestActivity
 * Method:    getVal
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_getVal
  (JNIEnv *, jobject);

/*
 * Class:     com_android_zhang_test_JNIZhangFangTestActivity
 * Method:    setVal
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_setVal
  (JNIEnv *, jobject, jint);

/*
 * Class:     com_android_zhang_test_JNIZhangFangTestActivity
 * Method:    init_jni
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_init_1jni
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

com_android_zhang_test_JNIZhangFangTestActivity.c

实现native方法。在hello_init中去找到抽象层定义的hello_module_t模块,并打开该设备,进行一系列初始化。hello_setVal(int val) 和 hello_getVal() 都是调用抽象层中定义的方法。

#include "com_android_zhang_test_JNIZhangFangTestActivity.h"
#define LOG_TAG "Zhangfang_JNI"
#include <utils/Log.h>
#include <JNIHelp.h>
//#include <android_runtime/AndroidRuntime.h>
//#include <utils/misc.h>
#include <hardware/hardware.h>
#include <stdio.h>
//#include "../../../hardware/libhardware/include/hardware/zf.h"
#include <hardware/zf.h>

//namespace android
//{
/*硬件抽象层定义的硬件访问结构体,可通过该结构体与硬件进行交互*/
struct hello_device_t* hello_device = NULL;
int hw_get_module(const char *id,const struct hw_module_t **module);

static int hello_getVal();
static void hello_setVal(int value);
static int hello_init();

JNIEXPORT jint JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_getVal
  (JNIEnv *env, jobject obj)
{
        return hello_getVal();
}

JNIEXPORT void JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_setVal
  (JNIEnv *env, jobject obj, jint val)
{
        hello_setVal(val);
}
JNIEXPORT void JNICALL Java_com_android_zhang_test_JNIZhangFangTestActivity_init_1jni
  (JNIEnv *env, jobject obj)
{
        if(hello_init() ==0){
                LOGI("ZhangFang JNI: hello_init successfully!");
        }else{
                LOGI("ZhangFang JNI: hello_init failed!");
        }
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    void *venv;
    LOGI("JNI_OnLoad!");

    if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed");
        return -1;
    }

     return JNI_VERSION_1_4;
}

static void hello_setVal(int value)
        {
                int val = value;
                LOGI("Zhangfang JNI: set value %d to device.",val);
                if(!hello_device){
                        LOGI("Zhangfang JNI: device is not open.");
                        return ;
                }

                hello_device->set_val(hello_device,val);
        }
/*获取硬件寄存器的值*/
        static int hello_getVal()
        {
                int val = 0;
                if(!hello_device){
                        LOGI("Zhangfang JNI: device is not open.");
                        return  val;
                }
                hello_device->get_val(hello_device,&val);
                LOGI("Zhangfang JNI: get value %d from device.",val);
                return val;
        }


static inline int hello_device_open(const hw_module_t* module,struct hello_device_t** dev)
        {
                return module->methods->open(module,HELLO_HARDWARE_MODULE_ID,(struct hw_device_t**)dev);
        }

/*通过硬件模块ID来加载指定硬件抽象层模块,并打开硬件*/
        static int hello_init()
        {
                struct hello_module_t *module;
                LOGI("Zhangfang JNI: initializing.......");
                if(hw_get_module(HELLO_HARDWARE_MODULE_ID,(const struct hw_module_t**)&module)==0)
                {
                        LOGI("Zhangfang JNI: hello Stub found.");
                        if(hello_device_open(&(module->common),&hello_device) == 0)
                        {
                                LOGI("Zhangfang: hello device is open.");
                                return 0;
                        }
                        LOGE("Zhangfang: failed to open hello device.");
                        return -1;
                }
                LOGE("Zhangfang JNI: failed to found hello Stub.");
                return -1;
        }

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := com_android_zhang_test_JNIZhangFangTestActivity.c

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)

LOCAL_MODULE := libzf

LOCAL_SHARED_LIBRARIES := libutils libhardware

LOCAL_PRELINK_MODULE := false

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)


3、HAL层

vi /hardware/libhardware/include/hello.c

#ifndef ANDROID_HELLO_INTERFACE_H
#define ANDROID_HELLO_INTERFACE_H

#include <hardware/hardware.h>

__BEGIN_DECLS

#define HELLO_HARDWARE_MODULE_ID "hello"

/*硬件模块结构体*/
struct hello_module_t {
        struct hw_module_t common;
};

/*硬件设备接口结构体*/
struct hello_device_t {
        struct hw_device_t common;
        int fd;
        int (*set_val)(struct hello_device_t* dev,int val);
        int (*get_val)(struct hello_device_t* dev,int *val);
};

__END_DECLS

#endif

vi /hardware/libhardware/modules/hello/hello.c

#define LOG_TAG "HelloStub"

#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>


#define DEVICE_NAME "/dev/hello"
#define MODULE_NAME "hello"
#define MODULE_AUTHOR "zhangfanghn@gmail.com"

/*打开和关闭设备*/
static int hello_device_open(const struct hw_module_t* module,const char* name,struct hw_device_t** device);
static int hello_device_close(struct hw_device_t* device);

/*设备访问接口*/
static int hello_get_val(struct hello_device_t* dev,int* val);
static int hello_set_val(struct hello_device_t* dev,int val);

/*模块方法表*/
static struct hw_module_methods_t hello_module_methods = {
        open:hello_device_open
};

struct hello_module_t HAL_MODULE_INFO_SYM = { /*模块名称必须为这个*/
        common:{
                tag: HARDWARE_MODULE_TAG, /*必须是这个*/
                version_major: 1,
                version_minor: 0,
                id: HELLO_HARDWARE_MODULE_ID, //向系统注册了一个ID为HELLO_HARDWARE_MODULE_ID的stub
                name: MODULE_NAME,
                author: MODULE_AUTHOR,
                methods: &hello_module_methods,
        }
};
static int hello_device_open(const struct hw_module_t* module,const char*name,struct hw_device_t** device)
{
        struct hello_device_t* dev;
        dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
        if(!dev){
                LOGE("Hello Stub : failed to alloc space!");
                return -EFAULT;
        }
        memset(dev,0,sizeof(struct hello_device_t));
        dev->common.tag = HARDWARE_DEVICE_TAG;/*这个必须为这个*/
        dev->common.version = 0;
        dev->common.module = (hw_module_t*)module;
        dev->common.close = hello_device_close;
        dev->set_val = hello_set_val;
        dev->get_val = hello_get_val;

        if((dev->fd = open(DEVICE_NAME,O_RDWR))== -1) {
                LOGE("Hello Stub : faild to open %s: %s",DEVICE_NAME,strerror(errno));
                free(dev);
                return -EFAULT;
        }

        *device = &(dev->common);
        LOGI("Hello Stub: open %s successfully.",DEVICE_NAME);

        return 0;
}
static int hello_device_close(struct hw_device_t* dev)
{
        struct hello_device_t* hello_device = (struct hello_device_t*)dev;

        if(!hello_device){
                close(hello_device->fd);
                free(hello_device);
        }
        return 0;
}

static int hello_set_val(struct hello_device_t* dev,int val)
{
        LOGI("Hello Stub: set value %d to device.",val);
        write(dev->fd,&val,sizeof(val));

        return 0;
}
static int hello_get_val(struct hello_device_t* dev,int *val)
{
        if(!val){
                LOGE("Hello Stub: error val pointer.");
                return -EFAULT;
        }
        read(dev->fd,val,sizeof(*val));
        LOGI("Hello Stub: get value %d from device.",*val);
        return 0;
}


android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

LOCAL_SHARED_LIBRARIES := liblog

LOCAL_SRC_FILES := hello.c

LOCAL_MODULE := hello.default

include $(BUILD_SHARED_LIBRARY)


4、驱动层

省略了。

修改init.rc文件,可开机加载内核驱动。

on boot
# basic network init          
    ifup lo                                                
    hostname localhost                
    domainname localdomain   
                               
# set RLIMIT_NICE to allow priorities from 19 to -20
    setrlimit 13 40 40       
                                       
# basic kernel modules              
    insmod /develop/hello.ko                                                                                                                                            
#    mknod /dev/zf c 248 0

修改ueventd.rc,可设置设备的访问权限。因为应用程序一般不具备访问硬件的权限,所以需要给硬件增加相应的访问权限。

/dev/hello                0666   root       root


5、出现的错误

编译JNI模块时出现如下错误:

undefined reference to 'hw_get_module'

collect2: ld returned 1 exit status

错误原因:
hw_get_module找不到,为什么会找不到呢?不是包含头文件#include <hardware/hardware.h>了吗?
其实,其真实原因是使用了hw_get_module这个函数,在链接的时候需要到libhardware.so库中去找,但是在Android.mk中却没有包含libhareware.so库,所以在链接的时候报错。
解决方法:
在Android.mk中加入该库即可:

LOCAL_SHARED_LIBRARIES := libutils libhardware


6、执行结果

I/ActivityManager( 1233): Start proc com.android.zhang.test for activity com.android.zhang.test/.JNIZhangFangTestActivity: pid=1701 uid=10031 gids={}
D/dalvikvm( 1701): Debugger has detached; object registry had 1 entries
I/Zhangfang_JNI( 1701): JNI_OnLoad!
I/Zhangfang_JNI( 1701): Zhangfang JNI: initializing.......
I/Zhangfang_JNI( 1701): Zhangfang JNI: hello Stub found.
I/ZhangFangStub( 1701): ZhangFang Stub: open /dev/zf successfully.
I/Zhangfang_JNI( 1701): Zhangfang: hello device is open.
I/Zhangfang_JNI( 1701): ZhangFang JNI: hello_init successfully!
I/ActivityManager( 1233): Displayed com.android.zhang.test/.JNIZhangFangTestActivity: +151ms
D/dalvikvm( 1319): GC_EXPLICIT freed 63K, 48% free 3027K/5767K, external 3312K/4113K, paused 25ms
W/KeyCharacterMap( 1701): No keyboard for id 0
W/KeyCharacterMap( 1701): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
I/Zhangfang_JNI( 1701): Zhangfang JNI: set value 0 to device.
I/ZhangFangStub( 1701): ZhangFang Stub: set value 0 to device.
W/InputManagerService( 1233): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@407848c0
I/Zhangfang_JNI( 1701): Zhangfang JNI: set value 20 to device.
I/ZhangFangStub( 1701): ZhangFang Stub: set value 20 to device.
W/InputManagerService( 1233): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@40852fa0
I/ZhangFangStub( 1701): ZhangFang Stub: get value 20 from device.
I/Zhangfang_JNI( 1701): Zhangfang JNI: get value 20 from device.



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值