开发可统计单词个数的Android驱动程序(3)

       在上一节已经实现了一个简单的Linux驱动程序,该驱动的功能是统计给定字符串中的单词数。并且在最后已经将该Linux驱动的源代码成功编译成 动态Linux驱动模块word_count.ko。下一步就是测试该模块。测试的方法很多,最常用的就是直接在UbuntuLinux中测试。当然,这 对于本章实现的Linux驱动是没问题的,但是对于需要直接访问硬件的驱动在Ubuntu Linux上测试就不太方便。在这种情况下就需要在相应的硬件上进行测试。

     对于一个Linux驱动程序,一开始可以在UbuntuLinux上做前期开发和测试。对于访问硬件的部分也可以在Ubuntu Linux用软件进行模拟。当基本开发完成后,就需要在开发板或工程样机上使用真实的硬件进行测试。当然,最后还需要在最终销售的手机上进行测试。最终测 试通过,Linux驱动才能算真正开发完成。在开发Linux驱动的过程中一个重要的步骤就是测试。本节将结合实际的开发流程介绍在不同平台上测试 Linux驱动程序。这些测试平台包括UbuntuLinux、Android模拟器和S3C6410开发板。

一、使用Ubuntu Linux测试Linux驱动

本 节将介绍如何在Ubuntu Linux下测试驱动程序。由于上一节编写的Linux驱动程序通过4个字节从设备文件(/dev/wordcount)返回单词数,所以不能使用cat 命令测试驱动程序(cat命令不会将这4个字节还原成int类型的值显示)。但可以使用如下命令从日志中查看单词数。

            
  1. # sh build.sh   
  2. # echo 'I love you.'  > /dev/wordcount   
  3. # dmesg   

执行上面的命令后,如果输出如图6-13所示白框中的信息,说明驱动程序成功统计了单词数。

    虽然使用echo和dmesg命令可以测试Linux驱动程序,但这种方式并不是真正的测试。为了使测试效果更接近真实环境,一般需要编写专门用于测试的 程序。本节将为word_count驱动编写一个专门的测试程序(test_word_count.c)。test_word_count.c通过直接操 作/dev/wordcount设备文件与word_count驱动进行交互。测试程序的代码如下:

            
  1. #include    
  2. #include    
  3. #include    
  4. #include    
  5. #include    
  6. int main(int argc, char *argv[])   
  7. {   
  8.     int testdev;                //  打开设备文件(/dev/wordcount)的句柄   
  9.     unsigned char buf[4];          //  表示单词数的4个字节   
  10.     //  打开设备文件   
  11.     testdev = open("/dev/wordcount", O_RDWR);   
  12.     //  如果open函数返回-1,表示打开设备文件失败   
  13.     if (testdev == -1)   
  14.     {   
  15.         printf("Cann't open file \n");   
  16.         return 0;   
  17.     }   
  18.     //  如果test_word_count后面跟有命令行参数,程序会将第1个参数值当作待统计的字符串   
  19.     //  如果没有命令行参数,则只读取设备文件中的值   
  20.     if (argc > 1)   
  21.     {   
  22.         //  向设备文件写入待统计的字符串   
  23.         write(testdev, argv[1], strlen(argv[1]));   
  24.         //  输出待统计的字符串   
  25.         printf("string:%s\n", argv[1]);   
  26.     }   
  27.     //  读取设备文件中的单词数(4个字节)   
  28.     read(testdev, buf, 4);   
  29.    
  30.     int n = 0;      //  单词数   
  31.    
  32.     //  将4个字节还原成int类型的值   
  33.     n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8   
  34.             | ((int) buf[3]);   
  35.         //  分别输出从设备文件获取的4个字节的值   
  36.     printf("word byte display:%d,%d,%d,%d\n", buf[0], buf[1], buf[2], buf[3]);   
  37.     //  输出统计出的单词数   
  38.     printf("word count:%d\n", n);   
  39.     //  关闭设备文件   
  40.     close(testdev);   
  41.     return 0;   
  42. }   

       test_word_count程序可以跟1个命令行参数(多个命令行参数只会使用第1个命令行参数)。如果命令行参数值含有空格,需要使用单引号(')或双引号(")将参数值括起来。可以使用下面的一组命令测试word_count驱动程序。

            
  1. # gcc test_word_count.c  -o test_word_count   
  2. # test_word_count   
  3. # test_word_count "I love you."   

        执行上面的命令后,如果输出如图6-14所示的信息(假设word_count以前统计过一个含有4个单词的字符串),表示word_count驱动成功测试。

二、在Android模拟器上通过原生(Native)C程序测试Linux驱动

      虽说我们开发的是Linux驱动,但本书主要介绍的是Android版的Linux内核,因此,Linux驱动只在Ubuntu Linux上测试成功还不能保证在Android设备上一定能正常工作,所以必须在Android设备上进行测试。Android设备有很多种类,如安装 了Android的开发板,运行Android系统的手机或平板电脑等。但离我们最近的并不是这些硬件设备,而是Android模拟器。Android模 拟器可以模拟绝大多数真实的环境,所以可以利用Android模拟器测试Linux内核。

      在Android模拟器上测试Linux驱动首先应该想到的,也是最先应该做的就是将word_count.ko驱动模块安装在模拟器上。可能读者使用过 adb shell命令。如果进入Android模拟器的命令提示符为“#”,说明通过命令行方式进入Android模拟器直接就是root权限(命令提示符为 “$”,表示非root权限),因此从理论上可以使用insmod命令将word_count.ko驱动模块直接安装在Android模拟器中。现在我们 来测试一下,看看是否可以将word_count.ko安装在Android模拟器上。现在执行build.sh脚本,并选择“Android模拟器”, 脚本会自动将word_count.ko文件上传到Android模拟器的/data/local目录,并进行安装。如果读者选择的是S3C6410开发 板,在安装word_count.ko时就会输出如下的错误信息,表示编译Linux驱动的Linux内核版本与当前Android模拟器的版本不相同, 无法安装。所以在编译Linux驱动时,必须选择与当前运行的Linux内核版本相同的Linux内核进行编译,否则就无法安装Linux驱动。

            
  1. insmod:init_module ‘/data/local/word_count.ko’ failed(Function not implemented)  

注意:建议上传文件到Android模拟器或开发板时,将文件放到/data/local目录,系统很多其他的目录,如/system/bin,都 是只读的,除非将word_count.ko文件打包进system.img,否则无法向这些目录写数据,即使有root权限也不行

     用于Android模拟器的goldfish内核默认不允许动态装载Linux驱动模块,因此需要在编译Linux内核之前执行如下命令配置Linux内核。

            
  1. # cd ~/kernel/goldfish   
  2. # make menuconfig   

     执行上面的命令后,会出现如图6-15所示的设置界面。按“空格”键将第二项“Enable loadable module support”选中(前面是[*]),然后按“回车”进入子菜单,选中前3项,如图6-16所示。否则Linux驱动模块仍然无法安装和卸载。当退出设 置菜单时保持设置。最后按4.2.3节的方法重新编译Linux内核,

      成功编译内核后,Android模拟器可以使用新生成的zImage内核文件动态装载Linux驱动模块。

     现在执行build.sh脚本文件完成对word_count驱动的编译、上传和安装的工作,然后进入Android模拟器的终端,使用echo和dmesg命令可以测试word_count驱动和查看测试结果,方法与上一节相同。

注意:编译可在Android模拟器上运行的Linux驱动模块要使用goldfish内核,使用其他的内核编译word_count.c,安装时会出现如下错误。

            
  1. insmod: error inserting 'word_count.ko': -1Invalid module format   

     在Android模拟器上不仅可以使用Linux命令测试驱动,也可以像UbuntuLinux一样使用本地C/C++程序进行测试。可能有的读者 要问,Android不是只能运行由Java编写的APK程序吗?顶多是在APK程序中嵌入NDK代码。还能直接运行普通的Linux程序吗?答案是肯定 的。不过要满足如下两个条件。

1.  Android模拟器、开发板或手机需要有root权限。

2.  可执行文件需要使用交叉编译器进行编译,以便支持ARM处理器。

     现在使用交叉编译器来编译在上一节编写的test_word_count.c文件。为了使编译步骤尽可能简单,我们使用Android.mk设置编译参 数,并使用make命令进行编译。首先在/root/drivers/ch06/word_count目录中建立一个Android.mk文件,并输入如 下的内容。

            
  1. LOCAL_PATH:= $(call my-dir)   
  2.    
  3. include $(CLEAR_VARS)   
  4.    
  5. # 指定要编译的源代码文件   
  6.    
  7. LOCAL_SRC_FILES:test_word_count.c   
  8.    
  9. # 指定模块名,也是编译后生成的可执行文件名   
  10.    
  11. LOCAL_MODULE :test_word_count   
  12.    
  13. LOCAL_MODULE_TAGS :optional   
  14.    
  15. include $(BUILD_EXECUTABLE)    

Android.mk文件中有如下两个地方需要说明一下。

LOCAL_MODULE_TAGS

表示当前工程(Android.mk文件所在的目录)在什么模式下编译。如果设为optional,表示不考虑模式,也就是说在任何模式下都会编译。该变量可以设置的值有user、userdebug、eng、optional。其中eng是默认值。

1.  user:限制用户对Android系统的访问,适合于发布产品。

2.  userdebug:类似于user模式,但拥有root访问权限,并且可以从日志中获取大量的调试信息。

3.  eng:一般在开发的过程中设置该模式。除了拥有userdebug的全部功能外,还会带有大量的调试工具。

LOCAL_MODULE_TAGS 的值与TARGET_BUILD_VARIANT变量有关。TARGET_BUILD_VARIANT变量用于设置当前的编译模式,可设置的值包括 user、userdebug和eng。如果想改变编译模式,可以在编译Android源代码之前执行如下命令。

# export TARGET_BUILD_VARIANT = user

或使用lunch命令设置编译模式。

# lunch full-eng

      其中full表示建立的目标,除了full目标(为所有的平台建立)外,还有专门为x86建立的full-x86。详细的建立目标执行lunch命令后就会列出。在图4-8已经显示了Android4支持的建立目标的编译模式。读者可以到第4章查看该图。

include $(BUILD_EXECUTABLE)

       BUILD_EXECUTABLE表示建立可执行的文件。可执行文件路径是/ out/target/product/generic/system/bin/test_word_count。如果想编译成动态库(.so)文件,可 以使用include $(BUILD_SHARED_LIBRARY)。动态库的路径是/ out/target/product/generic/system/lib/test_word_count.so。如果想编译成静态库(.a)文 件,可以使用include $(BUILD_STATIC_LIBRARY)。静态库的路径是/ out/target/product/generic/obj/STATIC_LIBRARIES/test_word_count_intermediates/test_word_count.

      为了将test_word_count.c文件编译成可在Android模拟器上运行的可执行程序,可以将word_count目录复制 到的某个子目录,也可以在目录中为word_count目录建立一个 符号链接。为了方便,我们采用如下命令为word_count目录在/development目录建立一个符号 链接(假设Android源代码的目录是/sources/android/android4/development/word_count)。

# ln -s  /root/drivers/ch06/word_count /sources/android/android4/development/word_count

现在进入/sources/android/android4目录,执行下面的命令初始化编译命令。

# source ./build/envsetup.sh

可以使用下面两种方法编译test_word_count.c。

1.     进入/sources/android/android4/development/word_count目录,并执行如下的命令。

# mm

2.     在/sources/android/android4目录下执行如下的命令。

# mmm  development/word_count

     成功编译后可以在/out/target/product/generic/system/bin目录中找到 test_word_count文件。在随书光盘和模拟环境中已经带了编译好的test_word_count程序(包括Emulator版本和 Ubuntu Linux版本),可执行程序一般不需要考虑Linux内核的版本,用交叉编译器编译的支持ARM处理器的程序即可以在Android模拟器上运行,也可 以在S3C6410开发板或其他有root权限的手机中运行。

Emulator版本的路径

随书光盘:<光盘根目录>/sources/ch06/word_count/emulator/test_word_count

模拟环境:/root/drivers/ch06/word_count/emulator/test_word_count

 

Ubuntu Linux版本的路径

随书光盘:<光盘根目录>/sources/ch06/word_count/ubuntu/test_word_count

模拟环境:/root/drivers/ch06/word_count/ubuntu/test_word_count

 

现在执行下面的命令将test_word_count文件上传到Android模拟器。

# adb push  ./emulator/test_word_count /data/local

然后进入Android模拟器的终端,并执行下面的命令测试word_count驱动(需要先使用chmod命令设置test_word_count的可执行权限)。

# chmod 777 /data/local/test_word_count

# /data/local/test_word_count

# /data/local/test_word_count  'a bb ccc ddd eee'

执行上面的命令后,如果输出的单词个数是5,表示程序测试成功。

 

本文节选至《Android深度探索(卷1):HAL与驱动开发》, 接下来几篇文章将详细阐述如何开发ARM架构的Linux驱动,并分别利用android程序、NDK、可执行文件测试Linux驱动。可在ubuntu Linux、Android模拟器和S3C6410开发板(可以选购OK6410-A开发板,需要刷Android)

更多相关文章

  1. Android真机测试,Find Explorer无法打开data文件夹解决办法
  2. Android音频开发(四)——ffmpeg的编译
  3. android ICS原生态Browser上增加对WML的支持
  4. android反编译工具总结
  5. Android渠道包测试方案
  6. Android(安卓)关于录音文件的编解码 实现米聊 微信一类的录音上
  7. Android(安卓)aapt实现资源分区(补充携程aapt源码)
  8. wince 四年之后,我这个菜鸟终于开始搞android了。
  9. 编译不同android系统镜像,需要的环境要求,到底是哪些

随机推荐

  1. Android(安卓)进阶 教你打造 Android(安
  2. Android中绘(画)图Canvas的简析
  3. 【android】一套完善的Android异步任务类
  4. 通过广播Intent控制Android系统自带的音
  5. Android中滑屏初探 ---- scrollTo 以及 s
  6. Android(安卓)call setting 源码分析 从
  7. 在哪里学习用于Android(安卓)App开发的Ja
  8. Menu模拟键与android:targetSdkVersion
  9. Android开机启动Activity或者Service方法
  10. Android(安卓)setContentView源码解析