Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30871
  • 博文数量: 7
  • 博客积分: 67
  • 博客等级: 民兵
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-22 14:53
文章分类
文章存档

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_setOnmokoid_setOff中分别利用led_control_device_t中的set_onset_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_onled_offled_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 = {

// //定义这个对象等于向系统注册了一个IDLED_HARDWARE_MODULE_IDstub。注意这里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

                           http://buaadallas.blog.51cto.com/399160/371545

 

阅读(3735) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~