首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

JNI对HAL的打包

2013-01-20 
JNI对HAL的封装文件位置:frameworks\base\services\jni动态注册文件:onload.cpp#include JNIHelp.h#incl

JNI对HAL的封装
文件位置:

frameworks\base\services\jni

动态注册文件:onload.cpp
#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_BatteryService(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_VibratorService(JNIEnv* env);int register_android_server_SystemServer(JNIEnv* env);int register_android_server_location_GpsLocationProvider(JNIEnv* env);};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) {        LOGE("GetEnv failed!");        return result;    }    LOG_ASSERT(env, "Could not retrieve the env!");    register_android_server_PowerManagerService(env);    register_android_server_InputManager(env);    register_android_server_LightsService(env);    register_android_server_AlarmManagerService(env);    register_android_server_BatteryService(env);    register_android_server_VibratorService(env);    register_android_server_SystemServer(env);    register_android_server_location_GpsLocationProvider(env);    return JNI_VERSION_1_4;}

注册文件主要做了两件事情:1在android空间声明注册函数2.在C空间注册jni中注册相关的服务

将注册文件编译进内核

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 \    onload.cpp
3.JNI实现(com_android_server_LightsService.cpp)
/* * 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. */#define LOG_TAG "LightsService"#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/lights.h>#include <stdio.h>namespace android{// These values must correspond with the LIGHT_ID constants in// LightsService.javaenum {    LIGHT_INDEX_BACKLIGHT = 0,    LIGHT_INDEX_KEYBOARD = 1,    LIGHT_INDEX_BUTTONS = 2,    LIGHT_INDEX_BATTERY = 3,    LIGHT_INDEX_NOTIFICATIONS = 4,    LIGHT_INDEX_ATTENTION = 5,    LIGHT_INDEX_BLUETOOTH = 6,    LIGHT_INDEX_WIFI = 7,    LIGHT_COUNT};struct Devices {    light_device_t* lights[LIGHT_COUNT];};static light_device_t* get_device(hw_module_t* module, char const* name){    int err;    hw_device_t* device;    err = module->methods->open(module, name, &device);    if (err == 0) {        return (light_device_t*)device;    } else {        return NULL;    }}static jint init_native(JNIEnv *env, jobject clazz){    int err;    hw_module_t* module;    Devices* devices;        devices = (Devices*)malloc(sizeof(Devices));    err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);    if (err == 0) {        devices->lights[LIGHT_INDEX_BACKLIGHT]                = get_device(module, LIGHT_ID_BACKLIGHT);        devices->lights[LIGHT_INDEX_KEYBOARD]                = get_device(module, LIGHT_ID_KEYBOARD);        devices->lights[LIGHT_INDEX_BUTTONS]                = get_device(module, LIGHT_ID_BUTTONS);        devices->lights[LIGHT_INDEX_BATTERY]                = get_device(module, LIGHT_ID_BATTERY);        devices->lights[LIGHT_INDEX_NOTIFICATIONS]                = get_device(module, LIGHT_ID_NOTIFICATIONS);        devices->lights[LIGHT_INDEX_ATTENTION]                = get_device(module, LIGHT_ID_ATTENTION);        devices->lights[LIGHT_INDEX_BLUETOOTH]                = get_device(module, LIGHT_ID_BLUETOOTH);        devices->lights[LIGHT_INDEX_WIFI]                = get_device(module, LIGHT_ID_WIFI);    } else {        memset(devices, 0, sizeof(Devices));    }    return (jint)devices;}static void finalize_native(JNIEnv *env, jobject clazz, int ptr){    Devices* devices = (Devices*)ptr;    if (devices == NULL) {        return;    }    free(devices);}static void setLight_native(JNIEnv *env, jobject clazz, int ptr,        int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode){    Devices* devices = (Devices*)ptr;    light_state_t state;    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {        return ;    }    memset(&state, 0, sizeof(light_state_t));    state.color = colorARGB;    state.flashMode = flashMode;    state.flashOnMS = onMS;    state.flashOffMS = offMS;    state.brightnessMode = brightnessMode;    devices->lights[light]->set_light(devices->lights[light], &state);}static JNINativeMethod method_table[] = {    { "init_native", "()I", (void*)init_native },//int init_native()    { "finalize_native", "(I)V", (void*)finalize_native },//void finalize_native(int)    { "setLight_native", "(IIIIIII)V", (void*)setLight_native },//void setLight_native(int,int,int,int,int,int,int)};int register_android_server_LightsService(JNIEnv *env){    return jniRegisterNativeMethods(env, "com/android/server/LightsService",            method_table, NELEM(method_table));}};

这个文件主要完成的事情有

1.完成JNI向java的注册:

        jniRegisterNativeMethods,这个函数体现JNI大部分的关键点,主要有env,JNI命名规则,函数签名。

       当VM载入libxxx_jni.so这个库时,就会呼叫JNI_OnLoad()函数。在JNI_OnLoad()中注册本地函数,继续调用到AndroidRuntime::registerNativeMethods(),该函数向VM(即AndroidRuntime)注册gMethods[]数组中包含的本地函数了。AndroidRuntime::registerNativeMethods()起到了以下两个作用:
         1,registerNativeMethods()函数使得java空间中的Native函数更加容易的找到对应的本地函数。(通过gMethods[]中的函数指针)
         2,可以在执行期间进行本地函数的替换。因为gMethods[]数组是一个<java中函数名字,本地函数指针>的对应表,所以可以在程序的执行过程中,多次呼叫registerNativeMethods()函数来更换本地函数的指针,提高程序的弹性。

 2.JNIEnv 介绍


      JNIEnv 是一个与线程相关的变量,由于线程相关,所以线程B中不能使用线程A中的JNIEnv函数。那个多个线程由谁来保存并保证每个线程的JNIEnv结构体正确呢?

jint JNI_OnLoad(JavaVM* vm, void* reserved)全进程只有一个JavaVM对象,可以保存并在任何地方使用没有问题,独此一份。利用JavaVM中的 AttachCurrentThread函数,就可以得到这个线程的 JNIEnv结构体,利用用DetachCurrnetThread释放相应资源。

一般通过JNIEnv 操作jobject的jfieldID  操作成员变量和jmethodID  操作成员函数。这个再JNI中创建的每个资源都有自己的ID,在Java空间中通过找到这些ID,就可以找到相对应的成员变量和成员函数。

static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)

static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,const char* sig)

3.JNI命名规则

    com_android_server_LightsService.cpp,表明这个服务是在com/android/server/下的LightsService.cpp文件,在注册的时候以com/android/server/LightsService作为参数传下去。

4.函数签名

   因为JAVA支持函数重载,可以定义同名但不同参数的函数,但直接根据函数名是没法找到具体函数的,因此利用参数类型及返回类型组成签名信息。利用JNINativeMethod结构保存其关系。
   typedef struct
   {
    //JAVA中native函数名字
    const char *name;
    //签名信息,用字符串表示,参数类型及返回值类型的组合
    const char *signature;
    ///JNI层函数函数指针,转换为void*类型
    void *fnPtr;
   };
常用类型标识符:
类型标识   JAVA类型    字长
  Z        boolean      8位
  B        byte         8位
  C        char         16位 -- 注意哟
  S        short        16位
  I        int          32位
  J        long         64位
  F        float        32位
  D        double       64位
  L/java/languageString  String
  [I       int[]        int数组
  [L/java/lang/object    Object[] 对象数组

在method_table中主要完成了JNI对HAL的封装函数。

5.垃圾回收

finalize_native

4.JNI其他功能1.异常处理

   常用的异常处理函数

Throw():丢弃一个现有的异常对象;在固有方法中用于重新丢弃一个异常。
ThrowNew():生成一个新的异常对象,并将其丢弃。
ExceptionOccurred():判断一个异常是否已被丢弃,但尚未清除。
ExceptionDescribe():打印一个异常和堆栈跟踪信息。
ExceptionClear():清除一个待决的异常。
FatalError():造成一个严重错误,不返回。

在所有这些函数中,最不能忽视的就是ExceptionOccurred()和ExceptionClear()。大多数JNI函数都能产生异常,而且没有象在Java的try块内的那种语言特性可供利用。所以在每一次JNI函数调用之后,都必须调用ExceptionOccurred(),了解异常是否已被丢弃。若侦测到一个异常,可选择对其加以控制(可能时还要重新丢弃它)。然而,必须确保异常最终被清除。这可以在自己的函数中用ExceptionClear()来实现;若异常被重新丢弃,也可能在其他某些函数中进行。

热点排行