歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

技術內幕:Android對Linux內核的增強

  【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 ,其中定義了一些Alarm的相關信息。Alarm的類型枚舉如下:

enum android_alarm_type {
    ANDROID_ALARM_RTC_WAKEUP,
    ANDROID_ALARM_RTC,
    ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
    ANDROID_ALARM_ELAPSED_REALTIME,
    ANDROID_ALARM_SYSTEMTIME,
    ANDROID_ALARM_TYPE_COUNT,
};

  主要包括了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 {
    ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
    ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
    ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
                1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
    ANDROID_ALARM_ELAPSED_REALTIME_MASK =
                1U << ANDROID_ALARM_ELAPSED_REALTIME,
    ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
    ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
};

  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 = alarm_suspend,
    .resume = alarm_resume,
    .driver = {
        .name = "alarm"
    }
};

  該參數主要指定了當系統掛起(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 = {
    .add_dev = &rtc_alarm_add_device,
    .remove_dev = &rtc_alarm_remove_device,
};

  如果在此過程中出現錯誤,那麼需要銷毀已經注冊的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)
{
    unsigned long   flags;
    struct timespec system_time;

    spin_lock_irqsave(&alarm_slock, flags);

    getnstimeofday(&elapsed_rtc_delta);
    ktime_get_ts(&system_time);
    elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, system_time);

    spin_unlock_irqrestore(&alarm_slock, flags);

    ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
        "alarm_late_init: rtc to elapsed realtime delta %ld.%09ld\n",
        elapsed_rtc_delta.tv_sec, elapsed_rtc_delta.tv_nsec);
    return 0;
}

  3.alarm_exit

  當Alarm退出時,就需要通過class_interface_unregister函數來卸載在初始化時注冊的Alarm接口,通過wake_lock_destroy函數來銷毀SUSPEND lock,以及通過platform_driver_unregister函數來卸載Alarm驅動。實現代碼如下:

static void  __exit alarm_exit(void)
{
    class_interface_unregister(&rtc_alarm_interface);
    wake_lock_destroy(&alarm_rtc_wake_lock);
    wake_lock_destroy(&alarm_wake_lock);
    platform_driver_unregister(&alarm_driver);
}

  4.添加和移除設備

  接下來是rtc_alarm_add_device和rtc_alarm_remove_device函數的實現。添加設備時,首先將設備轉換成rtc_device類型,然後,通過misc_register函數將自己注冊成為一個Misc設備。其包括的主要特性如下面的代碼所示:

static struct file_operations alarm_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = alarm_ioctl,
    .open = alarm_open,
    .release = alarm_release,
};

static struct miscdevice alarm_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "alarm",
    .fops = &alarm_fops,
};

  其中alarm_device中的“.name”表示設備文件名稱,而alarm_fops則定義了Alarm的常用操作,包括打開、釋放和I/O控制。這裡還需要通過rtc_irq_register函數注冊一個rtc_task,用來處理Alarm觸發的方法,其定義如下:

static struct rtc_task alarm_rtc_task = {
    .func = alarm_triggered_func
};

  其中“alarm_triggered_func”則是Alarm需要觸發的方法。

  注意 如果在添加設備的過程中出現錯誤,我們需要對已經執行的操作進行釋放、銷毀和卸載。但是,移除一個設備時同樣需要判斷設備是否是Alarm設備,然後再執行卸載等操作。另外,在處理掛起操作時,我們首先就需要對設備進行鎖定,然後根據Alarm的類型執行不同的操作,同時要保存時間。

  alarm_open和alarm_release的實現很簡單。最後需要說明的是,對於I/O操作而言,主要需要實現:設置時間、設置RTC、獲取時間、設置Alarm等待等。

  本小節主要對Android中最簡單的設備驅動——Alarm的實現流程進行了分析,大家應該可以自己繪制出一個流程圖來了吧。對於Alarm的具體實現,大家可以參考源代碼“drivers/rtc/alarm.c”中的實現方式。

上一頁1234下一頁查看全文 內容導航
  • 第1頁:Alarm(硬件時鐘)
  • 第2頁:Ashmem(匿名內存共享)
  • 第3頁:Low Memory Killer(低內存管理)
  • 第4頁:Logger(日志設備)
Copyright © Linux教程網 All Rights Reserved