標籤:
第九章心得:
HAL ( Hardware Abstraction Layer,硬體抽象腔,〉是建立在Linux驅動之上的一套翻字型檔。這套程式 j率並不屬於 Linux 核心, 而是屬於 Linux 核心層之上的應用程式層。
加入hal的目的:
(1)統一硬體的調用介面。由於HAL有標準的調用接臥,所以可以利用 HAL屏蔽Linux 驅動複雜,不統一的借口
(2)解決了GPl著作權問題。由於 Linux 核心基於GPL協議,而Android基於Apache Licence 2 .0 ,協議.因此Google玩了個“穿越飛將原本位於 Linux驅動中的敏感代碼向上移了一個層次二 這樣 這些敏感代碼就擺脫了 GPL協議的束縛。那些不想開源的 Linux驅動作者也就沒必要開源了。
(3)針對一些特殊的要求。 對於有些硬體,可能需要訪問→些使用者空間的資源,或在核心空間 不方便完成的工作以及特殊需求。在這種情況下,可以利用位於使用者空間的HAL代碼來輔助Linux 驅動完成一些工作。
為led驅動添加HAL步驟:
第 1 步,編寫 Linux 驅動
“編寫 Linux 驅動”,從表明上看是廢話,但如果要為 Linux 驅動添加 HAL,而且想盡量保護敏 感資料。 Linux 驅動的代碼就要盡量簡潔,儘可能將商務邏輯放到 HALLibrary 中。
第 2 步:編寫 HAL Library HAL Library
HAL Library HAL Library 就是普通的 Linux Library *.so )檔案。但這類庫檔案有一個介面。通過 HAL _MODULE_INFO _ SYM 變數實現。 Service Library 就是通過在這個介面中定義的 ID 定位 HAL Library 的。
第 3 步:編寫 Service Library
儘管這步並不是必需的,但新的 HAL 架構要求我們這樣做。 Service Library 也是 Linux Library。 這一步比較靈活。 Service Library 可以是一般的 Linux Library,也可以識別Library。在本章的 LED 驅動例子中將 Service Libraty和 Library 合到了一起。也就是說, Service Library就是JNI Library. 實際上這一步除了用 CIC件實現的*.so 庫檔案外,還應該包含一個用 Java 編寫的服務管理類 ( ServiceManager)。 ServiceManager會調用 Service Library。而 APK 程式會調用 ServiceManager類米 訪問 Service Library。
第十章心得
列印調試資訊printk。printk 函數在前面的章節己多數使用過。該函數的用法與printf 函數類似,具不過printk 函數 運行在核心空間。
printk是在核心中啟動並執行向控制台輸出顯示的函數 ,linux核心首先在核心空間分配一個靜態緩衝區,作為顯示用的空間,然後調用sprintf,格式化顯示字串,最後調用tty_write向終端進行資訊的顯示。
printk與printf的差異,是什麼導致一個運行在核心態而另一個運行使用者態?其實這兩個函數的幾乎是相同的,出現這種差異是因為tty_write函數需要使用fs指向的被顯示的字串,而fs是專門用於存放使用者態段選擇符的,因此,在核心態時,為了配合tty_write函數,printk會把fs修改為核心態資料區段選擇符ds中的值,這樣才能正確指向核心的資料緩衝區,當然這個操作會先對fs進行壓棧儲存,調用tty_write完畢後再出棧恢複。總結說來,printk與printf的差異是由fs造成的,所以差異也是圍繞對fs的處理。
proc_mkdir
name: 虛擬目錄名稱。
parent: 虛擬目錄父目錄的 proc_dir_entry結構體指標。如果直接在/proc 目錄下建立虛擬目錄,該參數的值為 NULL。
create_proc_entry
name: 虛擬檔案名稱。 mode: 虛擬檔案的存取權限, 等同於 Linux 檔案的存取權限。 parent: 虛擬檔案父目錄的 proc_ dir _ entry 結構體指標。如果直接在/proc 剖錄下建立虛擬 檔案,該參數的值為 NULL。
create_proc_read_entry
name: 虛擬檔案名稱。mode:虛擬檔案的存取權限,等同於 Linux 檔案的存取權限。Base:虛擬檔案父目錄的 proc_ dir _ entry 結構體指標。如果直接在/proc 下建立虛擬檔案, 該參數的值為 NULL。
read_proc:處理讀動作的函數指標。 data: 用於虛擬檔案系統的資料(任意類型的指標〉。該值就是 proc_ dir_entry.read _proc 函數 的最後一個參數值。相當於與某個虛擬檔案永久繫結資料。如果不市要設定該資料,可以為 NULL. remove _proc _ entry 。name: 要刪除的虛擬檔案的名稱。 parent: 虛擬檔案父目錄的 proc_ dir _ entry結構體指釗。如果直接在/proc 目錄下建立虛擬 檔案, 該參數的值為 NULL.
第十一章心得:
中斷屏蔽、原子操作、自旋鎖、 訊號量、 互斥體都 是解決並發問題的機制。中斷屏蔽很少單獨使用,原子操作只能對整數和位進行操作,而自旋鎖、 訊號量、 互斥體的應有比較廣泛。當然,如果強調程式碼片段的執行順序, 可以使用完成量。 自旋鎖會由於不斷自旋而導致死迴圈(也就是死結〉,而且鎖定狀態會造成 臼U 閑置,因此用 自旋鎖保護的臨界區的代碼不能執行時間過長,當然,更不允許臨界區出現阻塞情況。訊號量允許 臨界區阻惑,因此適用於大臨界區的情況. 讀寫↓自旋鎖和讀寫訊號量分別是放寬了條件的自旋鎖和訊號量,它們允許多個執行單元同時對 .共用資源執行讀操作。
Linux中與完成量相關的操作:
(1)定義完成量struct completion my_completion;
(2)初始完成量init_completion(&my_completion);
(3)等待完成量wait_for_completion;
(4)喚醒完成量complete();
Linux 系統中與互斥體相關的操作主要有如下 4 種。
- 定義互斥體
定義互斥體需要使用 mutex 結構體,代碼如下: struc.t mutex my_mutex;
2. 初始化直斥體 如果定義了 mutex 純構體變數F耳以使隔nutex_init函數初始化該變數,
3. 擷取互斥體
4. 釋放放互斥休
訊號量的分類
在學習訊號量之前,我們必須Crowdsourced Security Testing道——Linux提供兩種訊號量:
(1) 核心訊號量,由核心控制路徑使用
(2) 使用者態進程使用的訊號量,這種訊號量又分為POSIX訊號量和SYSTEMV訊號量。
POSIX訊號量又分為有名訊號量和無名訊號量。
有名訊號量,其值儲存在檔案中, 所以它可以用於線程也可以用於進程間的同步。無名訊號量,其值儲存在記憶體中。倘若對訊號量沒有以上的全面認識的話,你就會很快發現自己在訊號量的森林裡迷失了方向。
第十二章心得
阻塞操作是指在執行裝置操作時若不能獲得資源則掛起進程,直到滿足可操作的條件後再進行操作。
因為阻塞的進程會進入休眠狀態,因此,必須確保有一個地方能夠喚醒休眠的進程。喚醒進程的地方最大可能發生在中斷裡面,因為硬體資源獲得的同時往往伴隨著一個中斷。
注意:驅動程式需要提供阻塞(等待隊列,中斷)和非阻塞方式(輪詢,非同步通知)訪問裝置。
休眠(被阻塞)的進程處於一個特殊的不可執行狀態。這點非常重要,否則,沒有這種特殊狀態的話,發送器就可能選出一個本不願意被執行的進程,更糟糕的是,休眠就必須以輪詢的方式實現了。進程休眠有各種原因,但肯定都是為了等待一些事件。事件可能是一段時間、從檔案I/O讀更多資料,或者是某個硬體事件。一個進程還有可能在嘗試獲得一個已經佔用的核心訊號量時被迫進入休眠。休眠的一個常見原因就是檔案I/O -- 如進程對一個檔案執行了read()操作,而這需要從磁碟裡讀取。還有,進程在擷取鍵盤輸入的時候也需要等待。無論哪種情況,核心的操作都相同:進程把它自已標幟成休眠狀態,把自己從可執行隊列移出,放入等待隊列,然後調用schedule()選擇和執行一個其他進程。喚醒的進程剛好相反:進程被設定為可執行狀態,然後再從等待隊列中移到可執行隊列。
休眠有兩種相關的進程狀態:TASK_INTERRUPTIBLE and TASK_UNINTERRUPTIBLE。它們的惟一區別是處於TASK_UNINTERRUPTIBLE狀態的進程會忽略訊號,而處於TASK_INTERRUPTIBLE狀態的進程如果收到訊號會被喚醒並處理訊號(然後再次進入等待睡眠狀態)。兩種狀態的進程位於同一個等待隊列上,等待某些事件,不能夠運行。休眠通過等待隊列進行處理。等待隊列是由等待某些事件發生的進程組成的簡單鏈表。核心用wake_queue_head_t來代表等待隊列。
等待隊列可以通過DECLARE_WAITQUEUE()靜態建立。
也可用init_waitqueue_head()動態建立。進程把自己放入等待隊列中並設定成不可執行狀態。等與等待隊列相關的事件發生的時候,隊列上的進程會被喚醒。為了避免產生競爭條件,休眠和喚醒的實現不能有紕漏。
等待隊列
在Linux驅動程式中,可以使用等待隊列來實現阻塞進程的喚醒。
進程通過執行下面幾步將自己加入到一個等待隊列中:
當然,首先是定義等待隊列頭,並初始化:
(1)wait_queue_head_t wait;
(2)init_waitqueue_head(&wait);
android月考