你的位置:首页 > 操作系统

[操作系统][转] 基于TINY4412的Andorid开发


阅读目录

  • 一、编写驱动程序
  • 二、编写代码测试驱动程序
  • 三、编写HAL代码
  • 四、编写Framework代码
  • 五、编写JNI代码
  • 六、编写App

参考资料:

《Andriod系统源代码情景分析》

《嵌入式Linux系统开发完全手册_基于4412_上册》

作者:彭东林

邮箱:pengdonglin137@163.com

平台介绍:

主机:Win7 32位

虚拟机:VMware10 + ubuntu-12.04.2-desktop-amd64

Android版本:  android-4.2.2_r1

Linux内核版本:linux-3.5.0

Bootloader:  友善之臂提供的Superboot4412.bin

目标平台:tiny4412ADK+S700 4GB Flash

 

目的: 在Tiny4412上运行的Android系统上,通过点击屏幕上的Button来控制Tiny4412的核心板上的四个LED灯的亮灭。一个有八个Button,每个灯的亮灭通过两个灯来控制,点击ON,相应的LED亮;点击OFF,相应的LED灯灭。

 

下面分几步完成:

1、编写驱动程序

2、测试驱动程序

3、编写HAL代码

4、编写framework代码

5、编写JNI代码

6、编写App

下面开始:

回到顶部

一、编写驱动程序

分析tiny4412的原理图,看一下LED灯的位置:

image

可以知道,LED是低电平亮,高电平灭。

看一下,接到了Exynos4412的哪些引脚上了:

image

可以看到:

LED1  --------- GPM4_0

LED2  --------- GPM4_1

LED3  --------- GPM4_2

LED4  --------- GPM4_3

看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:

image

图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.

在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。

以GPM4_0引脚为例:

image

为了控制灯,[3:0]应设置为0x01,即输出模式

image

向GPM4DAT的第0位写0,GPM4_0引脚输出低电平,LED1亮;

向GPM4DAT的第0位写1,GPM4_0引脚输出高电平,LED1灭;

接下来,开始写驱动程序,用友善之臂自带的Linux3.5.0内核

  1: cd linux-3.5/
  2: cd drivers/
  3: mkdir android_led
  4: cd android_led/

在android_led/下创建led_demo.c和led_demo.h文件:

touch led_demo.c led_demo.h

再在其中创建Makefile和Kconfig文件

touch Makefile Kconfig
  • 修改Kconfig:
  1: config LED_DEMO

  2:   tristate "Android Led Demo"

  3:   default n

  4:   help

  5:   This is the led demo for Android system.

  • 修改Makefile:
obj-$(CONFIG_LED_DEMO) += led_demo.o
  • 修改drivers/Kconfig,添加 source “drivers/android_led/Kconfig”
  1: menu "Device Drivers"

  2:  

  3: source "drivers/android_led/Kconfig"

  4:  

  5: ......

  6:  

  7: endmenu

  • 修改drivers/Makefile:
  1: ......
  2:  
  3: obj-$(CONFIG_LED_DEMO) += android_led/

  • 在内核顶层目录下执行make  menuconfig,进入Device Drivers,将 Android Led Demo选择为*,然后保存配置退出。

image

 

注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了Android上用的Linux内核,并且在arch/arm/boot下生成了zImage等文件。

在前期开发的时候,时不时要编译,可以将drivers/android_led/Makefile修改为:

  1: #obj-$(CONFIG_LED_DEMO) += led_demo.o
  2: obj-m += led_demo.o

编译的时候,可以使用:

make M=drivers/android_led modules

目的是提高编译速度,最后再将Makfile改回原样。临时测试,可以在Wind7的命令行下,使用adb push将led_demo.ko上传到/data/local下,然后用adb shell登陆板子,进行测试。

  • 修改led_demo.h和led_demo.c

led_demo.h

  1: #ifndef __LED_DEMO_H__
  2: #define __LED_DEMO_H__
  3:  
  4: #include <linux/cdev.h>
  5:  
  6: #define LED_ON  _IOW('L', 0, int)
  7: #define LED_OFF  _IOW('L', 1, int)
  8:  
  9: #define LED_DEMO_DEVICE_NODE_NAME "led_demo"
 10: #define LED_DEMO_DEVICE_CLASS_NAME "led_demo"
 11: #define LED_DEMO_DEVICE_FILE_NAME "led_demo"
 12:  
 13: #define EXYNOS4412_GPM4CON  0x110002E0
 14: #define EXYNOS4412_GPM4DAT  0x110002E4
 15:  
 16:  
 17: struct led_demo_dev
 18: {
 19:   struct cdev dev;
 20: };
 21:  
 22: #endif

 

led_demo.c

  1: #include <linux/kernel.h>
  2: #include <linux/module.h>
  3: #include <linux/fs.h>
  4: #include <linux/slab.h>
  5: #include <linux/device.h>
  6:  
  7: #include <asm/io.h>
  8: #include <asm/uaccess.h>
  9:  
 10:  
 11: #include "led_demo.h"
 12:  
 13:  
 14: MODULE_LICENSE("GPL");
 15:  
 16:  
 17: static int led_demo_major;
 18: static int led_demo_minor;
 19: static int number_of_dev = 1;
 20:  
 21: static struct led_demo_dev *led_dev = NULL;
 22:  
 23: static unsigned int *GPM4CON = NULL;
 24: static unsigned int *GPM4DAT = NULL;
 25:  
 26: static struct class *led_demo_class = NULL;
 27:  
 28:  
 29: static int led_open (struct inode *node, struct file *fops)
 30: {
 31:   struct led_demo_dev *dev;
 32:  
 33:   dev = container_of(node->i_cdev, struct led_demo_dev, dev);
 34:  
 35:   fops->private_data = dev;
 36:  
 37:   return 0;
 38: }
 39: static int led_close (struct inode *node, struct file *fops)
 40: {
 41:   return 0;
 42: }
 43:  
 44: static long led_ioctl (struct file *fops, unsigned int cmd, unsigned long data)
 45: {
 46:   //struct led_demo_dev * led_dev = (struct led_demo_dev *)fops->private_data;
 47:  
 48:   if((data < 1) || (data > 4))
 49:   {
 50:     printk(KERN_ALERT"parameter is no valid.\n");
 51:     return -EINVAL;
 52:   }
 53:   
 54:   switch (cmd)
 55:   {
 56:     case LED_OFF:
 57:       writel(readl(GPM4DAT) | (0x1<<(data-1)), GPM4DAT);
 58:       break;
 59:     case LED_ON:
 60:       writel(readl(GPM4DAT) & ~(0x1<<(data-1)), GPM4DAT);
 61:       break;
 62:     default:
 63:       return -EINVAL;
 64:       break;
 65:   }
 66:  
 67:   
 68:   return 0;
 69: }
 70:  
 71: struct file_operations led_fops =
 72: {
 73:   .owner = THIS_MODULE,
 74:   .open = led_open,
 75:   .unlocked_ioctl = led_ioctl,
 76:   .compat_ioctl = led_ioctl,
 77:   .release = led_close,
 78: };
 79:  
 80: static int __led_setup_dev(struct led_demo_dev * dev)
 81: {
 82:   int err = -1;
 83:  
 84:   dev_t devno = MKDEV(led_demo_major, led_demo_minor);
 85:  
 86:   memset(dev, 0, sizeof(struct led_demo_dev));
 87:  
 88:   cdev_init(&(dev->dev), &led_fops);
 89:  
 90:   dev->dev.owner = THIS_MODULE;
 91:  
 92:   err = cdev_add(&(dev->dev), devno, number_of_dev);
 93:   if(err < 0)
 94:   {
 95:     return err;
 96:   }
 97:   
 98:   return 0;
 99: }
 100:  
 101: static int led_demo_init(void)
 102: {
 103:   int err = -1;
 104:   dev_t dev;
 105:   struct device *temp = NULL;
 106:  
 107:   printk(KERN_ALERT"Initializing led demo device.\n");
 108:  
 109:   err = alloc_chrdev_region(&dev, 0, number_of_dev, LED_DEMO_DEVICE_NODE_NAME);
 110:   if(err < 0)
 111:   {
 112:     printk(KERN_ALERT"fail to alloc char dev region.\n");
 113:     goto fail;
 114:   }
 115:  
 116:   led_demo_major = MAJOR(dev);
 117:   led_demo_minor = MINOR(dev);
 118:  
 119:   led_dev = kmalloc(sizeof(struct led_demo_dev), GFP_KERNEL);
 120:   if(!led_dev)
 121:   {
 122:     err = -ENOMEM;
 123:     printk(KERN_ALERT"Failed to alloc led device.\n");
 124:     goto unregister;
 125:   }
 126:  
 127:   err = __led_setup_dev(led_dev);
 128:   if (err < 0)
 129:   {
 130:     printk(KERN_ALERT"Failed to setup led device.\n");
 131:     goto clean_up;
 132:   }
 133:  
 134:   GPM4CON = (unsigned int *)ioremap(EXYNOS4412_GPM4CON, 4);
 135:   if(!GPM4CON)
 136:   {
 137:     err = -ENOMEM;
 138:     goto destroy_cdev;
 139:   }
 140:   
 141:   GPM4DAT = (unsigned int *)ioremap(EXYNOS4412_GPM4DAT, 4);
 142:   if(!GPM4DAT)
 143:   {
 144:     err = -ENOMEM;
 145:     goto unmap1;
 146:   }
 147:  
 148:   writel((readl(GPM4CON) & ~0xffff) | 0x1111, GPM4CON);
 149:   writel(readl(GPM4DAT)| 0xf, GPM4DAT);
 150:  
 151:   led_demo_class = class_create(THIS_MODULE, LED_DEMO_DEVICE_CLASS_NAME);
 152:   if(IS_ERR(led_demo_class))
 153:   {
 154:     err = PTR_ERR(led_demo_class);
 155:     printk(KERN_ALERT"Failed to create led demo class.\n");
 156:     goto unmap2;
 157:   }
 158:  
 159:   temp = device_create(led_demo_class, NULL, dev, NULL, "%s", LED_DEMO_DEVICE_FILE_NAME);
 160:   if(IS_ERR(temp))
 161:   {
 162:     err = PTR_ERR(temp);
 163:     printk(KERN_ALERT"Failed to create led demo device.\n");
 164:     goto destroy_class;
 165:   }
 166:  
 167:   dev_set_drvdata(temp, (void *)led_dev);
 168:  
 169:   printk(KERN_ALERT"Succeed to initialize led demo device.\n");
 170:     
 171:   return 0;
 172:  
 173: destroy_class:
 174:   class_destroy(led_demo_class);
 175:   
 176: unmap2:
 177:   iounmap(GPM4DAT);
 178:   
 179: unmap1:
 180:   iounmap(GPM4CON);
 181:   
 182: destroy_cdev:
 183:   cdev_del(&(led_dev->dev));
 184:  
 185: clean_up:
 186:   kfree(led_dev);
 187:   
 188: unregister:
 189:   unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
 190:   
 191: fail:
 192:  
 193:   return err;
 194: }
 195:  
 196: static void led_demo_exit(void)
 197: {
 198:   if(led_demo_class)
 199:   {
 200:     device_destroy(led_demo_class, MKDEV(led_demo_major, led_demo_minor));
 201:     class_destroy(led_demo_class);
 202:   }
 203:   
 204:   iounmap(GPM4DAT);
 205:   iounmap(GPM4CON);
 206:  
 207:   if(led_dev)
 208:   {
 209:     cdev_del(&(led_dev->dev));
 210:     kfree(led_dev);
 211:   }
 212:  
 213:   unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev);
 214: }
 215:  
 216:  
 217:  
 218: module_init(led_demo_init);
 219: module_exit(led_demo_exit);
 220:  

 

编写完成后,在内核源码的顶层目录执行make zImage –jN,然后就会在arch/arm/boot/生成zImage文件,利用友善之臂提供的Minitools将zImage烧写到板子上。具体步骤,参考友善之臂提供的PDF文档:《Tiny4412用户手册》

回到顶部

二、编写代码测试驱动程序

在android-4.2.2_r1源码顶层目录下

  1: external/led_demo/
  2: ├── Android.mk
  3: ├── led_demo.c
  4: └── led_demo.h

即,在external/下创建led_demo目录,并在其中创建Android.mk、led_demo.c以及led_demo.h文件.

Android.mk:

  1: LOCAL_PATH:= $(call my-dir)
  2: include $(CLEAR_VARS)
  3: LOCAL_MODULE_TAGS := optional
  4: LOCAL_SRC_FILES := $(call all-subdir-c-files)
  5: LOCAL_MODULE := led_demo_test
  6: include $(BUILD_EXECUTABLE)
  7:  

led_demo.h:

  1: #ifndef __LED_DEMO_H__
  2: #define __LED_DEMO_H__
  3:  
  4: #define LED_ON  _IOW('L', 0, int)
  5: #define LED_OFF  _IOW('L', 1, int)
  6:  
  7: #endif

led_demo.c:

  1: #include <stdio.h>
  2: #include <sys/types.h>
  3: #include <sys/stat.h>
  4: #include <fcntl.h>
  5: #include <stdlib.h>
  6: #include <sys/ioctl.h>
  7:  
  8: #include "led_demo.h"
  9:  
 10: int main(int argc, const char *argv[])
 11: {
 12:   int fd;
 13:   int i;
 14:  
 15:   fd = open("/dev/led_demo", O_RDWR);
 16:   if (fd < 0)
 17:   {
 18:     perror("failed to open.\n");  
 19:     exit(-1);
 20:   }          
 21:  
 22:   while(1)
 23:   {
 24:     for(i=0; i<4; i++)
 25:     {
 26:       ioctl(fd, LED_OFF, i+1);
 27:       sleep(1);
 28:       ioctl(fd, LED_ON, i+1);
 29:       sleep(1);
 30:       ioctl(fd, LED_OFF, i+1);
 31:       sleep(1);
 32:     }
 33:   }
 34:  
 35:   close(fd);
 36:  
 37:   return 0;
 38: }

编写完成后,在android-4.2.2_r1源码顶层目录下执行:

  1:  mmm ./external/led_demo/
  2:  
  3:  ./gen-img.sh

然后将顶层目录下新生成的system.img利用友善之臂提供的Minitools烧写到板子上。

烧写完成后,重启板子。

使用串口终端登陆板子,使用su命令进入root用户模式,然后进入/system/bin目录下,执行./led_demo_test,观察现象,可以看到,TINY4412的核心板上的四个LED灯循环亮灭。也可以使用wind7下的控制终端,用adb shell登陆板子,进行测试。

回到顶部

三、编写HAL代码

在hardware/libhardware/include/hardware/下创建文件led_demo_hal.h

在hardware/libhardware/modules/下创建目录led_demo_hal,然后进入led_demo_hal,创建两个文件,分别是Android.mk和

led_demo_hal.cpp。

下面是文件内容:

hardware/libhardware/include/hardware/led_demo_hal.h

  1: #ifndef ANDROID_LED_DEMO_HAL_H
  2: #define ANDROID_LED_DEMO_HAL_H
  3:  
  4: #include <hardware/hardware.h>
  5:  
  6: __BEGIN_DECLS
  7:  
  8: #define LED_DEMO_HARDWARE_MODULE_ID  "led_demo_hal" //模块ID 需要与下面的Android.mk中的LOCAL_MODULE 匹配,否则无法加载该HAL模块
  9: #define LED_DEMO_HARDWARE_DEVICE_ID  "led_demo"   // 设备ID  
 10:  
 11:  
 12: struct led_demo_module_t
 13: {
 14:     struct hw_module_t common;
 15: };
 16:  
 17: struct led_demo_device_t
 18: {
 19:     struct hw_device_t common;
 20:     int fd;
 21:     int (*set_on)(struct led_demo_device_t *dev, int val); //用于控制LED,点亮第val个LED灯
 22:     int (*set_off)(struct led_demo_device_t *dev, int val); //熄灭第val个LED灯
 23: };
 24:  
 25: __END_DECLS
 26:  
 27:  
 28: #endif

 

hardware/libhardware/modules/led_demo_hal/led_demo_hal.cpp

  1: #define LOG_TAG "LED_DEMO_HALSTUB"  //将来可以用DDMS的LogCat工具进行调试,便于查看打印信息
  2:  
  3: #include <hardware/hardware.h>
  4: #include <hardware/led_demo_hal.h>
  5:  
  6: #include <fcntl.h>
  7: #include <errno.h>
  8:  
  9: #include <utils/Log.h>
 10: #include <cutils/atomic.h>
 11:  
 12:  
 13: #define DEVICE_NAME  "/dev/led_demo"  //设备结点,有Linux驱动程序自动创建
 14: #define MODULE_NAME  "led_demo"
 15: #define MODULE_AUTHOR "pengdonglin137@163.com"
 16:  
 17: #define LED_ON 0x40044c00   //点灯的命令,其实就是_IOW('L', 0, int)的值,_IOW在编译时无法识别,待以后解决
 18: #define LED_OFF 0x40044c01   //灭灯命令,其实就是_IOW('L', 1, int)的值,可以在上面的led_demo.c中加打印,看一下这个值是多少
 19:  
 20:  
 21: static int led_demo_open(const struct hw_module_t* module, const char* id,
 22:     struct hw_device_t** device);
 23:  
 24: static int led_demo_close(struct hw_device_t* device);
 25:  
 26: static int led_demo_set_on(struct led_demo_device_t *dev, int val);
 27:  
 28: static int led_demo_set_off(struct led_demo_device_t *dev, int val);
 29:  
 30:  
 31: static hw_module_methods_t led_demo_module_methods =
 32: {
 33:   open:led_demo_open,
 34: };
 35:  
 36: struct led_demo_module_t HAL_MODULE_INFO_SYM = 
 37: {
 38:   common:{
 39:     tag:HARDWARE_MODULE_TAG,
 40:     version_major:1,
 41:     version_minor:0,
 42:     id:LED_DEMO_HARDWARE_MODULE_ID,
 43:     name:MODULE_NAME,
 44:     author:MODULE_AUTHOR,
 45:     methods:&led_demo_module_methods,
 46:   }
 47: };
 48:  
 49: static int led_demo_open(const struct hw_module_t* module, const char* id,
 50:     struct hw_device_t** device)
 51: {
 52:   if(!strcmp(id, LED_DEMO_HARDWARE_DEVICE_ID))
 53:   {
 54:     struct led_demo_device_t *dev;
 55:  
 56:     dev = (struct led_demo_device_t *)malloc(sizeof(struct led_demo_device_t));
 57:     if(!dev)
 58:     {
 59:       ALOGE("Failed to alloc space for struct led_demo_device_t.");
 60:       return -EFAULT;
 61:     }
 62:  
 63:     memset(dev, 0, sizeof(struct led_demo_device_t));
 64:  
 65:     dev->common.tag = 
HARDWARE_DEVICE_TAG
;
 66:     dev->common.version = 0;
 67:     dev->common.module = (struct hw_module_t *)module;
 68:     dev->common.close = led_demo_close;
 69:     dev->set_on = led_demo_set_on;
 70:     dev->set_off = led_demo_set_off;
 71:  
 72:     if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
 73:     {
 74:       ALOGE("Failed to open device %s ---- %s\n.", DEVICE_NAME, strerror(errno));
 75:       free(dev);
 76:       return -EFAULT;
 77:     }
 78:  
 79:     *device = &(dev->common);
 80:  
 81:     ALOGE("Open device file %s successfully.", DEVICE_NAME);
 82:  
 83:   }
 84:  
 85:   return -EFAULT;
 86: }
 87:  
 88: static int led_demo_close(struct hw_device_t* device)
 89: {
 90:   struct led_demo_device_t *led_device = (struct led_demo_device_t *)device;
 91:   if(led_device)
 92:   {
 93:     close(led_device->fd);
 94:     free(led_device);
 95:   }
 96:  
 97:   return 0;
 98: }
 99:  
 100: static int led_demo_set_on(struct led_demo_device_t *dev, int val)
 101: {
 102:   if(!dev)
 103:   {
 104:     ALOGE("Null dev pointer.");
 105:     return -EFAULT;
 106:   }
 107:   
 108:   if(ioctl(dev->fd, LED_ON, val) < 0)
 109:   {
 110:     ALOGE("ioctl error --- %s.", strerror(errno));
 111:     return -EFAULT;
 112:   }
 113:  
 114:   return 0;
 115:   
 116: }
 117:  
 118: static int led_demo_set_off(struct led_demo_device_t *dev, int val)
 119: {
 120:   if(!dev)
 121:   {
 122:     ALOGE("Null dev pointer.");
 123:     return -EFAULT;
 124:   }
 125:   
 126:   if(ioctl(dev->fd, LED_OFF, val) < 0)
 127:   {
 128:     ALOGE("ioctl error --- %s.", strerror(errno));
 129:     return -EFAULT;
 130:   }
 131:  
 132:   return 0;
 133:   
 134: }
 135:  

 

hardware/libhardware/modules/led_demo_hal/Android.mk

  1: LOCAL_PATH := $(call my-dir)
  2: include $(CLEAR_VARS)
  3: LOCAL_MODULE_TAGS := optional
  4: LOCAL_PRELINK_MODULE := false
  5: LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
  6: LOCAL_SHARED_LIBRARIES := liblog
  7: LOCAL_SRC_FILES := led_demo_hal.cpp
  8: LOCAL_MODULE := led_demo_hal.default
  9: include $(BUILD_SHARED_LIBRARY)

 

编写完成后,在Android源码的顶层目录执行:

mmm ./hardware/libhardware/modules/led_demo_hal/

最终out/target/product/tiny4412/system/lib/hw/目录下得到一个led_demo_hal.default.so文件。

下面处理一下硬件设备访问权限问题

在硬件抽象层模块中,我们是调用open函数来打开对应的设备文件的,在默认情况下,只有root用户才有权限访问系统的设备文件。但是一般的应用程序是没有root用户权限的。

解决办法,赋予root之外的其他用户访问设别文件/dev/led_demo的权限。做法如下:

在Android源码顶层目录下,修改system/core/rootdir/ueventd.rc,添加如下内容:

/dev/led_demo       0666  root    root

修改了ueventd.rc文件后,需要重新编译Android源代码工程,编译时,文件system/core/rootdir/ueventd.rc会拷贝到out/target/product/tiny4412/root/下,并且最终打包在ramdisk.img中。对于友善之臂,执行完make -jN后,还需要执行./gen-img.sh脚本,然后在Android源码顶层目录中会生成ramdisk-u.img文件,利用MiniTools将其烧写到板子上。

回到顶部

四、编写Framework代码

  • 定义硬件访问服务接口

在frameworks/base/core/java/android/os/创建文件ILed_demo_service.aidl,内容如下:

  1: package android.os;
  2:  
  3: interface ILed_demo_service
  4: {
  5:   void led_set_ON(int val);
  6:   void led_set_OFF(int val);
  7: }

然后,修改frameworks/base/Android.mk

  1: LOCAL_SRC_FILES += \
  2:   ......
  3:   core/java/android/os/IVibratorService.aidl \
  4:   core/java/android/os/ILed_demo_service.aidl \

最后,在Android源码顶层目录下执行

mmm ./frameworks/base/

编译后得到的framework.jar文件就包含了ILed_demo_service接口。

  • 实现硬件访问服务

在frameworks/base/services/java/com/android/server/创建文件Led_demo_Service.java,内容如下:

  1: package com.android.server;
  2: import android.content.Context;
  3: import android.os.ILed_demo_service;
  4: import android.util.Slog;
  5:  
  6:  
  7: public class Led_demo_Service extends ILed_demo_service.Stub
  8: {
  9:     private static final String TAG = "Led_demo_Service"; //方便DDMS提供的LogCat工具看打印信息
 10:  
 11:     private int mPtr = 0;
 12:  
 13:     Led_demo_Service()
 14:     {
 15:         mPtr = init_native(); //硬件访问服务Led_demo_Service在启动时,会通过JNI方法init_native
 16:  
 17:         if(mPtr == 0)
 18:         {
 19:             Slog.e(TAG, "Failed to initialize Led demo Service.");
 20:         }
 21:     }
 22:  
 23:     public void led_set_ON(int val)
 24:     {
 25:         if(mPtr == 0)
 26:         {
 27:             Slog.e(TAG, "Led demo Service is not initialized.");
 28:             return;
 29:         }
 30:  
 31:         set_ON_native(mPtr, val);
 32:     }
 33:  
 34:     public void led_set_OFF(int val)
 35:     {
 36:         if(mPtr == 0)
 37:         {
 38:             Slog.e(TAG, "Led demo Service is not initialized.");
 39:             return;
 40:         }
 41:  
 42:         set_OFF_native(mPtr, val);
 43:     }
 44:  
 45:  
 46:     private static native int init_native();
 47:     private static native void set_OFF_native(int mPtr, int val);
 48:     private static native void set_ON_native(int mPtr, int val);
 49:  
 50:  
 51: };

编写完成后,在Android源码顶层目录下执行:

mmm ./frameworks/base/services/java/

编译后得到的services.jar文件就包含有Led_demo_Service类。

 

回到顶部

五、编写JNI代码

在frameworks/base/services/jni/下创建文件com_android_server_led_demo_service.cpp,内容如下:

  1: #define LOG_TAG "LED_DEMO_Service_JNI"  //方便LogCat调试工具查看打印信息
  2:  
  3: #include "jni.h"
  4: #include "JNIHelp.h"
  5: #include "android_runtime/AndroidRuntime.h"
  6:  
  7: #include <utils/misc.h>
  8: #include <utils/Log.h>
  9: #include <hardware/hardware.h>
 10: #include <hardware/led_demo_hal.h>
 11:  
 12: #include <stdio.h>
 13:  
 14:  
 15: namespace android
 16: {
 17:  
 18:   static void led_demo_setOFF(JNIEnv *env, jobject clazz, jint ptr, jint value)
 19:   {
 20:     led_demo_device_t *device = (led_demo_device_t *)ptr;
 21:     if(!device)
 22:     {
 23:       ALOGE("Device led demo is not open.");
 24:       return ;
 25:     }
 26:  
 27:     int val = value;
 28:  
 29:     ALOGI("Set value %d to device led demo.", val);
 30:  
 31:     device->set_off(device, value);
 32:   }
 33:  
 34:   static void led_demo_setON(JNIEnv *env, jobject clazz, jint ptr, jint value)
 35:   {
 36:     led_demo_device_t *device = (led_demo_device_t *)ptr;
 37:     if(!device)
 38:     {
 39:       ALOGE("Device led demo is not open.");
 40:       return ;
 41:     }
 42:  
 43:     int val = value;
 44:  
 45:     ALOGI("Set value %d to device led demo.", val);
 46:  
 47:     device->set_on(device, value);
 48:   }
 49:   
 50:  
 51:   static inline int led_demo_device_open(const hw_module_t *module, struct led_demo_device_t **device)
 52:   {
 53:     return module->methods->open(module, LED_DEMO_HARDWARE_DEVICE_ID, (struct hw_device_t **)device);  
 54:   }
 55:  
 56:  
 57:  
 58:   static jint led_demo_init(JNIEnv *env, jclass clazz)
 59:   {
 60:     struct led_demo_module_t *module;
 61:     struct led_demo_device_t *device;
 62:  
 63:  
 64:     ALOGI("Initializing HAL stub led ......");
 65:  
 66:     if(hw_get_module(
LED_DEMO_HARDWARE_MODULE_ID
, (const struct hw_module_t **)&module) == 0)
 67:     {
 68:       ALOGE("Device led demo found.");
 69:  
 70:       if(led_demo_device_open(&(module->common), &device))
 71:       {
 72:         ALOGI("Device led demo is open.");
 73:         return (jint)device;
 74:       }
 75:  
 76:       ALOGE("Failed to open device led.");
 77:  
 78:       return 0;
 79:     }
 80:  
 81:     ALOGE("Failed to get HAL stub led demo.");
 82:     return 0;
 83:   }
 84:  
 85:   static const JNINativeMethod method_table[] =
 86:   {
 87:     {"init_native", "()I", (void *)led_demo_init},
 88:     {"set_OFF_native", "(II)V", (void *)led_demo_setOFF},
 89:     {"set_ON_native", "(II)V", (void *)led_demo_setON},
 90:   };
 91:  
 92:   int register_android_server_led_demo_service(JNIEnv *env)
 93:   {
 94:     return jniRegisterNativeMethods(env, "com/android/server/Led_demo_Service", 
 95:       method_table, NELEM(method_table));
 96:   }
 97:  
 98: };
 99:  
 100:  

 

修改frameworks/base/services/jni/onload.cpp文件:

  1: namespace android {
  2: ......
  3: int register_android_server_led_demo_service(JNIEnv *env);
  4: };
  5:  
  6: extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
  7: {
  8:   ......
  9:   register_android_server_led_demo_service(env);
 10:  
 11:   return JNI_VERSION_1_4;
 12: }

 

修改frameworks/base/services/jni/Android.mk文件,内容如下:

  1: LOCAL_SRC_FILES:= \
  2:   ......
  3:   com_android_server_led_demo_service.cpp \
  4:   onload.cpp

最后,在Android源码顶层目录下执行:

mmm ./frameworks/base/services/jni/
  • 启动硬件服务

修改frameworks/base/services/java/com/android/server/SystemServer.java文件

  1: // Bring up services needed for UI.
  2: if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
  3: ......
  4: try{
  5:   Slog.i(TAG, "Led demo Service");
  6:   ServiceManager.addService("led_demo", new Led_demo_Service()); //这里的名字要跟App中getService时传入的参数相同
  7: } catch (Throwable e) {
  8:   Slog.e(TAG, "Failed to start Led demo Service", e);
  9: }
 10:  
 11: }

 

编写完成后,在Android源码顶层目录下执行:

mmm ./frameworks/base/services/java/ 
回到顶部

六、编写App

这个app是在Win7下用eclipse开发的,如下图:

image

 

上面的错误是因为Win7下的SDK开发包中并没有我们编写的ILed_demo_service,这个不要紧。导出方法:在工程Tiny4412_led_demo上右键单击,点击Export,选择General----> File System ,选择导出路径,最后点击Finish。将导出的工程Tiny4412_led_demo拷贝到packages/experimental/目录下,然后进入packages/experimental/Tiny4412_led_demo,在其中创建一个Android.mk文件:

  1: LOCAL_PATH:= $(call my-dir)
  2: include $(CLEAR_VARS)
  3:  
  4: LOCAL_MODULE_TAGS := optional
  5:  
  6: # Only compile source java files in this apk.
  7: LOCAL_SRC_FILES := $(call all-java-files-under, src)
  8:  
  9: LOCAL_PACKAGE_NAME := Led_demo
 10:  
 11: include $(BUILD_PACKAGE)

下面是最终的效果图:

image

 

完成操作后,在Android源码顶层目录下执行

mmm ./packages/experimental/Tiny4412_led_demo/

然后再执行

./gen-img.sh

将生成的system.img利用MiniTools提供的烧写工具烧写到板子上。

 

最后,附上源代码:

 

http://pan.baidu.com/s/1ntwTz1B

完!!

 

原文:http://www.cnblogs.com/pengdonglin137/p/3857724.html