2012年(7)
分类:
2012-05-04 16:21:11
原文地址:Android LED HAL调试 作者:Cheney-Xu
Android LED HAL调试
|
前段时间在调试android2.3,芯片是s5pv210,一直没时间整理调试笔记,下面的代码来源于,其中做了一些修改,主要是与android版本不同和HAL层有关,代码的大体思路都是围绕JNI调用,数据流为APP->service(java)->service(jni,so文件)->HAL(so文件) |
|
Android应用程序层,下面的代码直接与Led Server层交互,能过创建Led Server层的对像,使得数据流可以从APk层一层一层向下传递直到linux驱动层 |
package com.mokoid.LedClient; import com.mokoid.server.LedService; import android.app.Activity; import android.os.Bundle; import android.widget.TextView;
public class LedClient extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// Call an API on the library. LedService ls = new LedService(); ls.setOn(0); ls.setOn(1); ls.setOff(2);
TextView tv = new TextView(this); tv.setText("LED 1 is on. LED 2 is on. LED 3 is off."); setContentView(tv); } } |
|
Led Server层会通过System.load函数加载JNI层的动态库 |
package com.mokoid.server; import android.util.Config; import android.util.Log; import android.content.Context; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.os.IBinder; import mokoid.hardware.ILedService;
public final class LedService extends ILedService.Stub {
static { System.load("/system/lib/libmokoid_runtime.so"); }
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); }
private static native boolean _init(); private static native boolean _set_on(int led); private static native boolean _set_off(int led); }
|
|
JNI层代码如下:mokoid_init函数中调用hw_get_module函数(hw_get_module函数会通过模块ID寻找到模块的动态库路径然后通过通过load函数加载模块,有点类似驱动中insmod哈),hw_get_module函数返回的数据类型为led_module_t型指针; 然后可以通过module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device);来调用HAL中的OPEN函数来进行模块的初始化操作,并且得到led硬件操作的结构体(led_control_device_t)对象,接着在mokoid_setOn和mokoid_setOff中分别利用led_control_device_t中的set_on和set_off进行相应的操作。JNI层代码最终会编译成动态链接库,被java层加载
|
#define LOG_TAG "Mokoid" #include "utils/Log.h" #include #include #include #include
#include #include "led.h"
// ----------------------------------------------------------------------------
struct led_control_device_t *sLedDevice = NULL;
static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) { LOGI("LedService JNI: mokoid_setOn() is invoked.");
if (sLedDevice == NULL) { LOGI("LedService JNI: sLedDevice was not fetched correctly."); return -1; } else { return sLedDevice->set_on(sLedDevice, led); } }
static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) { LOGI("LedService JNI: mokoid_setOff() is invoked.");
if (sLedDevice == NULL) { LOGI("LedService JNI: sLedDevice was not fetched correctly."); return -1; } else { return sLedDevice->set_off(sLedDevice, led); } }
/** helper APIs */ static inline int led_control_open(const struct hw_module_t* module, struct led_control_device_t** device) { return module->methods->open(module, LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device); }
static jboolean mokoid_init(JNIEnv *env, jclass clazz) { led_module_t* module;
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; }
// --------------------------------------------------------------------------
/* * Array of methods. * * Each entry has three fields: the name of the method, the method * signature, and a pointer to the native implementation. */ static const JNINativeMethod gMethods[] = { { "_init", "()Z", (void *)mokoid_init }, { "_set_on", "(I)Z", (void *)mokoid_setOn }, { "_set_off", "(I)Z", (void *)mokoid_setOff }, };
int register_mokoid_server_LedService(JNIEnv* env) { static const char* const kClassName = "com/mokoid/server/LedService"; 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; }
static int registerMethods(JNIEnv* env) { static const char* const kClassName ="com/mokoid/server/LedService"; 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; } /* * This is called by the VM when the shared library is first loaded. */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; LOGI("JNI_OnLoad LED"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed/n"); goto fail; } assert(env != NULL); if (registerMethods(env) != 0) { LOGE("ERROR: PlatformLibrary native registration failed/n"); goto fail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; fail: return result; }
|
|
hw_get_module函数的代码如下: |
|
int hw_get_module(const char *id, const struct hw_module_t **module) { int status; int i; const struct hw_module_t *hmi = NULL; char prop[PATH_MAX]; char path[PATH_MAX];
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) { if (i < HAL_VARIANT_KEYS_COUNT) { if (property_get(variant_keys[i], prop, NULL) == 0) { continue; }//查找并获取系统属性中硬件定义,该定义一般放在/system/build.prop或//初始化脚本中 snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH1, id, prop);//把库的路径放在path中 if (access(path, R_OK) == 0) break;
snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH2, id, prop); if (access(path, R_OK) == 0) break; } else { snprintf(path, sizeof(path), "%s/%s.default.so", HAL_LIBRARY_PATH1, id);//如果没有找到就用 //default.so,这也是为什么上面用i<HAL_VARIANT_KEYS_COUNT+1原因 if (access(path, R_OK) == 0) break; } }
status = -ENOENT; if (i < HAL_VARIANT_KEYS_COUNT+1) { status = load(id, path, module); }
return status; } |
参考定义: static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board", "ro.board.platform", "ro.arch" };
static const int HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/sizeof(variant_keys[0]));
/** Base path of the hal modules */ #define HAL_LIBRARY_PATH1 "/system/lib/hw" #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
|
|
LED HAL层,该层位于Linux的用户空间,直接调用底层驱动,来操作硬件。HAL层中有三个比较重要的结构体,hw_module_t结构体用于定义硬件模块,hw_device_t表示硬件设备,它中存储硬件设备的公共属性和操作方法,hw_module_methods_t定义操作设备的方法,该结构体中只定义了一个open函数需要用户实现,通常具体的HAL开发,会继承这两个结构体,如下led.h的定义 |
#include #include #include #include #include
/***************************************************************************/
struct led_module_t { struct hw_module_t common; };
struct led_control_device_t { struct hw_device_t common;
/* attributes */ int fd;
/* 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; };
#define LED_HARDWARE_MODULE_ID "led"
|
以下为led.c文件的内容,它为LED HAL层的实现 #define LOG_TAG "MokoidLedStub" #include #include #include #include #include #include "../include/mokoid/led.h" /*****************************************************************************/ int fd;//硬件led的设备描述符,你也可以用led_control_device_t结构中定义的fd
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); } close(fd); return 0; } int led_on(struct led_control_device_t *dev, int32_t led) { LOGI("LED Stub: set %d on.", led); ioctl(fd,1,led); return 0; } int led_off(struct led_control_device_t *dev, int32_t led) { LOGI("LED Stub: set %d off.", led); ioctl(fd,0,led); 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; *device = &dev->common; //将实例化后的led_control_device_t地址返回//给jni层这样jni层就可以直接调用led_on、led_off、led_device_close方法了 if((fd=open("/dev/Real210-led",O_RDWR))==-1) { LOGE("LED open error"); } else LOGI("open ok"); success: return 0; } static struct hw_module_methods_t led_module_methods = { open: led_device_open }; const struct led_module_t HAL_MODULE_INFO_SYM = { // //定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里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, //实现了一个open的方法供jni层调用, //从而实例化led_control_device_t } /* supporting APIs go here */ };
|
参考资料:http://blog.chinaunix.net/link.php?url=http://blog.csdn.net%2Fhongtao_liu |