Android系統(tǒng)的開機畫面顯示過程分析 |
發(fā)布時間: 2012/8/30 17:29:52 |
好幾個月都沒有更新過博客了,從今天開始,老羅將嘗試對Android系統(tǒng)的UI實現(xiàn)作一個系統(tǒng)的分析,也算是落實之前所作出的承諾。提到Android系統(tǒng)的UI,我們最先接觸到的便是系統(tǒng)在啟動過程中所出現(xiàn)的畫面了。Android系統(tǒng)在啟動的過程中,最多可以出現(xiàn)三個畫面,每一個畫面都用來描述一個不同的啟動階段。本文將詳細分析這三個開機畫面的顯示過程,以便可以開啟我們對Android系統(tǒng)UI實現(xiàn)的分析之路。
第一個開機畫面是在內(nèi)核啟動的過程中出現(xiàn)的,它是一個靜態(tài)的畫面。第二個開機畫面是在init進程啟動的過程中出現(xiàn)的,它也是一個靜態(tài)的畫面。第三個開機畫面是在系統(tǒng)服務(wù)啟動的過程中出現(xiàn)的,它是一個動態(tài)的畫面。無論是哪一個畫面,它們都是在一個稱為幀緩沖區(qū)(frame buffer,簡稱fb)的硬件設(shè)備上進行渲染的。接下來,我們就分別分析這三個畫面是如何在fb上顯示的。
1. 第一個開機畫面的顯示過程
Android系統(tǒng)的第一個開機畫面其實是Linux內(nèi)核的啟動畫面。在默認情況下,這個畫面是不會出現(xiàn)的,除非我們在編譯內(nèi)核的時候,啟用以下兩個編譯選項:
CONFIG_FRAMEBUFFER_CONSOLE
CONFIG_LOGO
第一個編譯選項表示內(nèi)核支持幀緩沖區(qū)控制臺,它對應(yīng)的配置菜單項為:Device Drivers ---> Graphics support ---> Console display driver support ---> Framebuffer Console support。第二個編譯選項表示內(nèi)核在啟動的過程中,需要顯示LOGO,它對應(yīng)的配置菜單項為:Device Drivers ---> Graphics support ---> Bootup logo。配置Android內(nèi)核編譯選項可以參考在Ubuntu上下載、編譯和安裝Android最新內(nèi)核源代碼(Linux Kernel)一文。
幀緩沖區(qū)硬件設(shè)備在內(nèi)核中有一個對應(yīng)的驅(qū)動程序模塊fbmem,它實現(xiàn)在文件kernel/goldfish/drivers/video/fbmem.c中,它的初始化函數(shù)如下所示:
這個函數(shù)首先調(diào)用函數(shù)proc_create在/proc目錄下創(chuàng)建了一個fb文件,接著又調(diào)用函數(shù)register_chrdev來注冊了一個名稱為fb的字符設(shè)備,最后調(diào)用函數(shù)class_create在/sys/class目錄下創(chuàng)建了一個graphics目錄,用來描述內(nèi)核的圖形系統(tǒng)。
模塊fbmem除了會執(zhí)行上述初始化工作之外,還會導(dǎo)出一個函數(shù)register_framebuffer:
這個函數(shù)在內(nèi)核的啟動過程會被調(diào)用,以便用來執(zhí)行注冊幀緩沖區(qū)硬件設(shè)備的操作,它的實現(xiàn)如下所示:
由于系統(tǒng)中可能會存在多個幀緩沖區(qū)硬件設(shè)備,因此,fbmem模塊使用一個數(shù)組registered_fb保存所有已經(jīng)注冊了的幀緩沖區(qū)硬件設(shè)備,其中,每一個幀緩沖區(qū)硬件都是使用一個結(jié)構(gòu)體fb_info來描述的。
我們知道,在Linux內(nèi)核中,每一個硬件設(shè)備都有一個主設(shè)備號和一個從設(shè)備號,它們用來唯一地標識一個硬件設(shè)備。對于幀緩沖區(qū)硬件設(shè)備來說,它們的主設(shè)備號定義為FB_MAJOR(29),而從設(shè)備號則與注冊的順序有關(guān),它們的值依次等于0,1,2等。
每一個被注冊的幀緩沖區(qū)硬件設(shè)備在/dev/graphics目錄下都有一個對應(yīng)的設(shè)備文件fb<minor>,其中,<minor>表示一個從設(shè)備號。例如,第一個被注冊的幀緩沖區(qū)硬件設(shè)備在/dev/graphics目錄下都有一個對應(yīng)的設(shè)備文件fb0。用戶空間的應(yīng)用程序通過這個設(shè)備文件就可以操作幀緩沖區(qū)硬件設(shè)備了,即將要顯示的畫面渲染到幀緩沖區(qū)硬件設(shè)備上去。
這個函數(shù)最后會通過調(diào)用函數(shù)fb_notifier_call_chain來通知幀緩沖區(qū)控制臺,有一個新的幀緩沖區(qū)設(shè)備被注冊到內(nèi)核中來了。
幀緩沖區(qū)控制臺在內(nèi)核中對應(yīng)的驅(qū)動程序模塊為fbcon,它實現(xiàn)在文件kernel/goldfish/drivers/video/console/fbcon.c中,它的初始化函數(shù)如下所示:
這個函數(shù)除了會調(diào)用函數(shù)device_create來創(chuàng)建一個類別為graphics的設(shè)備fbcon之外,還會調(diào)用函數(shù)fb_register_client來監(jiān)聽幀緩沖區(qū)硬件設(shè)備的注冊事件,這是由函數(shù)fbcon_event_notify來實現(xiàn)的,如下所示:
幀緩沖區(qū)硬件設(shè)備的注冊事件最終是由函數(shù)fbcon_fb_registered來處理的,它的實現(xiàn)如下所示:
函數(shù)fbcon_select_primary用來檢查當(dāng)前注冊的幀緩沖區(qū)硬件設(shè)備是否是一個主幀緩沖區(qū)硬件設(shè)備。如果是的話,那么就將它的信息記錄下來。這個函數(shù)只有當(dāng)指定了CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY編譯選項時才有效,否則的話,它是一個空函數(shù)。
在Linux內(nèi)核中,每一個控制臺和每一個幀緩沖區(qū)硬件設(shè)備都有一個從0開始的編號,它們的初始對應(yīng)關(guān)系保存在全局數(shù)組con2fb_map_boot中?刂婆_和幀緩沖區(qū)硬件設(shè)備的初始對應(yīng)關(guān)系是可以通過設(shè)置內(nèi)核啟動參數(shù)來初始化的。在模塊fbcon中,還有另外一個全局數(shù)組con2fb_map,也是用來映射控制臺和幀緩沖區(qū)硬件設(shè)備的對應(yīng)關(guān)系,不過它映射的是控制臺和幀緩沖區(qū)硬件設(shè)備的實際對應(yīng)關(guān)系。
全局變量first_fb_vc和last_fb_vc是全局數(shù)組con2fb_map_boot和con2fb_map的索引值,用來指定系統(tǒng)當(dāng)前可用的控制臺編號范圍,它們也是可以通過設(shè)置內(nèi)核啟動參數(shù)來初始化的。全局變量first_fb_vc的默認值等于0,而全局變量last_fb_vc的默認值等于MAX_NR_CONSOLES - 1。
全局變量info_idx表示系統(tǒng)當(dāng)前所使用的幀緩沖區(qū)硬件的編號。如果它的值等于-1,那么就說明系統(tǒng)當(dāng)前還沒有設(shè)置好當(dāng)前所使用的幀緩沖區(qū)硬件設(shè)備。在這種情況下,函數(shù)fbcon_fb_registered就會在全局數(shù)組con2fb_map_boot中檢查是否存在一個控制臺編號與當(dāng)前所注冊的幀緩沖區(qū)硬件設(shè)備的編號idx對應(yīng)。如果存在的話,那么就會將當(dāng)前所注冊的幀緩沖區(qū)硬件設(shè)備編號idx保存在全局變量info_idx中。接下來還會調(diào)用函數(shù)fbcon_takeover來初始化系統(tǒng)所使用的控制臺。在調(diào)用函數(shù)fbcon_takeover的時候,傳進去的參數(shù)為1,表示要顯示第一個開機畫面。
如果全局變量info_idx的值不等于-1,那么函數(shù)fbcon_fb_registered同樣會在全局數(shù)組con2fb_map_boot中檢查是否存在一個控制臺編號與當(dāng)前所注冊的幀緩沖區(qū)硬件設(shè)備的編號idx對應(yīng)。如果存在的話,那么就會調(diào)用函數(shù)set_con2fb_map來調(diào)整當(dāng)前所注冊的幀緩沖區(qū)硬件設(shè)備與控制臺的映射關(guān)系,即調(diào)整數(shù)組con2fb_map_boot和con2fb_map的值。
為了簡單起見,我們假設(shè)系統(tǒng)只有一個幀緩沖區(qū)硬件設(shè)備,這樣當(dāng)它被注冊的時候,全局變量info_idx的值就會等于-1。當(dāng)函數(shù)fbcon_fb_registered在全局數(shù)組con2fb_map_boot中發(fā)現(xiàn)有一個控制臺的編號與這個幀緩沖區(qū)硬件設(shè)備的編號idx對應(yīng)時,接下來就會調(diào)用函數(shù)fbcon_takeover來設(shè)置系統(tǒng)所使用的控制臺。
函數(shù)fbcon_takeover的實現(xiàn)如下所示:
全局變量logo_shown的初始值為FBCON_LOGO_CANSHOW,表示可以顯示第一個開機畫面。但是當(dāng)參數(shù)show_logo的值等于0的時候,全局變量logo_shown的值會被重新設(shè)置為FBCON_LOGO_DONTSHOW,表示不可以顯示第一個開機畫面。
中間的for循環(huán)將當(dāng)前可用的控制臺的編號都映射到當(dāng)前正在注冊的幀緩沖區(qū)硬件設(shè)備的編號info_idx中去,表示當(dāng)前可用的控制臺與緩沖區(qū)硬件設(shè)備的實際映射關(guān)系。
函數(shù)take_over_console用來初始化系統(tǒng)當(dāng)前所使用的控制臺。如果它的返回值不等于0,那么就表示初始化失敗。在這種情況下,最后的for循環(huán)就會將全局數(shù)組con2fb_map的各個元素的值設(shè)置為-1,表示系統(tǒng)當(dāng)前可用的控制臺還沒有映射到實際的幀緩沖區(qū)硬件設(shè)備中去。這時候全局變量info_idx的值也會被重新設(shè)置為-1。
調(diào)用函數(shù)take_over_console來初始化系統(tǒng)當(dāng)前所使用的控制臺,實際上就是向系統(tǒng)注冊一系列回調(diào)函數(shù),以便系統(tǒng)可以通過這些回調(diào)函數(shù)來操作當(dāng)前所使用的控制臺。這些回調(diào)函數(shù)使用結(jié)構(gòu)體consw來描述。這里所注冊的結(jié)構(gòu)體consw是由全局變量fb_con來指定的,它的定義如下所示:
本文出自:億恩科技【1tcdy.com】 服務(wù)器租用/服務(wù)器托管中國五強!虛擬主機域名注冊頂級提供商!15年品質(zhì)保障!--億恩科技[ENKJ.COM] |