您的位置:首页 > 编程语言 > Java开发

如何封装HAL API以及对应的JAVA API

2014-02-27 15:13 387 查看
如何封装HAL API以及对应的JAVA
API

HAL

Android与硬件访问有关的文件都在hardware目录中,组成了所谓的HAL(Hardware
Abstraction Layer)层。主要作用就是通过这一层给上层提供不变的API,如果硬件有所改变,只需要修改HAL的实现,大部分情况下可以保持提供给上层的API不会变化。这样硬件的改变后,上层的软件不需要改就可以继续工作。



图1 包含HAL层的Android架构

下面以led为例介绍如何封装HAL
API以及对应的JAVA API

结构图:



Android\hardware\libhardware\led\Android.mk

ifeq ($(TARGET_PRODUCT),sooner)
LOCAL_SRC_FILES += led/led_sardine.c
else
ifeq ($(TARGET_PRODUCT),dream)
LOCAL_SRC_FILES += led/led_trout.c
else
LOCAL_SRC_FILES += led/led_stub.c
endif
endif


通过宏TARGET_PRODUCT选择编译哪一个led文件。led_stub.c里面只有空的函数定义没有实现,提供给用户实现自己的led
HAL驱动,这也是stub(桩)的含义。

Android\hardware\libhardware\include\hardware\led.h

int set_led_state(unsigned colorARGB, int onMS, int offMS);

set_led_state函数就是led
hal提供给上层的API。

Android\hardware\libhardware\led\led_sardine.c

实现set_led_state函数,set_led_state主要做的工作很简单,就是把上层应用传递进来的参数进行转换,然后通过调用linux驱动,把参数设置到硬件上。

在这个例子中,set_led_state函数接受的颜色参数是colorARGB,不过我们的硬件只认识红色和绿色,如果设置为0就是红色,1就是绿色,那么我们就要把colorARGB转换成0或者1,然后调用linux驱动去设置。

设置的过程就是通过调用linux对设备文件的写入而实现,设备文件就是:

const char* const COLOR_FILE = "/sys/class/leds/left/color";

还有其他的设备文件,用来设置其他的属性:

const char* const CADENCE_FILE = "/sys/class/leds/left/cadence";

const char* const BT_WIFI_FILE = "/sys/class/leds/right/brightness";

HAL提供的API如何被java程序所使用

Android的app是java实现的,那么要调用c语言或者c++语言实现的HAL的接口需要借助java的一种机制--JNI(Java
Native Interface)。上层的java程序会定义一些函数为native的,意思是这些函数将在其他的语言中实现,比如c。然后在c中实现这些函数,然后通过jni注册为java所声明的函数,这样java调用native函数就会调用对应的c/c++函数。

上层java 声明的API

搜索函数名setLedState,可以找到java
app使用的API封装。

package android.os;

Android\Frameworks\base\core\java\android\os\hardware.java

/**
* {@hide}
*/
public class Hardware
{
/**
* Control the LED.
*/
public static native int setLedState(int colorARGB, int onMS, int offMS);
…..
}


注意函数申明的前缀”native”,注意类名android.os.Hardware(package
android.os)。

类的路径名就是类名android.os.hardware,在java应用程序中引用的话,用语句:

import android.os.hardware


定制的包可以放在: Android\Frameworks\base\core\java\com\huawei(或者google等等)

比如Android\Frameworks\base\core\java\com\huawei\android\debug\JNITest.java

用包的时候用语句:

import com.huawei.android.debug

Android\Frameworks\base\core\jni\android_os_Hardware.cpp

static jboolean
setLedState(JNIEnv *env, jobject clazz, jint colorARGB, jint onMS, jint offMS)
{
return set_led_state(colorARGB, onMS, offMS);
}


把set_led_state封装成setLedState,加了参数,所加的参数就是为了和上层java程序联系用的。

static JNINativeMethod g_methods[] = {
/* name, signature, funcPtr */
{ "setLedState",       "(III)I", (void*)setLedState },
{ "getFlashlightEnabled", "()Z", (void*)getFlashlightEnabled },
{ "setFlashlightEnabled", "(Z)V", (void*)setFlashlightEnabled },
{ "enableCameraFlash", "(I)V", (void*)enableCameraFlash },
{ "setScreenBacklight", "(I)V", (void*)setScreenBacklight },
{ "setKeyboardBacklight", "(Z)V", (void*)setKeyboardBacklight },
{ "setButtonBacklight", "(Z)V", (void*)setButtonBacklight },
};


把c的函数指针放到一个数组里面,方便批量的注册。第一个参数”setLedState”要和java声明的函数名称一样。第二个参数"(III)I",表示setLedState函数有3个int参数,返回值是int。第三个参数是c/c++函数指针。

int register_android_os_Hardware(JNIEnv* env)
{
return AndroidRuntime::registerNativeMethods(env,
"android/os/Hardware", g_methods, NELEM(g_methods));
}


Android/os/Hardware是java的类名。

Android\Frameworks\base\core\jni\AndroidRuntime.cpp

static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Hardware),
……
}


数组gRegJNI[]保存了所有注册JNI的函数,在android启动的时候会依次调用,把所有系统需要的Native函数都注册到虚拟机中。我们的register_android_os_Hardware函数自然要放在其中。

/*
* Register native methods using JNI.
*/
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods)
{
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}


函数jniRegisterNativeMethods是jni的标准函数,作用是把c函数注册到JNI中。这样java
API就和HAL提供的API联系起来了。

最后用一幅图来描述调用关系

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  api linux驱动 封装 hal jni
相关文章推荐