【IT168技術】IT168移動頻道在之前的技術文章中曾經介紹過Android對Linux內核的改動,本文將重點介紹Android對Linux內核的增強,主要包括Alarm(硬件時鐘)、Ashmem(匿名內存共享)、Low Memory Killer(低內存管理)、Logger(日志設備),等等,讓大家全方位了解為何Android能將Linux內核在移動領域運用的如此精湛,可以和蘋果相抗衡。
Alarm(硬件時鐘)
Alarm就是一個硬件時鐘,前面我們已經知道它提供了一個定時器,用於把設備從睡眠狀態喚醒,同時它也提供了一個在設備睡眠時仍然會運行的時鐘基准。在應用層上,有關時間的應用都需要Alarm的支持,源代碼位於“drivers/rtc/alarm.c”。
Alarm的設備名為“/dev/alarm”。該設備的實現非常簡單,我們首先打開源碼,可以看到include
主要包括了5種類型的Alarm,_WAKEUP類型表示在觸發Alarm時需要喚醒設備,反之則不需要喚醒設備;ANDROID_ALARM_RTC類型表示在指定的某一時刻出發Alarm;ANDROID_ALARM_ELAPSED_REALTIME表示在設備啟動後,流逝的時間達到總時間之後觸發Alarm;ANDROID_ALARM_SYSTEMTIME類型則表示系統時間;ANDROID_ALARM_ TYPE_COUNT則是Alram類型的計數。
注意 流逝的時間也包括設備睡眠的時間,流逝時間的計算點從它最後一次啟動算起。
Alarm返回標記的枚舉類型如下:
enum android_alarm_return_flags {Alarm返回標記會隨著Alarm的類型而改變。最後還定義了一些宏,主要包括禁用Alarm、Alarm等待、設置Alarm等。下面我們來分析Alarm驅動的具體實現。
首先,Alarm的初始化及退出由以下三個函數來完成:
late_initcall(alarm_late_init);
module_init(alarm_init);
module_exit(alarm_exit);
其中alarm_init函數對Alarm執行初始化操作,alarm_late_init需要在初始化完成之後進行調用,最後退出時需要調用alarm_exit來銷毀和卸載Alarm接口及驅動。
1.alarm_init
在初始化過程中,首先需要初始化系統時間,通過platform_driver_register函數來注冊Alarm驅動的相關參數,具體如下所示:
static struct platform_driver alarm_driver = {該參數主要指定了當系統掛起(suspend)和喚醒(Desume)所需要實現的分別為alarm_suspend和alarm_resume,同時將Alarm設備驅動的名稱設置為了“alarm”。
如果設置正確,那麼繼續通過如下代碼來初始化SUSPEND lock,因為在使用它們之前必須執行初始化操作。
wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
緊接著通過class_interface_register函數來注冊Alarm接口信息,主要包括設備的添加和移除操作,內容如下:
static struct class_interface rtc_alarm_interface = {如果在此過程中出現錯誤,那麼需要銷毀已經注冊的SUSPEND lock,並且卸載Alarm驅動,代碼如下:
wake_lock_destroy(&alarm_rtc_wake_lock);
wake_lock_destroy(&alarm_wake_lock);
platform_driver_unregister(&alarm_driver);
注意 wake lock是一種鎖機制,只要有用戶持有該鎖,系統就無法進入休眠狀態,該鎖可以被用戶態程序和內核獲得。這個鎖可以是超時的或者是沒有超時的,超時的鎖會在時間過期以後自動解鎖。如果沒有鎖或者超時了,內核就會啟動休眠機制進入休眠狀態,後面在講電源管理時還會進一步講解該機制。
2.alarm_late_init
當Alarm啟動之後,我們需要讀取當前的RCT和系統時間,由於需要確保在這個操作過程中不被中斷,或者在中斷之後能告訴其他進程該過程沒有讀取完成,不能被請求,因此這裡需要通過spin_lock_irqsave和spin_unlock_irqrestore來對其執行鎖定和解鎖操作。實現代碼如下:
static int __init alarm_late_init(void)3.alarm_exit
當Alarm退出時,就需要通過class_interface_unregister函數來卸載在初始化時注冊的Alarm接口,通過wake_lock_destroy函數來銷毀SUSPEND lock,以及通過platform_driver_unregister函數來卸載Alarm驅動。實現代碼如下:
static void __exit alarm_exit(void)4.添加和移除設備
接下來是rtc_alarm_add_device和rtc_alarm_remove_device函數的實現。添加設備時,首先將設備轉換成rtc_device類型,然後,通過misc_register函數將自己注冊成為一個Misc設備。其包括的主要特性如下面的代碼所示:
static struct file_operations alarm_fops = {其中alarm_device中的“.name”表示設備文件名稱,而alarm_fops則定義了Alarm的常用操作,包括打開、釋放和I/O控制。這裡還需要通過rtc_irq_register函數注冊一個rtc_task,用來處理Alarm觸發的方法,其定義如下:
static struct rtc_task alarm_rtc_task = {其中“alarm_triggered_func”則是Alarm需要觸發的方法。
注意 如果在添加設備的過程中出現錯誤,我們需要對已經執行的操作進行釋放、銷毀和卸載。但是,移除一個設備時同樣需要判斷設備是否是Alarm設備,然後再執行卸載等操作。另外,在處理掛起操作時,我們首先就需要對設備進行鎖定,然後根據Alarm的類型執行不同的操作,同時要保存時間。
alarm_open和alarm_release的實現很簡單。最後需要說明的是,對於I/O操作而言,主要需要實現:設置時間、設置RTC、獲取時間、設置Alarm等待等。
本小節主要對Android中最簡單的設備驅動——Alarm的實現流程進行了分析,大家應該可以自己繪制出一個流程圖來了吧。對於Alarm的具體實現,大家可以參考源代碼“drivers/rtc/alarm.c”中的實現方式。
上一頁1234下一頁查看全文 內容導航