android驱动_android驱动开发 - CSDN
  • Android驱动深度开发视频教程

    万人学习 2018-11-30 10:35:12
    也许是中国第一个讲解android驱动的课程,涵盖: bootloader,内核移植,INIT进程,框架(BINDER IPC,SERVICE FRAMEWORK Activity Manager Serive,JNI,HAL等),binder驱动,logger,Ashmen,电源管理,常用驱动(如灯光...
  • RK3288 android驱动入门

    2019-08-26 10:20:58
    本次课程包含 前面 RK3399 的内容,使用 RK3288 和 RK3399 多块开发板,带领大家把开发板上面的硬件模块功能都实现了,两个课程,大家看需求选其一即可,个人认为,RK平台功能快速实现有这些课程即可!
  • 1、基于RK3288平台,基于Android7.1,kernel4.4的驱动移植、调试和开发,驱动框架分析,跟代码等; 2、讲解RK平台的常用外设模块驱动(例如LCD,TP,GPIO,wifi+BT,IR,camera和key等)的调试流程以及一些...
  • 安卓编译与开发、Linux内核及驱动

    千人学习 2019-07-01 10:39:08
    安卓编译与开发、Linux内核及驱动视频教程,该课程内容包括一、源码编译:1、常见的ROM种类、谷歌的ROM、第三方的ROM2、区别3、RockChip的ROM、4、编译环境配置、源码下载、编译命令;二、源码开发:源码结构分析、...
  • 于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,...其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。
  • android驱动学习(1)

    2018-09-16 23:06:58
    linux系统:  uboot -----> linux内核 ------> 根文件系统: bin sbin sys dev etc lib等 二,根文件系统的制作 1,根文件系统的结构    内核的启动:  kernel_init线程: ... prepare_namespa...

    linux系统:
                uboot  -----> linux内核 ------> 根文件系统: bin sbin sys dev etc lib等
    二,根文件系统的制作
    1,根文件系统的结构
        
            内核的启动:
                kernel_init线程:
                    -----> prepare_namespace()
                    -----> init_post()
                                                /
                                                |
            ---------------------------------------------------------------------------------------------------------------------
            |             |           |                |                         |             |        |           |        |        |        |       |     |
            bin     sbin     etc            lib                       sys       dev   proc    root home usr   mnt tmp opt
           --------------         |               |                        ----------------------
                |        系统配置/脚本  交叉编译器中获取          |
              busybox                                                     虚拟文件系统:在内存中,有系统自动创建里面的文件       

    2,根文件系统的:
        1》创建相关目录
              mkdir myrootfs
              cd myrootfs
              mkdir bin sbin lib etc sys dev proc root home opt usr mnt tmp

    2》通过busybox生成bin和sbin中的命令

     拷贝解压配置编译busybox
                ① 将busybox拷贝到/home/farsight/s5pv210/filesystem,并解压
                        farsight@ubuntu:~/s5pv210/filesystem$ tar -xvf busybox-1.17.3.tar.bz2
                ② 配置交叉编译器
                    164 CROSS_COMPILE ?= arm-none-linux-gnueabi-
                    190 ARCH ?= arm
                ③ make menuconfig
                         Busybox Settings  --->
                                 Build Options  --->
                                    [*] Build BusyBox as a static binary (no shared libs)
                                 Installation Options  --->
                                    [*] Don't use /usr
                                    (./_install) BusyBox installation prefix
              ④ 编译,并安装
                    make -j2
                    make install
              ⑤ 将_install中的内容拷贝到 myrootfs中
                    farsight@ubuntu:~/s5pv210/filesystem/busybox-1.17.3/_install$ cp -raf * ../../myrootfs/ 拷贝解压配置编译busybox
                ① 将busybox拷贝到/home/farsight/s5pv210/filesystem,并解压
                        farsight@ubuntu:~/s5pv210/filesystem$ tar -xvf busybox-1.17.3.tar.bz2
                ② 配置交叉编译器
                    164 CROSS_COMPILE ?= arm-none-linux-gnueabi-
                    190 ARCH ?= arm
                ③ make menuconfig
                         Busybox Settings  --->
                                 Build Options  --->
                                    [*] Build BusyBox as a static binary (no shared libs)
                                 Installation Options  --->
                                    [*] Don't use /usr
                                    (./_install) BusyBox installation prefix
              ④ 编译,并安装
                    make -j2
                    make install
              ⑤ 将_install中的内容拷贝到 myrootfs中
                    farsight@ubuntu:~/s5pv210/filesystem/busybox-1.17.3/_install$ cp -raf * ../../myrootfs/

    3》拷贝交叉编译器中的库到  myrootfs/lib
         1) 拷贝交叉编译器中的库
              farsight@ubuntu:/usr/local/arm/toolchain-4.5.1-farsight/arm-none-linux-gnueabi/lib$ cp -raf * /home/farsight/s5pv210/filesystem/myrootfs/lib
         2) 对拷贝过来的lib中的库文件瘦身
              farsight@ubuntu:~/s5pv210/filesystem/myrootfs$ du -sh lib
              18M     lib
              
              //因为瘦身过程会修改库文件,必须要有可写权限,所以需要修改权限
              farsight@ubuntu:~/s5pv210/filesystem/myrootfs$ chmod a+w lib/*                */
              //瘦身:arm-none-linux-gnueabi-strip
              farsight@ubuntu:~/s5pv210/filesystem/myrootfs$ arm-none-linux-gnueabi-strip lib/*                            */
              arm-none-linux-gnueabi-strip:lib/libgcc_s.so: File format not recognized
              arm-none-linux-gnueabi-strip:lib/libgomp.spec: File format not recognized
              arm-none-linux-gnueabi-strip:lib/libstdc++.so.6.0.14-gdb.py: File format not recognized
              farsight@ubuntu:~/s5pv210/filesystem/myrootfs$ du -sh lib
              5.2M    lib

     4》编写etc下的相关脚本文件 ---------------------- 参考busybox源码
            1) 在etc中创建inittab:
                    farsight@ubuntu:~/s5pv210/filesystem/myrootfs/etc$ touch inittab
            2)参考busybox源码 -----  /examples/inittab
                ::sysinit:/etc/init.d/rcS
                ::askfirst:-/bin/sh
                ::ctrlaltdel:/sbin/reboot
                ::shutdown:/sbin/swapoff -a
                ::shutdown:/bin/umount -a -r
                ::restart:/sbin/init

              格式说明:
                 <id>:<runlevels>:<action>:<process>
                    <action>:  sysinit ---- 系统初始化
                               respawn ---- 重启/复位
                               askfirst---- 启动时第一次询问:Please press Enter to activate this  console.
                               wait -------等待
                               once -------执行一次
                               restart ----每次重启时执行
                               ctrlaltdel--按下组合键时执行
                               shutdown ---关机时执行
            3) 创建 init.d/rcS 并设置权限    echo与后面必须要空格隔离
                #!/bin/sh

                echo "-------myrootfs start----------------------"     
                /bin/mount -a                //挂载/etc/fstab中指定的所有的文件系统
                /sbin/mdev -s                //创建设备节点和系统的相关信息
                echo "-------myrootfs end----------------------"
                
                注意:修改rcS的权限
                    farsight@ubuntu:~/s5pv210/filesystem/myrootfs/etc/init.d$ chmod a+x rcS
            4) 创建:etc/fstab
            
                    myproc            /proc           proc    defaults    0       0
                    mysys             /sys            sysfs    defaults    0       0
                    mydev             /dev            tmpfs    defaults    0       0
                    mytmp             /tmp             tmpfs    defaults    0       0
                以上步骤完成之后,就得到了一个最简单的根文件系统.
        5》补充:
            1) 注释掉:init.d/rcS 中的
                #/bin/mount -a
                重启开发板,发现在 dev/ sys/ proc/中什么都没有
                
                但是,在init.d/rcS添加:
                    /bin/mount -t proc  myproc /proc
                    /bin/mount -t sysfs  mysys /sys
                    /bin/mount -t tmpfs  mydev /dev
                    /bin/mount -t tmpfs  mytmp /tmp
                重启开发板,发现在 dev/ sys/ proc/中有相关的文件存在
                
            2)注释掉:init.d/rcS 中的
                #/sbin/mdev -s
                  在dev下不会创建内核中需要加载的驱动对应的设备节点
            3) 创建 : etc/profile
                #!/bin/sh
                export HOSTNAME=farsight
                export USER=root
                export HOME=root
                export PS1="[$USER@$HOSTNAME \W]\# "
                PATH=/bin:/sbin:/usr/bin:/usr/sbin
                LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
                export PATH  LD_LIBRARY_PATH
                
                重启开发板,发现命令提示符前面显示用户名和主机名

     三,制作可用于烧录的文件系统镜像
        1, nand flash的移植

    1》拷贝驱动源码文件到内核源码中:

                1) 将s3c_nand.c拷贝到:\\192.168.7.8\farsight\s5pv210\kernel\linux-3.0.8\drivers\mtd\nand
                2) 将regs-nand.h拷贝到:\\192.168.7.8\farsight\s5pv210\kernel\linux-3.0.8\arch\arm\mach-s5pv210\include\mach
               

     2》修改    drivers/mtd/nand/Kconfig
                    添加以下内容:    --------参考2410的配置
                    config MTD_NAND_S3C
                        tristate "NAND Flash support for Samsung S3C S5PV210 SoCs"
                        depends on ARCH_S5PV210
                        help
                          This enables the NAND flash controller on the S5PV210 SoCs

                          No board specific support is done by this driver, each board
                          must advertise a platform_device for the driver to attach.

                    config MTD_NAND_S3C_DEBUG
                        bool "Samsung S5PV210 NAND driver debug"
                        depends on MTD_NAND_S3C
                        help
                          Enable debugging of the S3C NAND driver

                    config MTD_NAND_S3C_HWECC
                        bool "Samsung S5PV210 NAND Hardware ECC"
                        depends on MTD_NAND_S3C
                        help
                          Enable the use of the controller's internal ECC generator when
                          using NAND. Early versions of the chips have had problems with
                          incorrect ECC generation, and if using these, the default of
                          software ECC is preferable.
            
     3》修改Makefile
                    21 obj-$(CONFIG_MTD_NAND_S3C)          += s3c_nand.o
     4》修改平台相关代码
                vim arch/arm/mach-s5pv210/mach-smdkv210.c
                1)包含一下头文件:
                    #include <linux/mtd/mtd.h>
                    #include <linux/mtd/nand.h>
                    #include <linux/mtd/nand_ecc.h>
                    #include <linux/mtd/partitions.h>
                    #include <plat/nand.h>
                2) 添加平台设备
                /* Nand Flash Support */
                    static struct mtd_partition s5pv210_nand_part[] = {
                          [0] ={
                                .name = "myuboot",
                                .offset = 0x0,
                                .size = SZ_1M,
                          },
                          [1] ={
                                .name = "kernel",
                                .offset = MTDPART_OFS_APPEND,
                                .size = SZ_1M * 4,
                          },
                          [2] ={
                                .name = "rootfs",
                                .offset = MTDPART_OFS_APPEND,
                                .size = SZ_1M * 16,
                          },
                          [3] ={
                                .name = "userdata",
                                .offset = MTDPART_OFS_APPEND,
                                .size = SZ_1M * 16,
                          },
                          [4] ={
                                .name = "usr spec",
                                .offset = MTDPART_OFS_APPEND,
                                .size = MTDPART_SIZ_FULL,
                          },
                    };
                    struct s3c_nand_mtd_info s5pv210_nand_mtd_part_info = {
                          .chip_nr = 1,
                          .mtd_part_nr = ARRAY_SIZE(s5pv210_nand_part),
                          .partition = s5pv210_nand_part,
                    };
                    static struct resource s5pv210_nand_resource[] = {
                          [0] = {
                                .start = 0xB0E00000,
                                .end = 0xB0E00000 + SZ_1M,
                                .flags = IORESOURCE_MEM,
                          }
                    };
                    struct platform_device s5pv210_device_nand = {
                          .name = "s5pv210-nand",
                          .id = -1,
                          .num_resources = ARRAY_SIZE(s5pv210_nand_resource),
                          .resource = s5pv210_nand_resource,        //nand控制寄存器的地址资源
                                .dev = {                  
                                        .platform_data = &s5pv210_nand_mtd_part_info,         // 特殊的平台数据,分区表
                                }
                    };

                3)添加平台设备列表
                    在smdkv210_device[]结构体数组中添加如下内容:

                        #if defined(CONFIG_MTD_NAND_S3C)
                                &s5pv210_device_nand,
                        #endif?

                    修改arch/arm/plat-samsung/include/plat/nand.h添加如下内容:
                    struct s3c_nand_mtd_info{
                          uint chip_nr;
                          uint mtd_part_nr;
                          struct mtd_partition *partition;
                    };

                    修改include/linux/mtd/partitions.h
                    添加
                    extern    int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
                    ?
                    修改arch/arm/mach-s5pv210/clock.c中结构体在最后添加如下代码(加粗部分)
                        static struct clk init_clocks_off[] = {
                        {
                                        。。。。。。
                                      .ctrlbit      = (1 << 0),
                              },{
                                    .name = "nandxl",
                                          .id = -1,
                                          .parent = &clk_hclk_psys.clk,
                                          .enable = s5pv210_clk_ip1_ctrl,
                                          .ctrlbit = (1 << 24),
                              },
                        };
                    
    5》配置内核
                
                
                 Device Drivers  --->
                        <*> Memory Technology Device (MTD) support  --->  
                            <*>   Direct char device access to MTD devices
                            -*-   Common interface to block layer for MTD 'translation layers'
                             <*>   Caching block device access to MTD devices
                            
                             <*>   NAND Device Support  --->
                                    <*>   NAND Flash support for Samsung S3C S5PV210 SoCs
                                     [*]     Samsung S5PV210 NAND Hardware ECC  
                File systems  --->
                        [*] Miscellaneous filesystems  --->
                                 <*>   Journalling Flash File System v2 (JFFS2) support
                                  <*>   Compressed ROM file system support (cramfs)
            6》重新编译内核,并拷贝到/tftpboot中
                    make -j2
                     cp arch/arm/boot/zImage /tftpboot/
            7》重启开发板,观察
                 S3C NAND Driver, (c) 2008 Samsung Electronics
                S3C NAND Driver is using hardware ECC.
                NAND device: Manufacturer ID: 0xec, Chip ID: 0xd3 (Samsung NAND 1GiB 3,3V 8-bit)
                Creating 5 MTD partitions on "s5pv210-nand":
                0x000000000000-0x000000100000 : "myuboot"
                0x000000100000-0x000000500000 : "kernel"
                0x000000500000-0x000001500000 : "rootfs"
                0x000001500000-0x000002500000 : "userdata"
                0x000002500000-0x000040000000 : "usr spec"
            查看分区信息:
                [root@farsight /]# cat proc/partitions
                major minor  #blocks  name

                  31        0       1024 mtdblock0
                  31        1       4096 mtdblock1
                  31        2      16384 mtdblock2
                  31        3      16384 mtdblock3
                  31        4    1010688 mtdblock4

    2,制作可烧录的文件系统镜像
            1》linux内核支持的文件系统镜像种类
                    cramfs    -------   只读压缩的文件系统镜像 ,适用于nand
                    jffs2     -------   可读写压缩的文件系统镜像
                    yaffs -----------   不压缩可读写的文件系统镜像,适用于nand
            2》制作cramfs文件系统镜像
                    farsight@ubuntu:/opt$ mkfs.cramfs myrootfs/ rootfs.cramfs
                将rootfs.cramfs拷贝到/tftpboot/
                    farsight@ubuntu:/opt$ cp rootfs.cramfs /tftpboot/
                重启开发板,在uboot中烧录文件系统镜像
                    FS210 # tftp 20008000 rootfs.cramfs
                    FS210 # nand erase 0x500000 0x1000000
                    FS210 # nand write 20008000 0x500000 0x1000000
                重新配置uboot参数
                        FS210 # set bootargs console=ttySAC0,115200 init=/linuxrc root=/dev/mtdblock2 rootfstype=cramfs ip=192.168.7.5
                        FS210 # sa
                测试:
                    重启开发板,进入系统后创建一个文件:
                        [root@farsight /]# touch 1.txt
                        touch: 1.txt: Read-only file system
            3》制作jffs2文件系统镜像
                安装mtd工具:
                    sudo apt-get install mtd-utils
                制作jffs2文件系统:
                    farsight@ubuntu:/opt$ mkfs.jffs2 -r myrootfs -o rootfs.jffs2 -e 0x20000 --pad=0x400000 -n
                        -e      nand块大小
                        -pad    rootfs.jffs2指定为多大,和分区大小一致 ------该选项可以不写,时可选的
                        -n       不打印不必要的调试信息
                将rootfs.jffs2拷贝到/tftpboot/
                    farsight@ubuntu:/opt$ cp rootfs.jffs2 /tftpboot/
                重启开发板,在uboot中烧录文件系统镜像
                    FS210 # tftp 20008000 rootfs.jffs2
                    FS210 # nand erase 0x500000 0x1000000
                    FS210 # nand write 20008000 0x500000 0x1000000
                重新配置uboot参数
                    FS210 # set bootargs console=ttySAC0,115200 init=/linuxrc root=1f02 rootfstype=jffs2 ip=192.168.7.5
                    FS210 # sa
                测试:
                    重启开发板,进入系统后创建一个文件:
                    [root@farsight /]# touch 1.txt
                    [root@farsight /]# ls
                    1.txt    dev      home     linuxrc  opt      root     sys      usr
                    bin      etc      lib      mnt      proc     sbin     tmp

                4》混合烧录
                1) 在 /myrootfs/etc/init.d/rcS中添加以下内容:
                        
                        echo "-------ready to mount /dev/mtdblock3 to /home  -------------"
                        /bin/mount -t jffs2 /dev/mtdblock3 /home
                2) 重新制作根文件系统镜像
                    生成: rootfs.cramfs
                            mkfs.cramfs myrootfs rootfs.cramfs
                    将rootfs.cramfs拷贝到/tftpboot中
                            cp rootfs.cramfs /tftpboot/
                    在uboot中烧录文件系统镜像
                            FS210 # tftp 20008000 rootfs.cramfs
                            FS210 # nand erase 0x500000 0x1000000
                            FS210 # nand write 20008000 0x500000 0x1000000
                3) 再制作一个空的文件系统,格式为jffs2
                         mkdir userdata
                         mkfs.jffs2 -r userdata -o userdata.jffs2 -e 0x20000 --pad=0x400000 -n
                         cp userdata.jffs2 /tftpboot/
                4) 将userdata.jffs2烧录到开发板的nand中
                            0x000000000000-0x000000100000 : "myuboot"
                            0x000000100000-0x000000500000 : "kernel"
                            0x000000500000-0x000001500000 : "rootfs"
                            0x000001500000-0x000002500000 : "userdata"
                            0x000002500000-0x000040000000 : "usr spec"
                            
                            FS210 # tftp 20008000 userdata.jffs2
                            FS210 # nand erase 0x1500000 0x1000000
                            FS210 # nand write 20008000 0x1500000 0x1000000
                重新配置uboot参数
                    FS210 # set bootargs console=ttySAC0,115200 init=/linuxrc root=/dev/mtdblock2 rootfstype=cramfs ip=192.168.7.5
                    FS210 # sa
         3,内核的烧录
                在uboot中:
                1》通过网络烧录内核镜像
                    FS210 # tftp 20008000 zImage
                    FS210 # nand erase 0x100000 0x400000
                    FS210 # nand write 20008000 0x100000 0x400000
                2》配置uboot参数:
                    FS210 # set bootcmd nand read 0x40008000 0x100000 0x400000 \; bootm 0x40008000
                    FS210 # sa

        

    3,烧录内核:
            FS210 # tftp 0x40008000 zImage
            FS210 # nand erase 0x100000  0x400000
            FS210 # nand write 0x40008000  0x100000  0x400000
        
            启动的时候去从nand中加载内核:
                FS210 # set bootcmd nand read 0x40008000 0x100000  0x400000 \; bootm 0x40008000
                
                android系统的结构:


       etc结构:


                
        根文件系统目录:


        
        镜像焼写:


        
       

    展开全文
  • Android系统移植:驱动

    万次阅读 多人点赞 2017-05-24 15:13:16
    【导语】在Android系统移植中,有很重要的一个部分工作,就是为新平台上的硬件设备移植驱动程序。因为Android系统是基于Linux kernel内核构建,所以这里说的移植驱动程序,其实就是基于Android系统平台开发适应移动...

    【导语】在Android系统移植中,有很重要的一个部分工作,就是为新平台上的硬件设备移植驱动程序。因为Android系统是基于Linux kernel内核构建,所以这里说的移植驱动程序,其实就是基于Android系统平台开发适应移动设备的Linux内核驱动程序。

    一. Android系统中Linux内核与设备驱动

    Android系统中使用了Linux内核作为自己的操作系统,除了linux的通用代码之外,主要还包含三个方面的东西:

    • 体系结构和处理器
      体系结构处理器和标准的设备驱动程序这两个方面是和硬件相关的,但是对于同一种硬件,在Android系统和标准的Linux系统中基本上是一样的。

    • Android专用的驱动程序
      Android的专用驱动程序,通常是和硬件无关的驱动程序,仅仅在Android系统中使用。

    • 标准的linux设备驱动程序

    Android系统中Linux内核与设备驱动的结构如下图示:

    这里写图片描述

    Android系统通常用于移动设备和其他的嵌入式设备,因此都基于ARM体系结构,在ARM体系结构具有多种处理器。因此,对于不同对的处理器,基于相同的外围设备,驱动程序也可能不一样。

    需要说明的是上图中的Goldfish:

    Android模拟器通过运行一个Goldfish的虚拟CPU ,Goldfish用来运行arm926t指令集(arm926t属于armv5构架),并且仿真了输入/输出,比如键盘输入和LCD 输出。这个模拟器其实是在qemu之上开发的,输入/输出是基于libSDL的。既然Goldfish是被模拟器运行的虚拟CPU,那么当Android在真实的硬件设备上运行时,我们就需要去掉它。

    二. Android系统上的设备驱动

    • 基本图形用户界面(GUI)部分:包括显示部分、用户输入部分和硬件相关的加速部分,还包括媒体编解码和OpenGL等。
    • 音视频输入输出部分:包括音频、视频输出和摄像头等。
    • 连接部分:包括无线局域网、蓝牙、GPS等。
    • 电话部分:包括通话、GSM等。
    • 附属部件:包括传感器、背光、振动器等。

    具体来说是有以下:

    • [x] Display显示部分:包括FrameBuffer驱动和Gralloc模块。
    • [x] Input用户输入部分:包括Event驱动和EventHub。
    • [x] Codec多媒体编解码:包括硬件Codec驱动和Codec插件,例如OpenMax。
    • [x] 3DAccelerator(3D加速器)部分:包括硬件OpenGL驱动和OpenGL插件。
    • [x] Audio音频部分:包括Audio驱动和Audio硬件抽象层。
    • [x] VideoOut视频输出部分:包括视频显示驱动和Overlay硬件抽象层。
    • [x] Camera摄像头部分:包括Camera驱动(通常是v4l2)和Camera硬件抽象层。
    • [x] Phone电话部分:包括Modem驱动程序和RIL库。
    • [x] GPS全球定位系统部分:包括GPS驱动(例如串口)和GPS硬件抽象层。
    • [x] Wi-Fi无线局域网部分:包括Wlan驱动和协议和Wi-Fi的适配层。
    • [x] BlueTooth蓝牙部分:包括BT驱动和协议及BT的适配层。
    • [x] Sensor传感器部分:包括Sensor驱动和Sensor硬件抽象层。
    • [x] Vibrator振动器部分:包括Vibrator驱动和Vibrator硬件抽象层。
    • [x] Light背光部分:包括Light驱动和Light硬件抽象层。
    • [x] Alarm警告器部分:包括Alarm驱动和RTC系统和用户空间调用。
    • [x] Battery电池部分:包括电池部分驱动和电池的硬件抽象层。

    在实际应用中,通过下面的图,感受下一个量产的平板中用到了哪些硬件,体会下其中涉及到的驱动:
    全志A33平板PCBA,如有侵权,请及时告知

    三.Android系统专用驱动

    看一下Google为基于Linux kernel而定制的Android系统专用驱动程序:

    (1)Android Binder

    Android Binder是基于OpenBinder框架的一个驱动,用于Android平台的进程间通信(InterProcess
    Communication,IPC)。原来的Linux系统上层应用的进程间通信主要是D-bus(Desktop bus),采用消息总线的方式来进行IPC。
    源代码位于drivers/staging/android/binder.c。

    (2)Android电源管理

    Android电源管理是基于标准Linux电源管理系统的轻量级Android电源管理驱动,针对嵌入式设备做
    了很多优化。利用锁和定时器来切换系统状态,控制设备在不同状态下的功耗,已达到节能的目的。
    源代码位于:
    - [ ] kernel/power/earlysuspend.c
    - [ ] kernel/power/consoleearlysuspend.c
    - [ ] kernel/power/fbearlysuspend.c
    - [ ] kernel/power/wakelock.c
    - [ ] kernel/power/userwakelock.c

    Android5.0版本引用JobSchedule调度程序,以便增加设备续航时间。

    (3)低内存管理器(Low Memory Killer)

    比Linux的标准的OOM(Out Of Memory)机制更加灵活,它可以根据需要
    杀死进程以释放需要的内存。源代码位于 drivers/staging/ android/lowmemorykiller.c。

    (4)匿名共享内存(Ashmem)

    为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。源代码位于
    mm/ashmem.c。

    (5)Android PMEM(Physical)

    PMEM用于向用户空间提供连续的物理内存区域,DSP和某些设备只能工作在连续的物
    理内存上。
    源代码位于drivers/misc/pmem.c。

    (6)Android Logger

    一个轻量级的日志设备,用于抓取Android系统的各种日志,是Linux所没有的。
    源代码位于drivers/staging/android/logger.c。

    (7)Android Alarm

    提供了一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会
    运行的时钟基准。源代码位于drivers/rtc/alarm.c。

    (8)USB Gadget驱动

    一个基于标准 Linux USB gadget驱动框架的设备驱动,Android的USB驱动是基于gaeget框架的。
    源代码位于
    - [ ] drivers/usb/gadget/android.c
    - [ ] drivers/usb/gadget/f_adb.c
    - [ ] drivers/usb/gadget/f_mass_storage.c

    (9)Android Ram Console

    为了提供调试功能,Android允许将调试日志信息写入一个被称为RAM Console的设备
    里,它是一个基于RAM的Buffer。源代码位于drivers/staging/android / ram_console.c。

    (10)Android timed device

    提供了对设备进行定时控制的功能,目前支持vibrator和LED设备。源代码位于
    drivers/staging/android /timed_output.c(timed_gpio.c)。

    (11)Yaffs2 文件系统

    Android采用Yaffs2作为MTD nand flash文件系统,源代码位于fs/yaffs2/目录下。
    Yaffs2是一个快速稳定的应用于NAND和NOR Flash的跨平台的嵌入式设备文件系统,同其他Flash文件系统相比,
    Yaffs2能使用更小的内存来保存其运行状态,因此它占用内存小。Yaffs2的垃圾回收非常简单而且快速,因此能表
    现出更好的性能。Yaffs2在大容量的NAND Flash上的性能表现尤为突出,非常适合大容量的Flash存储。

    四.Android驱动开发主要工作

    Linux系统将设备驱动分为以下三类:

    • (1)字符设备

      指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。

    • (2)块设备

      指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。

    • (3)网络设备

      为支持通过文件接口处理网络连接,Linux使用了源于BSD的套接字抽象,套接字keil看作应用程序、文件接口、内核的网络之间的代理。

    驱动程序是介于系统和硬件之间的桥梁,实现硬件和系统之间的交互是我们底层开发的主要任务。在Android系统中,我们一般需要编写内核级和用户级的程序来完成具体的任务。

    4.1 实现系统和硬件之间交互的几种方式

    • (1).编写自己的系统调用
      系统调用是用户级程序访问内核最基本的方法,Linux提供了很多标准的系统调用(参见内核代码树中的include/asm-i386/unistd.h和arch/i386/kernel/entry.S文件),并且允许我们添加自己的系统调用来实现和内核的信息交换;

    • (2).编写驱动程序
      Linux有一个重要的理念就是“一切皆文件”(everything is a file)。

      用户空间的应用程序通过系统提供的统一交互接口 open() —— read() —— write() —— ioctl() —— close()方法,访问文件系统中/dev/目录下的一个文件来访问运行于内核空间的驱动程序,并通过驱动程序中实现的功能达到对硬件的访问。

    • (3). 使用proc 文件系统

      proc是Linux提供的一种特殊的文件系统,推出它的目的就是提供一种便捷的用户和内核间的交互方式。proc 文件系统相对是比较简单的,不过proc文件的读写并不统一,读数据的buf指针直接指向的就是用户态的地址,可以用sprintf进行写入;而写方法却是内核态的地址,需要用get_user或者 copy_from_user之类的方法。

    • (4).使用虚拟文件系统

      有些内核开发者认为利用ioctl()系统调用往往会似的系统调用意义不明确,而且难控制。而将信息放入到proc文件系统中会使信息组织混乱,因此也不赞成过多使用。他们建议实现一种孤立的虚拟文件系统来代替ioctl()和/proc,因为文件系统接口清楚,而且便于用户空间访问,同时利用虚拟文件系统使得利用脚本执行系统管理任务更家方便、有效。

    • (5).使用内存映像

      Linux通过内存映像机制来提供用户程序对内存直接访问的能力。内存映像的意思是把内核中特定部分的内存空间映射到用户级程序的内存空间去。也就是说,用户空间和内核空间共享一块相同的内存。

    4.2 内核空间和用户空间的交互

    上面讲了系统与硬件交互的几种方式提到了,在具体的交互中,驱动程序驱动具体的硬件模块工作时涉及到一个内核空间和用户空间交互的概念。

    现代的计算机体系结构中存储管理通常都包含保护机制。提供保护的目的,是要避免系统中的一个任务访问属于另外的或属于操作系统的存储区域。如在IntelX86体系中,就提供了特权级这种保护机制,通过特权级别的区别来限制对存储区域的访问。

    基于这种构架,Linux操作系统对自身进行了划分:一部分核心软件独立于普通应用程序,运行在较高的特权级别上,(Linux使用Intel体系的特权级3来运行内核。)它们驻留在被保护的内存空间上,拥有访问硬件设备的所有权限,Linux将此称为内核空间

    相对的,其它部分被作为应用程序在用户空间 执行。它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,不能直接访问内核空间,当然还有其他一些具体的使用限制。(Linux使用Intel体系的特权级0来运行用户程序。)

    通过下面的图,看一下内核空间与用户空间的交互关系:
    这里写图片描述

    版权声明:本文为【limin13215】原创文章,欢迎转载, 转载请注明链接地址:http://blog.csdn.net/limin2928/article/details/72676518

    展开全文
  • QQ:971586331 软件环境: 操作系统:windows 10 IDE版本:Android Studio 3.4.2 JAVA版本:jdk-8u221-windows-x64 NDK版本:android-ndk-...开发板android版本:android 4.0.3 硬件环境: 开发板:itop-44...

    QQ:971586331

    软件环境:

    操作系统:windows 10

    IDE版本:Android Studio 3.4.2

    JAVA版本:jdk-8u221-windows-x64

    NDK版本:android-ndk-r20-windows-x86_64

    Kernel版本:linux 3.0

    开发板android版本:android 4.0.3

    硬件环境:

    开发板:itop-4412 精英版

    本文内容:本文描述了如何使用android应用程序调用linux驱动控制LED灯的亮灭。要实现android应用程序控制LED,需要三个程序,LED的linux驱动,JNI库和android应用程序。android应用程序通过JNI库调用LED驱动程序,从而实现android应用程序控制LED。

    1.开发板环境搭建

    开发环境搭建请参考《iTOP-4412开发板之精英版使用手册_V3.1.pdf》,本文使用的配置是

    uboot:iTop4412_uboot_20180320.tar

    kernel:iTop4412_Kernel_3.0_20180604.tar

    android:iTop4412_ICS_git_20151120.tar

    编译完成后将ramdisk-uboot.img,system.img,zImage,u-boot-iTOP-4412.bin文件通过OTG或SD烧写到开发板的EMMC中,如果在uboot下使用OTG,发现windows 10装不上光盘中的android_drv_90000_64.exe驱动,可以谷歌搜索安装android_11000010001_x64_718.exe。

    2.LED的驱动程序

    LED驱动在kernel的drivers/char/itop4412-leds.c中,从itop4412-leds.c中我们可以得知LED驱动的设备文件名叫“leds”。驱动程序实现了ioctl函数。

    long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
    {
    	printk("debug: leds_ioctl cmd is %d\n" , cmd);
    
    	switch(cmd)
    	{
    		case 0:
    		case 1:
    			if (arg > LED_NUM) {
    				return -EINVAL;
    			}
    
    			gpio_set_value(led_gpios[arg], cmd);
    			break;
    
    		default:
    			return -EINVAL;
    	}
    
    	return 0;
    }

    leds_ioctl的cmd参数表示灯的亮灯,arg参数表示灯的编号,根据文件中的定义可以知,0表示GPL2_0,也就是LED2,1表示GPK1_1,也就是LED3。

    static int led_gpios[] = {
    	EXYNOS4_GPL2(0),
    	EXYNOS4_GPK1(1),
    };

    接下来我们查看drivers/char/Makefile文件,宏CONFIG_LEDS_CTL控制LED驱动是否编译

    obj-$(CONFIG_LEDS_CTL)		+= itop4412_leds.o

    再查看drivers/char/Kconfig文件,默认就是y

    config LEDS_CTL
            bool "Enable LEDS config"
            default y
            help
              Enable LEDS config

    再查看.config,已经将LED驱动编入了内核

    CONFIG_LEDS_CTL=y

    看来板子的驱动已经做好了,完全不用我们动手,接下我们看怎么编写JNI接口调用linux驱动

    3.JNI和NDK

    因为android是使用java语言进行开发的,但linux驱动是用C语言进行开发的,所以面临java如果调用C语言接口的问题,JNI提供的API就是解决java和其他语言通信的问题。NDK 是一套工具集合,允许你使用C语言来实现应用程序的部分功能。我们写好JNI接口后使用NDK打包成库文件,就可以提供给android应用程序调用了。接下来我们新建工程编写JNI。

    新建一个空activity

    填写工程名,选择工程路径,开发语言选择java,API选择15

    创建工程后得待编译完成,然后在包名下创建一个名叫jni_led的类

    文件内容如下:

    package com.example.led_test;
    
    public class jni_led {
    
        public native static String Leds_Operation(int ledNum, boolean status); //操作接口
    }

    打开 Android Studio 的 Terminal,使用javac命令将java文件编译成.class文件

    F:\OneDrive\Linux\android_project\led_test>javac .\app\src\main\java\com\example\led_test\jni_led.java

    使用javah命令创建头文件。-encoding UTF-8表示指定编码格式,防止出现“错误: 编码GBK的不可映射字符”,-d jni表示在当前目录下创建jni目录,将生成的文件放在jni目录中,-classpath表示指定类文件的路径。这里有一个地方要注意,类文件在写的时候是包名+类名,所有路径只用写到java目录,后面的com,example和led_test虽然都是文件夹,但这里表示包名(第一次写在这里纠结了好久,我想我路径明明写对了啊,为什么找不到\app\src\main\java\com\example\led_test文件夹下的类)

    F:\OneDrive\Linux\android_project\led_test>javah -encoding UTF-8 -d jni -classpath ./app/src/main/java com.example.led_test.jni_led
    

    指令执行完成后可以发现在jni目录下生成了包名加类名的头文件

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_led_test_jni_led */
    
    #ifndef _Included_com_example_led_test_jni_led
    #define _Included_com_example_led_test_jni_led
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_led_test_jni_led
     * Method:    Leds_Operation
     * Signature: (IZ)Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_example_led_1test_jni_1led_Leds_1Operation
      (JNIEnv *, jclass, jint, jboolean);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    可以发现,头文件中根据jni_led.java中定义的java类接口生成了JNI接口函数,我们要实现这个接口函数。

    然后在JNI下创建com_example_led_test_jni_led.c文件

    在com_example_led_test_jni_led.c中,我们将头文件中的接口函数据复制过来,然后使用linux API操作linux设备文件

    //
    // Created by shiyu on 2019/8/17.
    //
    
    #include<jni.h>
    #include<stdio.h>
    #include <fcntl.h>
    #include <linux/ioctl.h>
    //导入我们创建的头文件
    #include "com_example_led_test_jni_led.h"
    
    #define DEVICE_NAME		"/dev/leds"
    
    JNIEXPORT jstring JNICALL Java_com_example_led_JNITest_Leds_1Operation
      (JNIEnv *env, jclass obj, jint ledsNum, jboolean status){
    
    int leds_fd = 0;
    
    	leds_fd = open(DEVICE_NAME, O_RDWR);  //打开设备节点
    	if (leds_fd == -1) {
    		return 1;
    	}
    
    	switch (ledsNum) {
    	case 0:
    		if (status)
    			ioctl(leds_fd, 0, 0);
    		else
    			ioctl(leds_fd, 1, 0);
    		break;
    	case 1:
    		if (status)
    			ioctl(leds_fd, 0, 1);
    		else
    			ioctl(leds_fd, 1, 1);
    		break;
    	defautl :
    		break;
    	}
    
    	close(leds_fd);
    
    	return 0;  //操作成功返回0
    }

    在jni下创建一个Android.mk文件

    
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := jni_led
    LOCAL_SRC_FILES := com_example_led_test_jni_led.c
    include $(BUILD_SHARED_LIBRARY)

    这时指定了生成库的名字和源文件,再新建一个Application.mk文件

    APP_ABI := all

    安装NDK工具集后,进入jni目录使用ndk-build命令将JNI接口程序编译成库文件

    在libs目录下生成了各种平台的库文件

    为了让项目能够找到我们的生成的库,在 build.gradle 文件夹的 android 下添加:

    sourceSets {
            main() {
                jniLibs.srcDirs = ['../libs']
                jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
            }
        }

    然后在jni_led.java中加载生成的库文件

    package com.example.led_test;
    
    public class jni_led {
        static {
            System.loadLibrary("jni_led");  //加载生成的.so文件
        }
        public native static String Leds_Operation(int ledNum, boolean status); //操作接口
    }

    接下来我们编写android应用程序利用Leds_Operation接口控制LED灯

    4.编写android应用程序

    打开工程目录下的activity_main.xml文件,添加4个button,并指写button的onClick回调函数

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TableLayout
            android:id="@+id/TableLayout2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:collapseColumns="4" >
    
            <TableRow>
    
                <Button
                    android:id="@+id/button_led3off"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led3_off_click"
                    android:text="led3_off"
                    tools:layout_editor_absoluteX="228dp"
                    tools:layout_editor_absoluteY="186dp" />
    
                <Button
                    android:id="@+id/button_led3on"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led3_on_click"
                    android:text="led3_on"
                    tools:layout_editor_absoluteX="98dp"
                    tools:layout_editor_absoluteY="186dp" />
    
                <Button
                    android:id="@+id/button_led2off"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led2_on_click"
                    android:text="led2_off"
                    tools:layout_editor_absoluteX="228dp"
                    tools:layout_editor_absoluteY="100dp" />
    
                <Button
                    android:id="@+id/button_led2on"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led2_off_click"
                    android:text="led2_on"
                    tools:layout_editor_absoluteX="98dp"
                    tools:layout_editor_absoluteY="100dp" />
            </TableRow>
        </TableLayout>
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    我们为4个按键指定了4个回调函数据,接下来我们在MainActivity.java中实现这4个回调函数

    package com.example.led_test;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void led2_on_click( View view )
        {
            jni_led.Leds_Operation(0, false);
        }
    
        public void led2_off_click( View view )
        {
            jni_led.Leds_Operation(0, true);
        }
    
        public void led3_on_click( View view )
        {
            jni_led.Leds_Operation(1, false);
        }
    
        public void led3_off_click( View view )
        {
            jni_led.Leds_Operation(1, true);
        }
    }
    

    如上,我们实现了这4个回调函数,调用jni_led库中的Leds_Operation函数,Leds_Operation会调用Java_com_example_led_JNITest_Leds_1Operation函数,这样就实现了android应用程序调用linux驱动接口。

    连接开发板,编译运行。

     

     

    展开全文
  • android驱动框架介绍

    千次阅读 2019-06-28 14:05:11
    android驱动框架介绍 了解android驱动框架: 1.方法1——jni调用底层驱动 在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序: 优点:简单易行; 缺点:主要在于驱动程序,由于...

    android驱动框架介绍

    了解android驱动框架:

    1.方法1——jni调用底层驱动

     

    在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序:

    优点:简单易行;

    缺点:主要在于驱动程序,由于在linux中需要遵循GPL协议,需要开源,而许多厂商的一些代码不希望开源。

     

    2.方法2——增加硬件抽象层

    将驱动程序一分为二,一部分开源在内核中,一部分不开源在android框架中:

     

     

    led android驱动:
     

    从这里我们将看到整个应用框架层到底层驱动的走向。首先,无论是哪种方法,我们都需要实现一个linux驱动以供上层访问led资源。

     

    1.linux驱动:

    linux的字符设备驱动编写:

     

    #include#include#include#include#include#include#include#includestatic struct cdev dev;
    static dev_t dev_num;
    
    
    #define GPM4CON 0x110002E0
    #define GPM4DAT 0X110002E4
    
    #define LED_ON _IOW('G',0,int)
    #define LED_OFF _IOW('G',1,int)
    
    static unsigned int *led_con = NULL;
    static unsigned int *led_dat = NULL;
    
    
    static struct class *led_class = NULL;
    
    
    static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
    		switch(cmd)
    		{
    				case LED_ON:
    				{
    						writel(readl(led_dat)& ~(0x1<<arg), led_dat);
    						break;		
    				}
    					
    				case LED_OFF:
    				{
    						writel(readl(led_dat)| (0x1<<arg), led_dat);
    						break;		
    				}
    					
    				default:
    				{
    						return -EINVAL;		
    						break;
    				}
    			
    		}
    	
    		return 0;
    }
    
    static struct file_operations led_fops = {
    		.owner = THIS_MODULE,
    		.unlocked_ioctl = led_ioctl,
    };
    
    static void hw_init()//GPM4_0-3
    {
    			//1.2.1 映射地址
    			led_con = ioremap(GPM4CON,4);
    			led_dat = ioremap(GPM4DAT,4);
    			
    			//1.2.2 设置为输出状态
    			writel((readl(led_con)& ~0xffff) | 0x1111, led_con);
    			
    			//1.2.3 设置为高电平
    			writel(readl(led_dat)|0xf, led_dat);
    	
    }
    
    
    static int led_init()
    {
    	  //1.1 cdev字符设备初始化
    		//1.1.1 分配cdev结构(静态分配) 
    		
    		//1.1.2 初始化cdev结构
    		alloc_chrdev_region(&dev_num,0,1,"callon_led");
    		cdev_init(&dev, &led_fops);
    		dev.owner = THIS_MODULE;
    		
    		//1.1.3 注册cdev结构 
    		cdev_add(&dev,dev_num,1);
    		
    		//1.2 硬件初始化
    		hw_init();
    		
    		//1.3 创建设备文件
    		//1.3.1 创建类
    		led_class = class_create(THIS_MODULE,"callon_led");
    		
    		//1.3.2 创建设备
    		device_create(led_class,NULL,dev_num,NULL,"%s","callon_led");
    		
    		printk("init led device is OK!\n");
    		return 0;
    }
    
    static void led_exit()
    {
    		device_destroy(led_class,dev_num);
    		class_destroy(led_class);
    	
    		iounmap(led_dat);
    		iounmap(led_con);
    		
    		cdev_del(&dev);
    		unregister_chrdev_region(dev_num,1);
    }
    
    
    
    
    module_init(led_init);
    module_exit(led_exit);


     

     

     

     

    2 实现第一种方法:

    首先,说明一下为什么使用jni:

    1.基于对代码的保护,java相对容易被反编译,而c/c++库反汇编难度较大;

    2.可以方便地使用现存的开源库;

    3.提高执行效率;

    4.java在某些文件操作方面,找不到相关的API,如此处的ioctl.

    其次,为什么使用ndk?

    ndk提供了一系列的工具,能够帮助开发者快速开发c/c++的动态库,并能自动将.so动态库和java一起打包成apk.

    第一种方法的设计思路如下所示:

    在第一步中想要使用javah命令自动产生头文件需要先编写app程序,但是此时的app程序并不需要很完善,只需要提出一个你想要的native接口就好(但是你的android程序必须要Rebuild正确才会正确产生头文件):

     

    package com.led.ndk.example.callon.ndk_led;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.CheckBox;
    
    public class MainActivity extends Activity {
    
        private CheckBox[] Led = new CheckBox[4];
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Led[0] = (CheckBox)findViewById(R.id.checkbox_led1);
            Led[1] = (CheckBox)findViewById(R.id.checkbox_led2);
            Led[2] = (CheckBox)findViewById(R.id.checkbox_led3);
            Led[3] = (CheckBox)findViewById(R.id.checkbox_led4);
        }
    
        private void SendCmd(View view)
        {
            for(int i =1; i<5; i++)
            {
                if(Led[i].isChecked())
                {
                    cmdLeds(1, i);
                }
                else
                {
                    cmdLeds(0, i);
                }
            }
        }
    
        public native void cmdLeds(int cmd, int arg);
        
    }


    根据如上简单的app,使用命令:

     

     

    javah -d jni -classpath 你的sdk目录/platforms/你的平台名/android.jar:你的应用程序/app/build/intermediates/classes/debug/ 你的包名.主类名

    如:

     

    javah -d jni -classpath /opt/AndroidSDK/platforms/android-23/android.jar:/home/callon/Downloads/callon_ndk_led/ndk_led/app/build/intermediates/classes/debug/ com.led.ndk.example.callon.ndk_led.MainActivity


    此时自动产生出jni文件夹,其中包含头文件com_led_ndk_example_callon_ndk_led_MainActivity.h,头文件比较重要的:

     

     

    JNIEXPORT void JNICALL Java_com_led_ndk_example_callon_ndk_1led_MainActivity_cmdLeds
      (JNIEnv *, jobject, jint, jint);

     

    这也就是我们编写源文件需要实现的方法名,下面直接编写源文件:

     

    #include "com_led_ndk_example_callon_ndk_led_MainActivity.h"
    #include#include#include#include#include#include#include#define LED_ON _IOW('G',0,int)
    #define LED_OFF _IOW('G',1,int)
    
    
    JNIEXPORT void JNICALL Java_com_led_ndk_example_callon_ndk_1led_MainActivity_cmdLeds
      (JNIEnv * env, jobject thiz, jint cmd, jint arg)
    {
    		int fd;
    		int temp_cmd;
    		fd = open("/dev/callon_led",O_WRONLY);
    		
    		if(cmd == 1)
    			temp_cmd = LED_ON;
    		else
    			temp_cmd = LED_OFF;
    			
    		ioctl(fd, temp_cmd, arg);
    		close(fd);
    		  	
    }


    就是一些对内核驱动文件的操作,然后编写Android.mk即makefile:

     

     

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := callon_ndk_led
    LOCAL_SRC_FILES := ndk_led.c
    include $(BUILD_SHARED_LIBRARY)

    此时,在你的jni文件夹应该有这三个文件了,退到jni文件夹之外,使用命令ndk-build即可:

     

     

    callon@ubuntu:~/Downloads/callon_ndk_led/jni$ ls
    Android.mk  com_led_ndk_example_callon_ndk_led_MainActivity.h  ndk_led.c
    callon@ubuntu:~/Downloads/callon_ndk_led/jni$ cd ..
    callon@ubuntu:~/Downloads/callon_ndk_led$ ndk-build 
    [armeabi] Compile thumb  : callon_ndk_led  libs/armeabi/libcallon_ndk_led.so
    callon@ubuntu:~/Downloads/callon_ndk_led$

    最后一步,完善app:

    首先,用Project形式来看我们的app,并在app->src->main下创建一个目录"jniLibs";

    然后,将我们.so所在的armeabi目录拷贝到jniLibs目录下;

    最后在我们的app代码的最后加上:

     

    static
        {
            System.loadLibrary("callon_ndk_led");
        }

    然后Rebuild Project即可!

     

     

    3 实现第二种方法:
    1.HAL程序编写:

    首先在  安卓源代码根目录/hardware/libhardware/modules/下创建自己的hal代码存放路径,如led。

    最终编写的文件为:安卓源代码根目录/hardware/libhardware/modules/led/led_hal.c和Android.mk,安卓源代码根目录/hardware/libhardware/include/hardware/led.h。

     

    #include#include#include#include#include#include#include#include#include#include#define LOG_TAG "callon_led"
    static int fd;
    
    static int led_close(struct hw_device_t *device)
    {
    	struct led_device_t* led = (struct led_device_t*)device;
    	free(led);
    
    	close(fd);
    	return 0;
    }
    
    int led_on(struct led_device_t* dev,int arg)
    {
    	ioctl(fd,LED_ON,arg);
    	return 0;
    }
    
    int led_off(struct led_device_t* dev,int arg)
    {
    	ioctl(fd,LED_OFF,arg);
    	return 0;
    }
    
    static struct led_device_t led_dev = {
    	.led_device = {
    		.tag = HARDWARE_DEVICE_TAG,
    		.close = led_close,
    	},
    	.set_on = led_on,
    	.set_off = led_off,
    };
    
    static int open_led(const struct hw_module_t* module, char const* name,
            struct hw_device_t** device)
    {
    	*device = &led_dev;
    	fd = open("/dev/callon_led",O_RDWR);
    	if(fd < 0)
    	{
    		ALOGD(LOG_TAG, "open device fail!");
    		return -1;
    	}
    	return 0;
    }
    
    static struct hw_module_methods_t led_methods = {
        .open =  open_led,
    };
    
    
    struct hw_module_t HAL_MODULE_INFO_SYM = {
        .tag = HARDWARE_MODULE_TAG,
        .id = "led",
        .methods = &led_methods,
    };


     

     

     

    led.h

     

    #ifndef _HARDWARE_LED_H
    #define _HARDWARE_LED_H
    
    #include#define LED_ON _IOW('G',0,int)
    #define LED_OFF _IOW('G',1,int)
    
    struct led_device_t {
    	struct hw_device_t led_device;
    	int (*set_on)(struct led_device_t* dev,int arg);//means led_number
    	int (*set_off)(struct led_device_t* dev,int arg);
    };
    
    
    
    #endif  // _HARDWARE_LED_H

     

     

    Android.mk

     

     

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := led.default
    
    # HAL module implementation stored in
    # hw/.default.so
    LOCAL_MODULE_RELATIVE_PATH := hw
    LOCAL_C_INCLUDES := hardware/libhardware
    LOCAL_SRC_FILES := led_hal.c
    LOCAL_SHARED_LIBRARIES := liblog
    LOCAL_MODULE_TAGS := eng
    
    include $(BUILD_SHARED_LIBRARY)

    编译则在  安卓源代码根目录下使用

     

    $ . setenv
    $ lunch
    $ mmm hardware/libhardware/modules/led/

    看到

     

     

    target SharedLib: led.default (out/target/product/tiny4412/obj/SHARED_LIBRARIES/led.default_intermediates/LINKED/led.default.so)
    target Symbolic: led.default (out/target/product/tiny4412/symbols/system/lib/hw/led.default.so)
    Export includes file: hardware/libhardware/modules/led/Android.mk -- out/target/product/tiny4412/obj/SHARED_LIBRARIES/led.default_intermediates/export_includes
    target Strip: led.default (out/target/product/tiny4412/obj/lib/led.default.so)
    Install: out/target/product/tiny4412/system/lib/hw/led.default.so
    make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'
    
    #### make completed successfully (1 seconds) ####

    即可,最后产生的就在out/target/product/tiny4412/system/lib/hw/led.default.so了。

    我们将system.img重做,这里通过一个脚本./gen-img.sh完成。

     

    2.硬件服务编写:

    首先,Service Manager为了解决访问冲突而存在的,在有Service Manager的基础之上,我们的底层需要先编写硬件服务,注册到Service Manager,我们的app才能通过Service Manager获取到服务,操作底层。

     

    由于涉及到许多目录操作,细化操作后为:

     

    1.创建 ILedService.aidl

    仿照 frameworks/base/core/java/android/os/IVibratorService.aidl 

     

    package android.os;
    
    /** {@hide} */
    interface ILedService
    {
        int LedOpen();
        int LedOn(int arg);
        int LedOff(int arg);
    }

     

    2.修改frameworks/base/Android.mk 增加

    core/java/android/os/ILedService.aidl \

    3.自动生成ILedService.java

    mmm frameworks/base/编译自动生成out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/ILedService.java

    4.创建 LedService.java 实现接口函数

    仿照frameworks/base/services/core/java/com/android/server/VibratorService.java 

     

    package com.android.server;
    
    import android.util.Slog;
    import android.os.ILedService;
    
    public class LedService extends ILedService.Stub{
        private static final String TAG = "LedService";
        
    	public LedService() 
    	{
    		Slog.d(TAG,"LedService");
    	}
        	public int LedOpen() throws android.os.RemoteException
    	{
    		return native_LedOpen();
    	}
        	public int LedOn(int arg) throws android.os.RemoteException
    	{
    		return native_LedOn(arg);
    	}
    	public int LedOff(int arg) throws android.os.RemoteException
    	{
    		return native_LedOff(arg);
    	}      
            
    	public static native int native_LedOpen();
    	public static native int native_LedOn(int arg);
    	public static native int native_LedOff(int arg);
    }

     

     

    5.将服务注册到Service Manager当中 修改frameworks/base/services/java/com/android/server/SystemServer.java
    参考vibrator修改的地方

    LedService led = null;

     

    Slog.i(TAG, "Led Service");
                led = new LedService();
                ServiceManager.addService("led", led);


    6.实现com_android_server_LedService.cpp

    为什么需要它?因为我们的hal代码并没有提供jni的接口(这里提供了一种新的方法来提供native方法,之前是自动产生头文件然后来实现的)。

    根据frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

     

    /*
     * Copyright (C) 2009 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    #define LOG_TAG "LedService"
    
    #include "jni.h"
    #include "JNIHelp.h"
    #include "android_runtime/AndroidRuntime.h"
    
    #include#include#include#includestruct led_device_t *led_dev;
    
    namespace android
    {
    
    static jint LedOpen(JNIEnv *env, jobject clazz)
    {
    	hw_module_t *module;
    	hw_device_t *device;	
    	hw_get_module("led",(hw_module_t const **)&module);
    
    	module->methods->open(module, NULL, &device);
    	
    	led_dev = (struct led_device_t*)device;
    	return 0;
    }
    
    static jint LedOn(JNIEnv *env, jobject clazz, int arg)
    {
    	led_dev->set_on(led_dev,arg);
    	return 0;
    }
    
    static jint LedOff(JNIEnv *env, jobject clazz, int arg)
    {
        	led_dev->set_off(led_dev,arg);
    	return 0;
    }
    
    static JNINativeMethod method_table[] = {
        { "native_LedOpen", "()I", (void*)LedOpen },
        { "native_LedOn", "(I)I", (void*)LedOn },
        { "native_LedOff", "(I)I", (void*)LedOff}
    };
    
    int register_android_server_LedService(JNIEnv *env)
    {
        return jniRegisterNativeMethods(env, "com/android/server/LedService",
                method_table, NELEM(method_table));
    }
    
    };


     

     

    7.注册native接口

     

    在frameworks/base/services/core/jni/onload.cpp中添加

     

    int register_android_server_LedService(JNIEnv* env);

     

     

    register_android_server_LedService(env);

     

     

    8.修改Android.mk

    在frameworks/base/services/core/jni/Android.mk中加入自己写的com_android_server_LedService.cpp

     

    $(LOCAL_REL_DIR)/com_android_server_LedService.cpp \

     

    9.mmm frameworks/base/services/编译

    Copying: out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes.dex
    target Jar: services (out/target/common/obj/JAVA_LIBRARIES/services_intermediates/javalib.jar)
    Install: out/target/product/tiny4412/system/framework/services.jar
    make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'
    
    #### make completed successfully (50 seconds) ####

     

    其中碰到一阵错误,非常无语:

     

    make: Entering directory `/opt/Tiny4412/Android/android-5.0.2'
    make: *** No rule to make target `frameworks/base/services/core/.java', needed by `out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes-full-debug.jar'.  Stop.
    make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'
    
    #### make failed to build some targets (1 seconds) ####

    直接不往下编译,直接报错,非常难找错误,最后发现由于LedService.java的文件名多了个空格。出现这种错误一定要耐心,一定是某个小地方出错的。
     

     

    最后继续使用./gen-img.sh完成system.img的编译,烧写进开发板,为写应用程序做准备。

     

    3.应用程序设计:

     

    package com.led.hal.example.callon.callonhalled;
    
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.CheckBox;
    import android.os.ILedService;
    import android.os.ServiceManager;
    
    public class MainActivity extends AppCompatActivity {
    
        private CheckBox[] Led = new CheckBox[4];
        private ILedService iLedService = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Led[0] = (CheckBox)findViewById(R.id.checkbox_led1);
            Led[1] = (CheckBox)findViewById(R.id.checkbox_led2);
            Led[2] = (CheckBox)findViewById(R.id.checkbox_led3);
            Led[3] = (CheckBox)findViewById(R.id.checkbox_led4);
            iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
            try {
                iLedService.LedOpen();
            }catch(RemoteException e){
                e.printStackTrace();
            }
        }
    
        private void SendCmd(View view)
        {
            for(int i =1; i<5; i++)
            {
                if(Led[i].isChecked()) {
                    try {
                        iLedService.LedOn(i);
                    }catch (RemoteException e){
                        e.printStackTrace();
                    }
                }
                else {
                    try {
                        iLedService.LedOff(i);
                    }catch (RemoteException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    程序其实很简单,但是涉及到android 中隐藏类的使用,我们的ILedService和ServiceManager其实都是隐藏类,你编译不过去的,添加相应的jar包才可以,参考

     

    http://blog.csdn.net/wukunting/article/details/5788196

    首先拷贝out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar到工程下

    然后AndroidStudio中File->Project Structure点击其中的'+'->选择Import .JAR/.AAR Package->选择classes.jar->Finish

    继续在Project Structure下选择app->Dependencies->选择'+'->Module Dependency->选择'classes'即可。

    这时候整个源码都好了,但是下载速度会很慢,改善基于frameworks设计的app下载和运行速度的方案:

    1.修改build.gradle(Module:app)

     

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"
    
        defaultConfig {
            applicationId "com.led.hal.example.callon.callonhalled"
            minSdkVersion 21
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
            multiDexEnabled true
        }
    
        dexOptions {
            javaMaxHeapSize "4g"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.2.0'
        compile project(':classes')
        compile 'com.android.support:multidex:1.0.0'
    }

    2.修改AndroidManifest.xml

     

    在application下增加

    android:name="android.support.multidex.MultiDexApplication"
     

    最后下载运行吧!
     

    展开全文
  • Android驱动开发全过程

    千次阅读 2019-07-01 21:35:10
    Android驱动开发全过程(有图有真相) 前言 意外在网上发现了这扁文章,看后感觉很有必要分享,所以整理并上传,希望大家喜欢。 Android硬件抽象层(HAL)概要介绍和学习计划 Android 的硬件抽象层,简单来说,...
  • android 设备驱动

    2019-06-25 16:59:39
    说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正,还增加了...
  • Android驱动入门系列(一)

    万次阅读 多人点赞 2013-03-08 17:07:41
    Android驱动入门系列(一) —— Android驱动简介及编写第一个Android驱动   以下文章参考网上搜到的《Android驱动开发全过程(有图有真相)》一文,其中根据自己的实际编写情况作了部分修改,不用作商业用途 ...
  • Android 开发之 ---- 底层驱动开发(一)

    万次阅读 多人点赞 2012-05-07 10:48:48
    驱动概述  说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。...android 驱动 主要分两种类型:Android 专用驱动Android 使用
  • Android驱动开发与移植实战详解,完整扫描版

    千次下载 热门讨论 2020-07-30 23:33:34
    李骏、陈小玉编著的《Android驱动开发与移植实战详解》分为18章,依次讲解了Android系统的基本知识, Linux内核的基本知识,分析了Android系统的源码,深入分析HAL层的基本知识,GoldFish下的驱动、MSM内核和驱动、...
  • 如何学习Android驱动开发

    千次阅读 2017-04-05 14:53:20
    如何成为一名优秀的Android驱动程序员?参数如下要求: 一、Android驱动的基础知识 1.Android驱动是基于Linux驱动,强烈推荐阅读Linux Device Driver 3rd版,这本书讲了Linux下设备驱动的基础知识,要求反复细读。 2...
  • Android 驱动程序Demo及流程

    千次阅读 2017-07-29 16:32:16
    很久前就想了解驱动程序的想法,这里现做一个简单的开始,从demo做起,看到Android驱动程序的基本运行流程,这对漏洞分析、检测和挖掘都是必要的。同样,本篇基本也是自己学习过程的记录,无干货。本篇大多数内容...
  • 理论的东西不常用时就会慢慢的被遗忘,但是找...linux/android驱动工程师面试相关内容总结如下(以后遇到新问题再补充): 1、linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 答:Linux内核将内存
  • 嵌入式Linux/Android驱动开发揭秘(1)触摸屏驱动开发 专题简介:自1971年,美国人SamHurst发明了世界上第一个触摸传感器以来,触摸屏技术不断革新,给了程序设计师和UI工程师无限的想象空间,它极大改善了终端...
  • Android驱动开发知识储备 Android软件层次结构 (1)操作系统层 显示驱动(Frame Buffer),Flash内存驱动,照相机驱动,音频驱动,WiFi驱动,键盘驱动,蓝牙驱动,Binder IPC驱动,Power Management ,这些都包括...
  • Android架构分析之Android驱动程序开发

    千次阅读 2013-01-14 12:02:39
    作者:刘昊昱  ... Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29   本文介绍如何开发Android驱动程序并进行测试...Android是基于Linux的,所以Android驱动程序的开发方法与Linux驱动程序开发方法
1 2 3 4 5 ... 20
收藏数 110,846
精华内容 44,338
关键字:

android驱动