一、代码讲解
1、 编写HAL层代码
一般来说HAL moudle需要涉及的是三个关键结构体:
struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;
下面结合代码说明这3个结构的用法
文件:weiyan/hardware/modules/include/weiyan/led.h
- //HAL 规定不能直接使用hw_module_t结构
- //因此需要做这么一个继承
- struct led_module_t {
- struct hw_module_t common;
- };
- struct led_control_device_t {
- //自定义一个针对led控制的结构
- //包含hw_device_t和支持的API操作
- struct hw_device_t common;
- /* supporting control APIs go here */
- int (*set_on)(struct led_control_device_t *dev, int32_t led);
- int (*set_off)(struct led_control_device_t *dev, int32_t led);
- };
- /*****************************************************************************/
- struct led_control_context_t {
- struct led_control_device_t device;
- };
- //定义一个MODULE_ID
- //HAL层可以根据这个ID找到我们这个HAL Stub
- #define LED_HARDWARE_MODULE_ID "led"
文件:weiyan/hardware/modules/led/led.c
- int led_device_close(struct hw_device_t* device)
- {
- struct led_control_device_t* ctx = (struct led_control_device_t*)device;
- if (ctx) {
- free(ctx);
- }
- return 0;
- }
- int led_on(struct led_control_device_t *dev, int32_t led)
- {
- int fd;
- char buff[3] = "";
- int size = 0;
- if ((fd = open(DEVICE_NAME, O_RDWR)) == -1) {
- LOGI("open leds fail");
- return 0;
- }
- //memset(buff,'1',5);
- memset(buff,0,3);
- buff[0]=1;//灯开
- buff[1]=(char)led; //leds 灯号
- size = write(fd, buff, sizeof(buff));
- LOGI("LED Stub: set %d on.", led);
- close(fd);
- return 0;
- }
- int led_off(struct led_control_device_t *dev, int32_t led)
- {
- int fd;
- char buff[5] = "";
- int size = 0;
- if ((fd = open(DEVICE_NAME, O_RDWR)) == -1) {
- LOGI("open leds fail");
- return 0;
- }
- memset(buff,0,3);
- buff[0]=0;//灯关
- buff[1]=(char)led; //leds 灯号
- size = write(fd, buff, sizeof(buff));
- LOGI("LED Stub: set %d off.", led);
- close(fd);
- return 0;
- }
- static int led_device_open(const struct hw_module_t* module, const char* name,
- struct hw_device_t** device)
- {
- struct led_control_device_t *dev;
- dev = (struct led_control_device_t *)malloc(sizeof(*dev));
- memset(dev, 0, sizeof(*dev));
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = module;
- dev->common.close = led_device_close;
- dev->set_on = led_on;//实例化支持的操作
- dev->set_off = led_off;
- //将实例化后的led_control_deivce_t地址返回给jni层
- //这样jni层就可以直接调用led_on、led_off、led_device_close 方法
- *device = &dev->common;
- success:
- return 0;
- }
- static struct hw_module_methods_t led_module_methods = {
- open: led_device_open
- };
- //向系统注册一个iD为LED_HARDWARE_MODULE_ID的stub
- //注意这里的HAL_MODULE_INFO_SYM不能修改
- const struct led_module_t HAL_MODULE_INFO_SYM = {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: LED_HARDWARE_MODULE_ID,
- name: "Sample LED Stub",
- author: "The Mokoid Open Source Project",
- methods: &led_module_methods,
- }
- /* supporting APIs go here */
- };
2.JNI层
文件:weiyan/frameworks/base/service/jni/com_mokoid_server_LedService.cpp
- struct led_control_device_t *sLedDevice = NULL;
- static jboolean weityan_setOn(JNIEnv* env, jobject thiz, jint led) {
- LOGI("LedService JNI: weityan_setOn() is invoked.");
- if (sLedDevice == NULL) {
- LOGI("LedService JNI: sLedDevice was not fetched correctly.");
- return -1;
- } else {
- return sLedDevice->set_on(sLedDevice, led);//调用HAL层的方法
- }
- }
- static jboolean weiyan_setOff(JNIEnv* env, jobject thiz, jint led) {
- LOGI("LedService JNI: weiyan_setOff() is invoked.");
- if (sLedDevice == NULL) {
- LOGI("LedService JNI: sLedDevice was not fetched correctly.");
- return -1;
- } else {
- return sLedDevice->set_off(sLedDevice, led);//调用HAL层的方法
- }
- }
- /** helper APIs */
- static inline int led_control_open(const struct hw_module_t* module,
- struct led_control_device_t** device) {
- //这个过程非常重要
- //JNI通过LED_HARDWARE_MODULE_ID 找到对应的Stub
- return module->methods->open(module,
- LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
- }
- static jboolean
- weiyan_init(JNIEnv *env, jclass clazz)
- {
- led_module_t* module;
- //根据LED_HARDWARE_MODULE_ID找到对应的hw_module_t
- if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
- LOGI("LedService JNI: LED Stub found.");
- if (led_control_open(&module->common, &sLedDevice) == 0) {
- LOGI("LedService JNI: Got Stub operations.");
- return 0;
- }
- }
- LOGE("LedService JNI: Get Stub operations failed.");
- return -1;
- }
- // ----------------------------------------------------------------------------
- /*
- *JNINativeMethod是JNI层注册的方法
- *Framework层可以使用这些方法
- * _init,_set_on,_set_off是Framework层调用的方法
- * ()Z 无参数返回值为bool型
- * (I)Z整形参数返回值为bool型
- */
- static const JNINativeMethod gMethods[] = {
- {"_init", "()Z",
- (void*)weiyan_init},//framework层调用_init 时促发
- { "_set_on", "(I)Z",
- (void*)weityan_setOn },
- { "_set_off", "(I)Z",
- (void*)weiyan_setOff },
- };
- static int registerMethods(JNIEnv* env) {
- static const char* const kClassName =
- "com/weiyan/server/LedService";//必须与Frameword层的service类名相同
- jclass clazz;
- /* look up the class */
- clazz = env->FindClass(kClassName);
- if (clazz == NULL) {
- LOGE("Can't find class %s/n", kClassName);
- return -1;
- }
- /* register all the methods */
- if (env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
- {
- LOGE("Failed registering methods for %s/n", kClassName);
- return -1;
- }
- /* fill out the rest of the ID cache */
- return 0;
- }
- // ----------------------------------------------------------------------------
- /*
- * Framework层加载JNI库时调用
- */
- 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("ERROR: GetEnv failed/n");
- goto bail;
- }
- assert(env != NULL);
- //注册JNINavtiveMethod方法
- if (registerMethods(env) != 0) {
- LOGE("ERROR: PlatformLibrary native registration failed/n");
- goto bail;
- }
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
- bail:
- return result;
- }
3.Framework层的service
文件:weiyan/frameworks/base/service/java/com/weiyan/server
- public final class LedService extends ILedService.Stub {
- static {
- System.load("/system/lib/libmokoid_runtime.so");//加载JNI动态 库
- }
- public LedService() {
- Log.i("LedService", "Go to get LED Stub...");
- _init();
- }
- /*
- * Mokoid LED native methods.
- */
- public boolean setOn(int led) {
- Log.i("MokoidPlatform", "LED On");
- return _set_on(led);
- }
- public boolean setOff(int led) {
- Log.i("MokoidPlatform", "LED Off");
- return _set_off(led);
- }
- //声明jni可以使用的方法
- private static native boolean _init();
- private static native boolean _set_on(int led);
- private static native boolean _set_off(int led);
- }
4.APP 测试程序 (属于APP层)
APP层两种调用模式
(1)Android的app可以直接通过service调用.so格式的jni
(2)经过Manager调用service
Manager (属于Framework层)
- public class LedManager
- {
- private static final String TAG = "LedManager";
- private ILedService mLedService;
- public LedManager() {
- //利用ServiceManager获取LedService,从而调用它
- //提供的方法,这要求LedService必须已经增加
- //到ServiceManager中,这个过程将在App的一个
- //Service进程中完成
- mLedService = ILedService.Stub.asInterface(
- ServiceManager.getService("led"));
- if (mLedService != null) {
- Log.i(TAG, "The LedManager object is ready.");
- }
- }
- public boolean LedOn(int n) {
- boolean result = false;
- try {
- result = mLedService.setOn(n);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in LedManager.LedOn:", e);
- }
- return result;
- }
- public boolean LedOff(int n) {
- boolean result = false;
- try {
- result = mLedService.setOff(n);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
- }
- return result;
- }
- }
因为LedService和LedManager在不同的进程,所以要考虑到进程通讯的问题。Manager通过增加一个aidl文件来描述通讯接口
文件:weiyan/frameworks/base/core/java/weiyan/hardware/ILedService.aidl
package mokoid.hardware;
interface ILedService
{
boolean setOn(int led);
boolean setOff(int led);
}
系统的aidl工具会将ILedService.aidl生成ILedService.java文件,实现IledService
SystemServer (属于APP层)
文件: weiyan/apps/LedTest/src/com/weiyan/LedTest/LedSystemServer.java
- public class LedSystemServer extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- public void onStart(Intent intent, int startId) {
- Log.i("LedSystemServer", "Start LedService...");
- /* Please also see SystemServer.java for your interests. */
- LedService ls = new LedService();
- try {
- //将LedService添加到ServiceManager
- ServiceManager.addService("led", ls);
- } catch (RuntimeException e) {
- Log.e("LedSystemServer", "Start LedService failed.");
- }
- }
- }
二、 加载方法
1、把weiyan.tar.gz解压到/opt/ android_froyo_smdk
$ cd /opt/ android_froyo_smdk
$ tar -jxvf weiyan.tar.bz2
2、 修改build/core/config.mk文件防止编译找不到led.h头文件
$cd /opt/ android_froyo_smdk
$gedit build/core/config.mk
找到SRC_HEADERS := /
$(TOPDIR)system/core/include /
在后面加入
$(TOPDIR)weiyan/hardware/modules/include
3、编译工程
$ source /opt/android_froyo_smdk/build/envsetup.sh
$ export TARGET_PRODUCT=sec_smdkv210
$mmm /opt/android_froyo_smdk/weiyan
编译成功后会如下路径生成apk文件,库文件,jar包等
/opt/android_froyo_smdk/out/target/product/smdkv210/system/app/LedClient.apk
/opt/android_froyo_smdk/out/target/product/smdkv210/system/app/LedTest.apk
/opt/android_froyo_smdk/out/target/product/smdkv210/system/framework/ledctl.jar
/opt/android_froyo_smdk/out/target/product/smdkv210/system/lib/hw/led.smdkv210.so
/opt/android_froyo_smdk/out/target/product/smdkv210/system/lib/libled.so
/opt/android_froyo_smdk/out/target/product/smdkv210/system/lib/libmokoid_runtime.so
把LedClient.apk, LedTest.apk放到android的system/app目录,把ledctl.jar放到system/framework目录,把led.smdkv210.so放到system/lib/hw目录,把ibled.so,
libmokoid_runtime.so放到system/lib目录下
4、为了android桌面能显示我们的LedClient.apk, LedTest.apk程序,把weiyan/frameworks/base/service/com.weiyan.server.xml放到android的
system/etc/permissions目录下
5、加载led驱动模块
把leds.ko复制到android 的system目录下,执行
#insmod leds.ko
#chmod 666 /dev/leds
6、运行LedClient.apk, LedTest.apk