1. 程式人生 > >編譯和測試android的驅動程式學習筆記

編譯和測試android的驅動程式學習筆記

0x00 前言

    通過這篇文章,我們可以詳細的掌握android驅動程式的編譯以及對其進行測試的知識點,這裡採用goldfish核心並且在android模擬器上進行測試。

0x01 準備

       首先我們應該瞭解怎麼樣下載和編譯android下面的linux核心,推薦一篇文章,寫的很詳細:http://bbs.pediy.com/showthread.php?t=192746 .。其次,由於用於android模擬器的goldfish核心預設是不允許動態載入linux驅動模組的,為了方便後面我們要講到的測試動態載入的驅動模組,我們這裡需要先配置goldfish核心允許動態載入linux驅動模組,具體方法是切換到goldfish核心根目錄下執行:

make menuconfig
執行上面的命令後,會出現如下圖所示的設定介面,按空格鍵將第二項“Enable loadable module support”選中(前面是【×】)


然後按回車鍵進入其子選單,將前三項選中,如下圖:

然後儲存退出。

0x02 編寫驅動程式以及配置檔案

新建一個目錄用於存放驅動程式和配置檔案,檔案目錄結構如下圖:


其中,各檔案內容如下:

Makefile:

ifndef CONFIG_WORD_ECHO
	obj-m := word_echo.o
else
	obj-${CONFIG_WORD_ECHO} := word_echo.o
endif
Kconfig:
config WORD_ECHO
	tristate "word_echo driver"
	default y
	help
		This is a word echo driver,it can echo what you write
word_echo.c:
#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/miscdevice.h>  
#include <asm/uaccess.h>  
   
#define DEVICE_NAME "word_echo"         //  定義裝置檔名  
static unsigned char mem[10000];                //  儲存向裝置檔案寫入的資料  
static char read_flag = 'y';                    //  y:已從裝置檔案讀取資料   n:未從裝置檔案讀取資料  
static int written_count = 0;                   // 向裝置檔案寫入資料的位元組數  
   
//  從裝置檔案讀取資料時呼叫該函式  
//  file:指向裝置檔案、buf:儲存可讀取的資料   count:可讀取的位元組數  ppos:讀取資料的偏移量  
static ssize_t word_echo_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  
{     
    //  如果還沒有讀取裝置檔案中的資料,可以進行讀取  
    if(read_flag == 'n')  
    {     
        //  將核心空間的資料複製到使用者空間,buf中的資料就是從裝置檔案中讀出的資料  
        copy_to_user(buf, (void*) mem, written_count);  
        //  向日志輸出已讀取的位元組數  
        printk("read count:%d", (int) written_count);  
        //  設定資料已讀狀態  
        read_flag = 'y';  
        return written_count;  
    }  
    //  已經從裝置檔案讀取資料,不能再次讀取資料  
    else 
    {     
        return 0;  
    }  
}  
//  向裝置檔案寫入資料時呼叫該函式  
//  file:指向裝置檔案、buf:儲存寫入的資料   count:寫入資料的位元組數  ppos:寫入資料的偏移量  
static ssize_t word_echo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)  
{     
    //  將使用者空間的資料複製到核心空間,mem中的資料就是向裝置檔案寫入的資料  
    copy_from_user(mem, buf, count);  
    //  設定資料的未讀狀態  
    read_flag = 'n';  
    //  儲存寫入資料的位元組數  
    written_count = count;  
    //  向日志輸出已寫入的位元組數  
    printk("written count:%d", (int)count);  
    return count;  
}  
//  描述與裝置檔案觸發的事件對應的回撥函式指標  
//  需要設定read和write成員變數,系統才能呼叫處理讀寫裝置檔案動作的函式  
static struct file_operations dev_fops =  
{ .owner = THIS_MODULE, .read = word_echo_read, .write = word_echo_write };  
   
//  描述裝置檔案的資訊  
static struct miscdevice misc =  
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops };  
   
//  初始化Linux驅動  
static int word_echo_init(void)  
{  
    int ret;  
    //  建立裝置檔案  
    ret = misc_register(&misc);  
    //  輸出日誌資訊  
    printk("word_echo_init_success\n");  
    return ret;  
}  
   
// 解除安裝Linux驅動  
static void word_echo_exit(void)  
{  
    //  刪除裝置檔案  
    misc_deregister(&misc);  
    //  輸出日誌資訊  
    printk("word_echo_exit_success\n");  
}  
   
//  註冊初始化Linux驅動的函式  
module_init( word_echo_init);  
//  註冊解除安裝Linux驅動的函式  
module_exit( word_echo_exit);  
   
MODULE_AUTHOR("parkerpeng");  
MODULE_DESCRIPTION("just echo word which you write in!");  
MODULE_ALIAS("word echo module.");  
MODULE_LICENSE("GPL");  

然後將上述目錄建立一個軟連結到${kernel_home}/drvicers/char/目錄下(當然你也可以直接在${kernel_home}/drvicers/char/下建立word_ehco目錄,就可以省去建立軟連結這一步,這裡我把目錄放在了其它地方,以便於我自己程式碼管理),如下:

ln -s   ~/src/android/kernel/mydrivers/word_echo   /home/parker/src/android/kernel/goldfish/drivers/char/word_echo

0x03 修改核心配置檔案

        為了能讓make命令找到word_echo目錄中的Kconfig以及Makefile,我們需要修改上級目錄也就是${kernel_home}/drivers/char/中的Kconfig以及Makefile檔案,讓他們包含word_echo目錄下的Kconfig以及Makefile。

開啟${kernel_home}/drivers/char/目錄下的Kconfig,在檔案末尾“endmenu”之前新增如下一行程式碼:

source "drivers/char/word_echo/Kconfig"
開啟${kernel_home}/drivers/char/目錄下的Makefile,在新增如下一行:
obj-$(CONFIG_WORD_ECHO)		+= word_echo/

然後我們需要修改核心根目錄下.config檔案,新增CONFIG_WORD_ECHO變數並且給它賦值,這些值可以是:

m:將驅動編譯成可供核心動態載入的ko模組

y:將驅動編譯進核心

n:將該驅動從核心剔除

可以手動在.config檔案中給CONFIG_WORD_EHCO賦值,也可以通過在核心根目錄下輸入make menuconfig命令給它賦值,它會自動修改.config檔案中的該變數。

輸入make menuconfig命令後,選擇“Device Driver”---------->“Character devices”---------->"word_echo driver",按空格鍵在<>,<*>,<M>三種值之間切換,它們分別表示上述的n,y,m三個值,如下圖所示:

這裡選擇將驅動模組編譯進核心,儲存設定後,就可以切換到核心根目錄下執行make命令進行編譯了。

0x04 測試驅動程式

由於前面選擇的是將驅動程式編譯進核心,因此核心會自動載入該驅動程式,在${kernel_home}/arch/arm/boot目錄下找到編譯好的核心zimage,執行以下命令執行模擬器:

emulator -avd AVD_XXXX -kernel zImage -system system.img -data userdata.img -ramdisk ramdisk.img
上面命令中system.img,userdata.img,ramdisk.img是我在編譯好的android4.4.2檔案

接著進入adb shell,測試結果如下圖所示: