记得实习的时候,带我的那个师父对我说,搞这一块,不要学得太细,主要需要熟悉linux、android相关的框架。
在实习期,做了第一个项目,其实在这个中需到了很多东西。做一个androd的产品开发,说白了,就是用户能够通过上层应用程序来控制底层的硬件。
从底层驱动层来看,这一部分应该是产品开发的基石。它主要实现,用户对于该硬件设备的需求。如最简单的LED灯,上层应用就需要能够控制LED的亮、灭。底层驱动的代码主要是C,处于内核层,我们有静态加载驱动和动态加载驱动的两种方式。(Makefile arm-none-linux-gnueabi-gcc)
静态加载驱动,就是在编写内核过程中,把该驱动编写到kernel中,无需手动加载;动态加载驱动,编写以ko的形式,需要动态的加载,有一些常用的命令:lsmod insmod rmsmod,在开发的初期,建议使用动态加载的方式。
驱动层,就是去操控硬件。所以,我们需要对硬件知识需要一定的了解。对于最简单的LED,实现的应用为:控制亮、灭,那么底层驱动只需要控制与LED相连的CPU端引脚电平即可,对于此类功能简单的设备,可以使用文件节点(sys)的方法。
如:
static ssize_t red(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
gpio_set_value(SCAN_RED, ((buf[0]=='1')?1:0));
printk("sacn--%s,state=%d\n",__FUNCTION__,((buf[0]=='1')?1:0));
return count;
}
static DEVICE_ATTR(red, S_IRWXUGO, 0, red);static struct attribute *scan_attr[] = {
&dev_attr_red.attr,
NULL
};
而对于相对复杂的的产品,如摄像头、LCD、TP这类,需要相关的子系统框架,或者搭建平台设备驱动模型。在自主的产品开发过程中,采用平台设备驱动模型较多。在平台设备驱动中,对上层提供控制接口,主要是通过open、close、read、write、ioctl的方法,对于下层硬件层,主要根据具体的设备,通过与设备相连的总线协议,去读写设备中的寄存器,从而控制硬件。所以,这里我们还需要有相关总线协议的驱动。如:摄像头一般通过I2C,BT通过串口、wifi通过SDIO。
对于驱动层的编写,有一些小技巧,一方面,使用动态加载驱动的方式,另一方面,编写一个测试驱动的可执行文件,通过查看在设备终端执行,查看相关的log,可以比较方法的测试,底层驱动是否可以控制硬件设备。
从android framework层来看,一般分为C的jni层、java层。我们应该知道,java不能直接调用C所编写的方法,而需要通过jni进行转换。一般framework层也有不同的机制,其一:把jni层编写动态共享库so,jar;其二:把jni层加入到android 源码下的farmework/base/core/jni,jar代码加到frameworks/base/core/java/android/的native方法,中间在封装一个serve或者manager。这两种方法的实现原理都是一样的。
从jni层来看,这一部分主要使用c、c++,但需要了解jni的机制、java和C的数据类型的差别等。jni层对代码的健壮要求比较高,所以写程序的时候,对于指针、数组一定要小心。
jni层,就是把驱动提供的方法通过jni转换,提供给java用,从而用户通过编写应用程序,调用方法,从而控制硬件。这里,主要对于平台设备模型,主要是调用open、read、write、ioctl、close这些方法,提供用户对硬件产品的需求的方法。对于文件节点的方式,只需要对文件节点传值。jni层的代码和Android.mk通过android mm或者NDK生成so。
从jar包或者native、serve来看,这主要是对jni提供的方法进行再次封装,并对类、方法名进行规范。这里注意jar的路径、包名、so的名称的一致性与规范性。
从应用层来看,这里主要是调用jar包中的方法,实现用户对该硬件产品的需求功能。主要是针对硬件产品的功能,做出相对应的应用。
最后,整体上可以看出,硬件、驱动、jni接口、java中native(serve manager)、app。