参考资料:
《Andriod系统源代码情景分析》
《嵌入式Linux系统开发完全手册_基于4412_上册》
作者:彭东林
平台介绍:
主机: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灯的位置:
可以知道,LED是低电平亮,高电平灭。
看一下,接到了Exynos4412的哪些引脚上了:
可以看到:
LED1 --------- GPM4_0
LED2 --------- GPM4_1
LED3 --------- GPM4_2
LED4 --------- GPM4_3
看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:
图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.
在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。
以GPM4_0引脚为例:
为了控制灯,[3:0]应设置为0x01,即输出模式
向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选择为*,然后保存配置退出。
注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了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. ");
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. ");
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. ");
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. ");
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. ");
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. ");
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. ");
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. ");
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. ");
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 .", 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开发的,如下图:
上面的错误是因为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)
下面是最终的效果图:
完成操作后,在Android源码顶层目录下执行
mmm ./packages/experimental/Tiny4412_led_demo/
然后再执行
./gen-img.sh
将生成的system.img利用MiniTools提供的烧写工具烧写到板子上。
最后,附上源代码:
http://pan.baidu.com/s/1ntwTz1B
完!!