[?開發可統計單詞個數的Android驅動程序](http://blog.csdn.net/nokiaguy/article/details/8523272)
???? 在上一節已經實現了一個簡單的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類型的值顯示)。但可以使用如下命令從日志中查看單詞數。
~~~
# sh build.sh
# echo 'I love you.' > /dev/wordcount
# dmesg
~~~
執行上面的命令后,如果輸出如圖6-13所示白框中的信息,說明驅動程序成功統計了單詞數。

?????? 雖然使用echo和dmesg命令可以測試Linux驅動程序,但這種方式并不是真正的測試。為了使測試效果更接近真實環境,一般需要編寫專門用于測試的程序。本節將為word_count驅動編寫一個專門的測試程序(test_word_count.c)。test_word_count.c通過直接操作/dev/wordcount設備文件與word_count驅動進行交互。測試程序的代碼如下:
~~~
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int testdev; // 打開設備文件(/dev/wordcount)的句柄
unsigned char buf[4]; // 表示單詞數的4個字節
// 打開設備文件
testdev = open("/dev/wordcount", O_RDWR);
// 如果open函數返回-1,表示打開設備文件失敗
if (testdev == -1)
{
printf("Cann't open file \n");
return 0;
}
// 如果test_word_count后面跟有命令行參數,程序會將第1個參數值當作待統計的字符串
// 如果沒有命令行參數,則只讀取設備文件中的值
if (argc > 1)
{
// 向設備文件寫入待統計的字符串
write(testdev, argv[1], strlen(argv[1]));
// 輸出待統計的字符串
printf("string:%s\n", argv[1]);
}
// 讀取設備文件中的單詞數(4個字節)
read(testdev, buf, 4);
int n = 0; // 單詞數
// 將4個字節還原成int類型的值
n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8
| ((int) buf[3]);
// 分別輸出從設備文件獲取的4個字節的值
printf("word byte display:%d,%d,%d,%d\n", buf[0], buf[1], buf[2], buf[3]);
// 輸出統計出的單詞數
printf("word count:%d\n", n);
// 關閉設備文件
close(testdev);
return 0;
}
~~~
????? test_word_count程序可以跟1個命令行參數(多個命令行參數只會使用第1個命令行參數)。如果命令行參數值含有空格,需要使用單引號(')或雙引號(")將參數值括起來。可以使用下面的一組命令測試word_count驅動程序。
~~~
# gcc test_word_count.c -o test_word_count
# test_word_count
# 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驅動。
~~~
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內核。
~~~
# cd ~/kernel/goldfish
# 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,安裝時會出現如下錯誤。
~~~
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文件,并輸入如下的內容。
~~~
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# 指定要編譯的源代碼文件
LOCAL_SRC_FILES:= test_word_count.c
# 指定模塊名,也是編譯后生成的可執行文件名
LOCAL_MODULE := test_word_count
LOCAL_MODULE_TAGS := optional
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 NDK和Java測試Linux驅動](http://blog.csdn.net/nokiaguy/article/details/8671397)
本文節選至[《Android深度探索(卷1):HAL與驅動開發》](http://product.dangdang.com/main/product.aspx?product_id=23043311),接下來幾篇文章將詳細闡述如何開發ARM架構的Linux驅動,并分別利用android程序、NDK、可執行文件測試Linux驅動。可在ubuntu Linux、Android模擬器和S3C6410開發板(可以選購OK6410-A開發板,需要刷Android)