Android之编写hello HAL&JNI代码

http://blog.csdn.net/eliot_shao/article/details/51861905
http://blog.csdn.net/eliot_shao/article/details/51864811

HAL层中文名称又叫硬件抽象层,可以理解我Linux驱动的应用层。本文实现了一个简单的hello HAL的代码,衔接hello驱动和hello JNI:

http://blog.csdn.net/eliot_shao/article/details/51860229

Android标准架构实例分析之编写最简单的hello驱动

HAL层的代码会使用open read write等系统调用操作驱动层的文件系统(dev、sysfs、proc),同时它也有自己的数据结构,为上层提供接口,并导出和本体模块相关ID号。上层可以使用hw_get_module获得HAL中写的方法。其实如果不是为了避开Linux的GPL开源协议,HAL层可以不用,直接使用JNI层或者在Java代码中访问操作驱动层的文件系统(dev、sysfs、proc)也是可行的。
详细原理可以参考:

http://blog.csdn.net/eliot_shao/article/details/50461738

HAL代码编写的基本步骤

1、编写HAL层头文件

2、填充相关的结构体

1、编写HAL层头文件

首先我们要知道关于HAL的三点要求:

1、 每一个hardware硬件模块都有一个ID;

2、 每一个hardware模块必须有一个继承struct hw_module_t common;的结构体;

3、 每一个hardware模块必须有一个继承struct hw_device_t common;的结构体;

struct hw_module_t的继承者担负了“联络员”的任务,在/system/lib/hw下面有若干hardware module,本地框架层通过ID找到对应的模块。

struct hw_device_t的继承者承担了对驱动操作方法的包装的任务。
struct hw_module_t和struct hw_device_t的内容定义在:

hardware\libhardware\include\hardware\hardware.h

所以我们的hello.h内容如下:

#ifndef ANDROID_HELLO_INTERFACE_H

#define ANDROID_HELLO_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS #define HELLO_HARDWARE_MODULE_ID “hello”//ID struct hello_module_t { struct hw_module_t common; };//hw_module_t的继承者 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); };//hw_device_t的继承者 __END_DECLS #endif

2、填充相关的结构体

我们总结一下硬件具体的调用流程,也是hardware层的工作流程:

1、 通过ID找到硬件模块,struct hw_module_t common的结构体的继承者;

2、 通过硬件模块找到hw_module_methods_t,打开操作,获得设备的hw_device_t;

3、 调用hw_device_t中的各种操作硬件的方法;

4、 调用完成,通过hw_device_t的close关闭设备。

HAL规定了需要创一个名为HAL_MODULE_INFO_SYM结构体,如下:

struct hello_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag= HARDWARE_MODULE_TAG,
        //.module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
        .hal_api_version= HARDWARE_HAL_API_VERSION,
        .id = HELLO_HARDWARE_MODULE_ID,
        .name   = "Demo shaomingliang hello HAL",
        .author = "The Android Open Source Project",
        .methods= &hello_module_methods,
    },
};

填充struct hw_module_t common 并对其成员 methods进行赋值:

.methods= &hello_module_methods,

hello_module_methods的定义如下:

static struct hw_module_methods_t hello_module_methods = {
    .open = hello_device_open,
};

hello_device_open 对 struct hello_device_t 进行填充。

下面是抽象层hello.c的详细代码:

#define LOG_TAG "HelloStub"
#include <hardware/hardware.h>
#include <hardware/hello.h>

#include <sys/mman.h>

#include <dlfcn.h>

#include <cutils/ashmem.h>
#include <cutils/log.h>

#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>

#include <cutils/log.h>
#include <cutils/atomic.h>

#define MODULE_NAME "Hello"
char const * const device_name = "/dev/hello" ;
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_set_val(struct hello_device_t* dev, int val);
static int hello_get_val(struct hello_device_t* dev, int* val);

static struct hw_module_methods_t hello_module_methods = {
    .open = hello_device_open,
};
static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
{
    struct hello_device_t* dev;
    char name_[64];
    //pthread_mutex_t lock;
    dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
    if(!dev) {
        ALOGE("Hello Stub: failed to alloc space");
        return -EFAULT;
    }
    ALOGE("Hello Stub: hello_device_open eliot_shao");
    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;

    //pthread_mutex_lock(&lock);
    dev->fd = -1 ;
    snprintf(name_, 64, device_name, 0);
    dev->fd = open(name_, O_RDWR);
    if(dev->fd == -1) {
        ALOGE("Hello Stub:eliot failed to open %s !-- %s.", name_,strerror(errno));
        free(dev);
        return -EFAULT;
    }
    //pthread_mutex_unlock(&lock);
    *device = &(dev->common);
    ALOGI("Hello Stub: open HAL hello successfully.");
    return 0;
}

static int hello_device_close(struct hw_device_t* device) {
    struct hello_device_t* hello_device = (struct hello_device_t*)device;
    if(hello_device) {
        close(hello_device->fd);
        free(hello_device);
    }
    return 0;
}
static int hello_set_val(struct hello_device_t* dev, int val) {
    ALOGI("Hello Stub: set value to device.");
    write(dev->fd, &val, sizeof(val));
    return 0;
}
static int hello_get_val(struct hello_device_t* dev, int* val) {
    if(!val) {
        ALOGE("Hello Stub: error val pointer");
        return -EFAULT;
    }
    read(dev->fd, val, sizeof(*val));
    ALOGI("Hello Stub: get value  from device");
    return 0;
}

struct hello_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag                = HARDWARE_MODULE_TAG,
        //.module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
        .hal_api_version    = HARDWARE_HAL_API_VERSION,
        .id                 = HELLO_HARDWARE_MODULE_ID,
        .name               = "Demo shaomingliang hello HAL",
        .author             = "The Android Open Source Project",
        .methods            = &hello_module_methods,
    },
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

Android.mk 的详细代码如下:


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello.default
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := hello.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)


  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

hello HAL代码的编译

将hal的代码放到如下位置:

hardware\libhardware\modules\hello\hello.c
hardware\libhardware\modules\hello\Android.mk
hardware\libhardware\include\hardware\hello.h

执行:mmm hardware\libhardware\modules\hello\

将会在system/lib/hw/下生成一个hello.default.so!

摘要:

Android JNI是一种技术,提供Java调用Android native代码或者native调用Java代码的一种机制,并不提供策略。

JNI原理分析

首先上一张Android JNI技术的工作原理图:

这里写图片描述

在图中主要描述Java-jni-native的一个调用流程。下面进行按步骤讲解:
1、Java代码通过System.loadLibrary(“android_servers”); 加载JNI静态库;
2、Android runtime自动调用JNI静态库中的JNI_OnLoad函数;
3、JNI_OnLoad调用jniRegisterNativeMethods函数,注册多个或者一个JNINativeMethod到Android runtime的gMthods链表中;
4、Java代码声明并调用相关的native代码;
5、Android runtime查找gMthods链表找到前面注册的本地函数指针,然后执行。

注意:JNI和HAL的衔接是通过JNI的代码

hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) 

实现的。

本文使用的hello的案例是以system_server进程上建立的,后面会创建一个hello的本地服务。下面是对system_server进程调用JNI过程进行分析。

1、frameworks\base\services\java\com\android\server\SystemServer.java

    // Initialize native services.
    System.loadLibrary("android_servers");

2、frameworks\base\services\core\jni\onload.cpp

jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_HelloService(env);//add by eliot_shao

3、frameworks\base\services\core\jni\com_android_server_HelloService.cpp

jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
static const JNINativeMethod method_table[] = {
        {"init_native", "()Z", (void*)hello_init},
        {"setVal_native", "(I)V", (void*)hello_setVal},
        {"getVal_native", "()I", (void*)hello_getVal},
    };

4、frameworks\base\services\Android.mk

LOCAL_MODULE:= libandroid_servers

hello JNI实例

rameworks\base\services\core\jni\com_android_server_HelloService.cpp

#define LOG_TAG "HelloService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <stdio.h>
namespace android
{
    struct hello_device_t* hello_device = NULL;
    static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {
        int val = value;
        ALOGI("Hello JNI: set value %d to device.", val);
        if(!hello_device) {
            ALOGI("Hello JNI: device is not open.");
            return;
        }
        hello_device->set_val(hello_device, val);
    }
    static jint hello_getVal(JNIEnv* env, jobject clazz) {
        int val = 0;
        if(!hello_device) {
            ALOGI("Hello JNI: device is not open.");
            return val;
        }
        hello_device->get_val(hello_device, &val);

        ALOGI("Hello JNI: get value %d from device.", val);

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

    }
    static jboolean hello_init(JNIEnv* env, jclass clazz) {
        hello_module_t* module;

        ALOGI("Hello JNI: initializing......");
        if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
            ALOGI("Hello JNI: hello Stub found.");
            if(hello_device_open(&(module->common), &hello_device) == 0) {
                ALOGI("Hello JNI: hello device is open.");
                return 0;
            }
            ALOGE("Hello JNI: failed to open hello device.");
            return -1;
        }
        ALOGE("Hello JNI: failed to get hello stub module.");
        return -1;      
    }
    static const JNINativeMethod method_table[] = {
        {"init_native", "()Z", (void*)hello_init},
        {"setVal_native", "(I)V", (void*)hello_setVal},
        {"getVal_native", "()I", (void*)hello_getVal},
    };
    int register_android_server_HelloService(JNIEnv *env) {
    return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
    }   
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

frameworks\base\services\core\jni\onload.cpp

/*
* Copyright (C) 2014 MediaTek Inc.
* Modification based on code covered by the mentioned copyright
* and/or permission notice(s).
*/
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "JNIHelp.h"
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"

namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
int register_com_mediatek_perfservice_PerfServiceManager(JNIEnv* env);
#if defined (MTK_HDMI_SUPPORT)
int register_com_mediatek_hdmi_MtkHdmiManagerService(JNIEnv* env);
#endif
// Mediatek AAL support
int register_android_server_display_DisplayPowerController(JNIEnv* env);
#ifndef MTK_BSP_PACKAGE
int register_com_android_internal_app_ShutdownManager(JNIEnv *env);
#endif

int register_android_server_HelloService(JNIEnv *env);//add by eliot_shao
};

using namespace android;

extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_PowerManagerService(env);
    register_android_server_SerialService(env);
    register_android_server_InputApplicationHandle(env);
    register_android_server_InputWindowHandle(env);
    register_android_server_InputManager(env);
    register_android_server_LightsService(env);
    register_android_server_AlarmManagerService(env);
    register_android_server_UsbDeviceManager(env);
    register_android_server_UsbMidiDevice(env);
    register_android_server_UsbHostManager(env);
    register_android_server_VibratorService(env);
    register_android_server_SystemServer(env);
    register_android_server_location_GpsLocationProvider(env);
    register_android_server_location_FlpHardwareProvider(env);
    register_android_server_connectivity_Vpn(env);
    register_android_server_AssetAtlasService(env);
    register_android_server_ConsumerIrService(env);
    register_android_server_BatteryStatsService(env);
    register_android_server_hdmi_HdmiCecController(env);
    register_android_server_tv_TvInputHal(env);
    register_android_server_PersistentDataBlockService(env);
    register_android_server_Watchdog(env);
    register_com_mediatek_perfservice_PerfServiceManager(env);
#if defined (MTK_HDMI_SUPPORT)
    register_com_mediatek_hdmi_MtkHdmiManagerService(env);
#endif
    // Mediatek AAL support
    register_android_server_display_DisplayPowerController(env);
#ifndef MTK_BSP_PACKAGE
    register_com_android_internal_app_ShutdownManager(env);
#endif
    register_android_server_HelloService(env);//add by eliot_shao
    return JNI_VERSION_1_4;
}

编译:

android 2.3 和android 6.0版本的JNI位置发生了一点变化。
将com_android_server_HelloService.cpp放入frameworks\base\services\core\jni\
修改: LOGI–>ALOGI
LOGE–>ALOGE
修改onload.cpp 和 Android.mk
编译:mmm frameworks/base/services/

生成system/lib/libandroid_servers.so

编译结果

猜你喜欢

转载自blog.csdn.net/flaoter/article/details/79184436