文章目錄
- 一、使用Ubuntu Linux測試Linux驅動
- 二、在Android模擬器上通過原生(Native)C程式測試Linux驅動
開發可統計單詞個數的Android驅動程式
在上一篇文章中已經實現了一個簡單的Linux驅動程式,該驅動的功能是統計給定字串中的單詞數。並且在最後已經將該Linux驅動的原始碼成功編譯成動態Linux驅動模組word_count.ko。下一步就是測試該模組。測試的方法很多,最常用的就是直接在Ubuntu Linux、Android模擬器中測試。當然,這 對於本章實現的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表示建立可執行檔檔案。可執行檔路徑是<Android原始碼目錄>/ out/target/product/generic/system/bin/test_word_count。如果想編譯成動態庫(.so)檔案,可 以使用include $(BUILD_SHARED_LIBRARY)。動態庫的路徑是<Android原始碼目錄>/ out/target/product/generic/system/lib/test_word_count.so。如果想編譯成靜態庫(.a)文 件,可以使用include $(BUILD_STATIC_LIBRARY)。靜態庫的路徑是<Android原始碼目錄>/ out/target/product/generic/obj/STATIC_LIBRARIES/test_word_count_intermediates/test_word_count.
為了將test_word_count.c檔案編譯成可在Android模擬器上啟動並執行可執行程式,可以將word_count目錄複寫 到<Android原始碼目錄>的某個子目錄,也可以在<Android原始碼目錄>目錄中為word_count目錄建立一個 符號連結。為了方便,我們採用如下命令為word_count目錄在<Android原始碼目錄>/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
成功編譯後可以在<Android原始碼目錄>/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驅動
本文節選至《Android深度探索(卷1):HAL與驅動開發》, 接下來幾篇文章將詳細闡述如何開發ARM架構的Linux驅動,並分別利用android程式、NDK、可執行檔測試Linux驅動。可在ubuntu Linux、Android模擬器和S3C6410開發板(可以選購OK6410-A開發板,需要刷Android)