Android底层开发Led控制实验

一、代码讲解

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

 

[c-sharp]  view plain copy
  1. //HAL  规定不能直接使用hw_module_t结构  
  2. //因此需要做这么一个继承  
  3. struct led_module_t {  
  4.    struct hw_module_t common;  
  5. };  
  6. struct led_control_device_t {  
  7.     //自定义一个针对led控制的结构  
  8.     //包含hw_device_t和支持的API操作  
  9.    struct hw_device_t common;  
  10.    /* supporting control APIs go here */  
  11.    int (*set_on)(struct led_control_device_t *dev, int32_t led);  
  12.    int (*set_off)(struct led_control_device_t *dev, int32_t led);  
  13. };  
  14. /*****************************************************************************/  
  15. struct led_control_context_t {  
  16.     struct led_control_device_t device;  
  17. };  
  18. //定义一个MODULE_ID  
  19. //HAL层可以根据这个ID找到我们这个HAL Stub  
  20. #define LED_HARDWARE_MODULE_ID "led"  
 

文件:weiyan/hardware/modules/led/led.c

[c-sharp]  view plain copy
  1. int led_device_close(struct hw_device_t* device)  
  2. {  
  3.     struct led_control_device_t* ctx = (struct led_control_device_t*)device;  
  4.     if (ctx) {  
  5.         free(ctx);  
  6.     }  
  7.     return 0;  
  8. }  
  9. int led_on(struct led_control_device_t *dev, int32_t led)  
  10. {  
  11.     int fd;  
  12.     char buff[3] = "";  
  13.     int size = 0;  
  14.     if ((fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
  15.             LOGI("open leds fail");  
  16.             return 0;  
  17.         }  
  18.     //memset(buff,'1',5);  
  19.     memset(buff,0,3);  
  20.     buff[0]=1;//灯开  
  21.     buff[1]=(char)led; //leds 灯号  
  22.       
  23.     size = write(fd, buff, sizeof(buff));  
  24.     LOGI("LED Stub: set %d on.", led);  
  25.     close(fd);  
  26.     return 0;  
  27. }  
  28. int led_off(struct led_control_device_t *dev, int32_t led)  
  29. {  
  30.     int fd;  
  31.     char buff[5] = "";  
  32.     int size = 0;  
  33.     if ((fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
  34.             LOGI("open leds fail");  
  35.             return 0;  
  36.         }  
  37.     memset(buff,0,3);  
  38.     buff[0]=0;//灯关  
  39.     buff[1]=(char)led; //leds 灯号  
  40.     size = write(fd, buff, sizeof(buff));  
  41.     LOGI("LED Stub: set %d off.", led);  
  42.     close(fd);  
  43.     return 0;  
  44. }  
  45. static int led_device_open(const struct hw_module_t* module, const char* name,  
  46.         struct hw_device_t** device)   
  47. {  
  48.     struct led_control_device_t *dev;  
  49.     dev = (struct led_control_device_t *)malloc(sizeof(*dev));  
  50.     memset(dev, 0, sizeof(*dev));  
  51.     dev->common.tag =  HARDWARE_DEVICE_TAG;  
  52.     dev->common.version = 0;  
  53.     dev->common.module = module;  
  54.     dev->common.close = led_device_close;  
  55.     dev->set_on = led_on;//实例化支持的操作  
  56.     dev->set_off = led_off;  
  57.     //将实例化后的led_control_deivce_t地址返回给jni层  
  58.     //这样jni层就可以直接调用led_on、led_off、led_device_close 方法  
  59.     *device = &dev->common;  
  60. success:  
  61.     return 0;  
  62. }  
  63. static struct hw_module_methods_t led_module_methods = {  
  64.     open: led_device_open  
  65. };  
  66. //向系统注册一个iD为LED_HARDWARE_MODULE_ID的stub  
  67. //注意这里的HAL_MODULE_INFO_SYM不能修改  
  68. const struct led_module_t HAL_MODULE_INFO_SYM = {  
  69.     common: {  
  70.         tag: HARDWARE_MODULE_TAG,  
  71.         version_major: 1,  
  72.         version_minor: 0,  
  73.         id: LED_HARDWARE_MODULE_ID,  
  74.         name: "Sample LED Stub",  
  75.         author: "The Mokoid Open Source Project",  
  76.         methods: &led_module_methods,  
  77.     }  
  78.     /* supporting APIs go here */  
  79. };  
 

 

2.JNI层

 

文件:weiyan/frameworks/base/service/jni/com_mokoid_server_LedService.cpp

[c-sharp]  view plain copy
  1. struct led_control_device_t *sLedDevice = NULL;  
  2. static jboolean weityan_setOn(JNIEnv* env, jobject thiz, jint led) {  
  3.     LOGI("LedService JNI: weityan_setOn() is invoked.");  
  4.     if (sLedDevice == NULL) {  
  5.         LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
  6.         return -1;  
  7.     } else {  
  8.         return sLedDevice->set_on(sLedDevice, led);//调用HAL层的方法  
  9.     }  
  10. }  
  11. static jboolean weiyan_setOff(JNIEnv* env, jobject thiz, jint led) {  
  12.     LOGI("LedService JNI: weiyan_setOff() is invoked.");  
  13.     if (sLedDevice == NULL) {  
  14.         LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
  15.         return -1;  
  16.     } else {  
  17.         return sLedDevice->set_off(sLedDevice, led);//调用HAL层的方法  
  18.     }  
  19. }  
  20. /** helper APIs */  
  21. static inline int led_control_open(const struct hw_module_t* module,  
  22.         struct led_control_device_t** device) {  
  23.     //这个过程非常重要  
  24.     //JNI通过LED_HARDWARE_MODULE_ID 找到对应的Stub  
  25.     return module->methods->open(module,  
  26.             LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  
  27. }  
  28. static jboolean  
  29. weiyan_init(JNIEnv *env, jclass clazz)  
  30. {  
  31.     led_module_t* module;  
  32.     //根据LED_HARDWARE_MODULE_ID找到对应的hw_module_t  
  33.     if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {  
  34.         LOGI("LedService JNI: LED Stub found.");  
  35.         if (led_control_open(&module->common, &sLedDevice) == 0) {  
  36.             LOGI("LedService JNI: Got Stub operations.");  
  37.             return 0;  
  38.         }  
  39.     }  
  40.     LOGE("LedService JNI: Get Stub operations failed.");  
  41.     return -1;  
  42. }  
  43. // ----------------------------------------------------------------------------  
  44. /* 
  45.  *JNINativeMethod是JNI层注册的方法 
  46.  *Framework层可以使用这些方法 
  47.  * _init,_set_on,_set_off是Framework层调用的方法 
  48.  * ()Z 无参数返回值为bool型 
  49.  * (I)Z整形参数返回值为bool型 
  50.  */  
  51. static const JNINativeMethod gMethods[] = {  
  52.     {"_init",       "()Z",  
  53.             (void*)weiyan_init},//framework层调用_init 时促发  
  54.     { "_set_on",          "(I)Z",  
  55.                         (void*)weityan_setOn },  
  56.     { "_set_off",          "(I)Z",  
  57.                         (void*)weiyan_setOff },  
  58. };  
  59. static int registerMethods(JNIEnv* env) {  
  60.     static const charconst kClassName =  
  61.         "com/weiyan/server/LedService";//必须与Frameword层的service类名相同  
  62.     jclass clazz;  
  63.     /* look up the class */  
  64.     clazz = env->FindClass(kClassName);  
  65.     if (clazz == NULL) {  
  66.         LOGE("Can't find class %s/n", kClassName);  
  67.         return -1;  
  68.     }  
  69.     /* register all the methods */  
  70.     if (env->RegisterNatives(clazz, gMethods,  
  71.             sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)  
  72.     {  
  73.         LOGE("Failed registering methods for %s/n", kClassName);  
  74.         return -1;  
  75.     }  
  76.     /* fill out the rest of the ID cache */  
  77.     return 0;  
  78. }  
  79. // ----------------------------------------------------------------------------  
  80. /* 
  81.  * Framework层加载JNI库时调用 
  82.  */  
  83. jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
  84.     JNIEnv* env = NULL;  
  85.     jint result = -1;  
  86.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  87.         LOGE("ERROR: GetEnv failed/n");  
  88.         goto bail;  
  89.     }  
  90.     assert(env != NULL);  
  91.     //注册JNINavtiveMethod方法  
  92.     if (registerMethods(env) != 0) {  
  93.         LOGE("ERROR: PlatformLibrary native registration failed/n");  
  94.         goto bail;  
  95.     }  
  96.     /* success -- return valid version number */  
  97.     result = JNI_VERSION_1_4;  
  98. bail:  
  99.     return result;  
  100. }  
 


 

 


3.Framework层的service

文件:weiyan/frameworks/base/service/java/com/weiyan/server

[c-sharp]  view plain copy
  1. public final class LedService extends ILedService.Stub {      
  2.     static {  
  3.         System.load("/system/lib/libmokoid_runtime.so");//加载JNI动态 库  
  4.     }  
  5.     public LedService() {  
  6.         Log.i("LedService""Go to get LED Stub...");  
  7.     _init();  
  8.     }  
  9.     /* 
  10.      * Mokoid LED native methods. 
  11.      */  
  12.     public boolean setOn(int led) {  
  13.         Log.i("MokoidPlatform""LED On");  
  14.     return _set_on(led);  
  15.     }  
  16.     public boolean setOff(int led) {  
  17.         Log.i("MokoidPlatform""LED Off");  
  18.     return _set_off(led);  
  19.     }  
  20.     //声明jni可以使用的方法  
  21.     private static native boolean _init();  
  22.     private static native boolean _set_on(int led);  
  23.     private static native boolean _set_off(int led);  
  24. }  
 

 

4.APP 测试程序 (属于APP层)

    APP层两种调用模式

(1)Android的app可以直接通过service调用.so格式的jni

(2)经过Manager调用service

Manager (属于Framework层)

[c-sharp] view plaincopy
  1. public class LedManager  
  2. {  
  3.     private static final String TAG = "LedManager";  
  4.     private ILedService mLedService;  
  5.     public LedManager() {  
  6.         //利用ServiceManager获取LedService,从而调用它  
  7.         //提供的方法,这要求LedService必须已经增加  
  8.         //到ServiceManager中,这个过程将在App的一个  
  9.         //Service进程中完成  
  10.       
  11.         mLedService = ILedService.Stub.asInterface(  
  12.                              ServiceManager.getService("led"));  
  13.     if (mLedService != null) {  
  14.             Log.i(TAG, "The LedManager object is ready.");  
  15.     }  
  16.     }  
  17.     public boolean LedOn(int n) {  
  18.         boolean result = false;  
  19.         try {  
  20.             result = mLedService.setOn(n);  
  21.         } catch (RemoteException e) {  
  22.             Log.e(TAG, "RemoteException in LedManager.LedOn:", e);  
  23.         }  
  24.         return result;  
  25.     }  
  26.     public boolean LedOff(int n) {  
  27.         boolean result = false;  
  28.         try {  
  29.             result = mLedService.setOff(n);  
  30.         } catch (RemoteException e) {  
  31.             Log.e(TAG, "RemoteException in LedManager.LedOff:", e);  
  32.         }  
  33.         return result;  
  34.     }  
  35. }  
 

因为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

[c-sharp]  view plain copy
  1. public class LedSystemServer extends Service {  
  2.     @Override  
  3.     public IBinder onBind(Intent intent) {  
  4.         return null;  
  5.     }  
  6.     public void onStart(Intent intent, int startId) {  
  7.         Log.i("LedSystemServer""Start LedService...");  
  8.     /* Please also see SystemServer.java for your interests. */  
  9.     LedService ls = new LedService();  
  10.         try {  
  11.             //将LedService添加到ServiceManager  
  12.             ServiceManager.addService("led", ls);  
  13.         } catch (RuntimeException e) {  
  14.             Log.e("LedSystemServer""Start LedService failed.");  
  15.         }  
  16.     }  
  17. }  
 


 

 

二、 加载方法

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

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值