




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、android系統(tǒng)啟動流程android系統(tǒng)啟動流程 從init進(jìn)程開始到systemserver 目錄android系統(tǒng)啟動流程1從init進(jìn)程開始到systemserver11.概述:22 系統(tǒng)啟動基本原理33 Init進(jìn)程解析53.1/system/core/init/init.c分析53.2 核心任務(wù)一:各種初始化73.3核心任務(wù)二: 解析和執(zhí)行init.rc文件73.4核心任務(wù)三:執(zhí)行command,監(jiān)控service重啟h和socket請求123.5疑問:傳說中的zygote進(jìn)程啟動在 哪里?124 認(rèn)識和解析init.rc的內(nèi)容134.1認(rèn)識AIL語言寫成的init.
2、rc134.1.1 行(line)的概念134.1.2 段(section)的概念134.1.3 動作(action)和服務(wù)(service)的概念目前init.rc內(nèi)已經(jīng)寫入的主要的action和service Actions和command的語法格式:服務(wù)(services)和選項(option)語法174.2解析init.rc過程194.2.1init_parse_config_file和parse_config194.2.2 next_token214.2.3 lookup_keyword、kw_is和keywords.h254.2
3、.4 parse_new_section305 zygote的啟動335.1 zygote在init.rc中的啟動流程:335.1.1 zygote在init.rc中配置為class main335.1.2 on boot這個action會執(zhí)行class_start main335.1.3 class_start main對應(yīng)執(zhí)行函數(shù)do_class_start:335.2 do_class_start真正啟動zygote355.2.1 do_class_start分析:355.2.2 service_for_each_class分析355.2.3 service_start_if_not_d
4、isabled分析:365.2.4 service_start分析:366 zygote進(jìn)程分析406.1 分析app_process改名為zygote及其main函數(shù) 流程406.2 AndroidRuntime啟動dalvik虛擬機和ZygoteInit類426.3 分析ZygoteInit 類:436.3.1 注冊socket -registerZygoteSocket分析446.3.2 加載資源-preload456.3.3啟動systemserver466.3.4啟動消息循環(huán):runSelectLoop486.3.5 zygote最終進(jìn)化為所有app進(jìn)程的父進(jìn)程497 總結(jié):511.
5、概述: Linux內(nèi)核啟動之后,執(zhí)行第一個進(jìn)程 Init,并最終到達(dá)systemserver,systemserver再往上啟動framework層相關(guān)服務(wù)和進(jìn)程,啟動launcher,完成整個開機流程。 init進(jìn)程之前和systemserver啟動之后的動作,本文不做分析,專著分析從init到systemserver之間的流程。本文的核心: init進(jìn)程工作內(nèi)容分 init.rc內(nèi)容和執(zhí)行分析 zygote啟動和內(nèi)容分析 systemserver啟動和內(nèi)容簡析android系統(tǒng)啟動流程圖:2 系統(tǒng)啟動基本原理 關(guān)鍵詞:內(nèi)核空間和用戶空間(關(guān)于內(nèi)核空間和應(yīng)用空間的詳細(xì)描述(可以參考Andro
6、id深度探索(卷1):HAL與驅(qū)動開發(fā)) 1)內(nèi)核空間 Android本質(zhì)上就是一個基于Linux內(nèi)核的操作系統(tǒng)+龐雜的上層應(yīng)用。一個完整的Linux系統(tǒng)首先會將一個Linux內(nèi)核裝載到內(nèi)存,也就是編譯Linux內(nèi)核源代碼生成的bzImage文件,對于為Android優(yōu)化的Linux內(nèi)核源代碼會生成zImage文件。該文件就是Linux內(nèi)核的二進(jìn)制版本,zImage在內(nèi)核空間運行。內(nèi)核空間簡而言之就是內(nèi)核kernel的非用戶user能控制的運行空間。 2)應(yīng)用空間 而我們平常使用的軟件都是在應(yīng)用空間運行,這部分空間,用戶可以自己分配進(jìn)程所需內(nèi)存
7、和其他資源。 3)兩個空間需要通訊 內(nèi)核空間和應(yīng)用空間是不能直接通過內(nèi)存地址級別訪問的,所以就需要建立某種通訊機制。 目前Linux有很多通訊機制可以在用戶空間和內(nèi)核空間之間交互,例如設(shè)備驅(qū)動文件(位于/dev目錄中)、內(nèi)存文件(/proc、/sys目錄等)。了解Linux的同學(xué)都應(yīng)該知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一個設(shè)備通常與一個或多個設(shè)備文件對應(yīng)。這些與內(nèi)核空間交互的文件都在用戶空間。 注意:/dev,/proc,/sys這些設(shè)備文件路徑,在系統(tǒng)編譯完的img文件中是不存在的,所以原生的系統(tǒng)是沒有他們的。 在
8、Linux內(nèi)核裝載完,需要首先建立這些設(shè)備文件所在的目錄,而完成這些工作的程序就是本文要介紹的內(nèi)容之一:init進(jìn)程。 init進(jìn)程,它是一個由內(nèi)核啟動的用戶級進(jìn)程。內(nèi)核自行啟動之后,就通過啟動一個用戶級程序init的方式,完成引導(dǎo)進(jìn)程。init始終是第一個進(jìn)程,執(zhí)行了:文件夾建立,掛載,rc文件解析,屬性設(shè)置,啟動服務(wù),socket監(jiān)聽,啟動zygote進(jìn)程和servicemanager進(jìn)程等。 4)zygote是所有java進(jìn)程的父進(jìn)程:zygote進(jìn)程被init啟動起來,再往上啟動systemserver,并隨時等待其他java進(jìn)程請求,負(fù)責(zé)java進(jìn)程的真正的創(chuàng)建和入口函數(shù)的執(zhí)行。 所
9、以我們很有必要搞清楚,zygote到底是怎么啟動的以及他自身的工作原理。3 Init進(jìn)程解析3.1/system/core/init/init.c分析 其中init.c是init的主文件,由于init是命令行程序,所以分析init.c首先應(yīng)從main函數(shù)開始,現(xiàn)在好到main函數(shù),代碼如下: 注意:下面這段截圖的代碼本來是在for循環(huán)中,但是為了更直觀地看到for循環(huán)所做的工作,特意把這段代碼提出來. 我們可以看到main函數(shù)的邏輯并不復(fù)雜,但是信息量很大,通常只需要了解init的主線
10、即可。main函數(shù)的主要任務(wù)包括以下3個部分:1)初始化(包括建立/dev、/proc等目錄、初始化屬性)。2)解析和執(zhí)行init.rc(以及init.rc加載的其他rc文件)文件中的各commond。3)使用for無限循環(huán)執(zhí)行rc文件的command,監(jiān)控service進(jìn)程的重啟,響應(yīng)系統(tǒng)屬性等上層修改請求。 3.2 核心任務(wù)一:各種初始化 設(shè)備文件目錄的創(chuàng)建很直觀,就不做分析了,這里主要分析下property進(jìn)程初始化。從上面的main函數(shù)分析中,大家可以看到依次調(diào)用了4個property相關(guān)的函數(shù)1)初始化property全局內(nèi)存和工作空間2)加載根目錄下的defa
11、p文件的全部屬性#define PROP_PATH_RAMDISK_DEFAULT "/p"3)加載其余4個屬性文件的全部屬性,并啟動socket監(jiān)聽#define PROP_PATH_SYSTEM_BUILD "/system/p"#define PROP_PATH_SYSTEM_DEFAULT "/system/p"#define PROP_PATH_LOCAL_OVERRIDE "/data/p"#define PE
12、RSISTENT_PROPERTY_DIR "/data/property"4)將init.rc這里rc腳本文件解析出來的所有和property相關(guān)的action動作加入執(zhí)行隊列這個任務(wù)先簡單介紹到這里,這不是本文的主旨,要詳細(xì)了解系統(tǒng)屬性property的相關(guān)知識,可以參考另外一篇筆記android系統(tǒng)屬性詳解。3.3核心任務(wù)二: 解析和執(zhí)行init.rc文件 這里的配置文件主要指init.rc。我們所看到的init.rc實際上僅僅是kernel加載到內(nèi)存中的鏡像(真實的init.rc實際被打包到boot.ima
13、ge中去了)。要想修改rc的內(nèi)容,只有修改源文件,并重新編譯和燒寫。 init.rc代碼路徑: systemcorerootdirinit.rc 終端根目錄下ls可以看到有以下相關(guān)rc文件:現(xiàn)在回到main函數(shù),啟動解析init.rc的代碼是:進(jìn)入systemcoreinit init_parser.c 下的init_parse_config_file函數(shù):進(jìn)入systemcoreinit init_parser.c 下的parse_config函數(shù):注意: 1) 解析rc文件中所有的action,token,ketwork,section,service等:一直跟蹤parse_new_sec
14、tion,會發(fā)現(xiàn)最后數(shù)據(jù)存在servicelist,actionlist等鏈表中去了,后續(xù)執(zhí)行這些解析出來的數(shù)據(jù)的時候,正是從servicelist,actionlist中取出來,加入到執(zhí)行隊列queue中.。至于rc文件到底是怎么解析的,其中有什么關(guān)鍵內(nèi)容,先放到后面。2) 嵌套調(diào)用init_parse_config_file:繼續(xù)解析完init.rc用import導(dǎo)入的所有其他rc.看看init.rc的開頭是如何導(dǎo)入其他文件的:其中的import /init.$ro.hardware.rc,顯然需要知道ro. hardware到底是什么值。前面分析init.c的main函數(shù)的時候,我們注意
15、到下面2個函數(shù):3)進(jìn)入systemcoreinitutil.c的get_hardware_name:該函數(shù)的源代碼如下: 我們在終端cat /proc/cpuinfo獲得如下信息前面是4個CPU信息(4核處理器),最后明確看到Hardware的值是bigfish.4)回到systemcoreinitinit.c的 process_kernel_cmdline:process_kernel_cmdline中調(diào)用了export_kernel_boot_props函數(shù),這個函數(shù)設(shè)置了ro. hardware這個屬性的值:ro.boot.hardware在 系統(tǒng)中沒有設(shè)值,所以hardware這個字
16、符串保持為bigfish,導(dǎo)致:所以import /init.$ro.hardware.rc就是import /init. bigfish.rc,而這個文件在終端的根目錄下,和init.rc同級.5)接下來,解析得到的所有action就開始加入到執(zhí)行隊列: 并在systemcoreinitinit.c的main的for循環(huán)中得以執(zhí)行。3.4核心任務(wù)三:執(zhí)行command,監(jiān)控service重啟h和socket請求 systemcoreinitinit.c的main:poll這個api其實就是檢測傳入的socket的可讀,可寫,異常等狀態(tài);返回POLLIN表示該socket可讀,此時就
17、分別調(diào)調(diào)三種類型任務(wù)對應(yīng)的handle接口進(jìn)行任務(wù)處理。這三個socket分別是在各自的模塊初始化函數(shù)(init)中創(chuàng)建的:3.5疑問:傳說中的zygote進(jìn)程啟動在 哪里? 通過上面對systemcorerootdirinit.c下面main函數(shù)及其執(zhí)行的相關(guān)核心任務(wù)的解析,init進(jìn)程到底干了些什么事,已經(jīng)基本清楚了,但是我們似乎沒發(fā)現(xiàn)傳說中的zygote進(jìn)程在哪里啟動? main函數(shù)的任務(wù)中,唯一確實看到他到底是內(nèi)容,到底在做什么的就是init.rc的內(nèi)容,整理我們還沒有詳細(xì)分析過,而zygote和servicemanager等的啟動其實就藏在里面,我們這里只關(guān)注zygote。4 認(rèn)識和
18、解析init.rc的內(nèi)容 從上面可以看出,init.rc文件這個文件到底解析出來包含了哪些任務(wù),是系統(tǒng)啟動的根本所在,因為拋開這個部分,systemcoreinitinit.c的main函數(shù)都沒看到其他往上啟動相關(guān)進(jìn)程的地方。 源代碼: systemcorerootdir init.rc4.1認(rèn)識AIL語言寫成的init.rc init.rc 文件并不是普通的配置文件,而是由一種被稱為“Android初始化語言”(Android Init Language,這里簡稱為AIL)的腳本寫成的文件。在了解init如何解析init.rc文件之前,先了解AIL非常必要。AIL由如下4部分組成。1.
19、60; 動作(Actions)2. 命令(Commands)3服務(wù)(Services)4. 選項(Options)5. 導(dǎo)入 (import)其中action,service,import領(lǐng)銜的語句統(tǒng)稱section;另外還有tokens和line的概念。 他們之間的關(guān)系: section>action/services>line> tokens>: command |Options4.1.1 行(line)的概念這4部分都是面向行的代碼,也就是說: 1)用回車換行符作為每一條語句的分隔符。 2)每一行的代碼由多個符號(Tokens)表示。 3)
20、雙引號可以將多個由空格分隔的Tokens合成一個Tokens。 4)如果一行寫不下,可以在行尾加上反斜杠,來連接下一行。也就是 說,可以用反斜杠將多行代碼連接成一行代碼。 5)AIL的注釋與很多Shell腳本一樣,以#開頭。4.1.2 段(section)的概念 AIL在編寫時需要分成多個部分(Section),而每一部分的開頭需要指定Actions或Services或import。 而所有的Commands和Options只能屬于最近定義的Section。如果Commands和 Options在第
21、一個Section之前被定義,它們將被忽略。Actions和Services還需要有自己的名稱,且必須唯一。如果有兩個或多個Action或Service擁有同樣的名稱,那么init在執(zhí)行它們時將拋出錯誤,并忽略這些Action和Service。以init.rc為例,section包含下面三種類型的段內(nèi)容:import:action:services:4.1.3 動作(action)和服務(wù)(service)的概念目前init.rc內(nèi)已經(jīng)寫入的主要的action和service Actions和command的語法格式:on <trigger> <co
22、mmand> <command> <command> 也就是說Actions是以關(guān)鍵字on開頭的,on后面跟的字符串叫觸發(fā)器trigger,接下來是若干命令。例如,下面就是一個標(biāo)準(zhǔn)的Action。 on boot ifup lo hostname localhost domainname localdomain 其中boot是觸發(fā)器,下面三行是執(zhí)行命令command.1)目前init.rc支持的觸發(fā)器類型:1. boot2. init/post-fs/post-fs-data3.
23、<name>=<value> 當(dāng)屬性<name>被設(shè)置成<value>時被觸發(fā)。例如, on property:vold.decrypt=trigger_reset_main class_reset main4. device-added-<path> 當(dāng)設(shè)備節(jié)點被添加時觸發(fā)5. device-removed-<path> 當(dāng)設(shè)備節(jié)點被移除時添加6. service-exited-
24、<name> 會在一個特定的服務(wù)退出時觸發(fā)2)目前支持的commandActions后需要跟若干個命令,這些命令如下:1. exec <path> <argument> * 創(chuàng)建和執(zhí)行一個程序(<path>)。在程序完全執(zhí)行前,init將會阻塞。由于它不是內(nèi)置命令,應(yīng)盡量避免使用exec ,它可能會引起init執(zhí)行超時。 2. export <name> <value>在全局環(huán)境中將 <name>變量的值設(shè)為<value>。3.&
25、#160; ifup <interface> 啟動網(wǎng)絡(luò)接口4. import <filename> 指定要解析的其他配置文件。常被用于當(dāng)前配置文件的擴展5. hostname <name> 設(shè)置主機名6. chdir <directory> 改變工作目錄7. chmod <octal-mode><path> 改變文件的訪問權(quán)限8. chown &
26、lt;owner><group> <path> 更改文件的所有者和組9. chroot <directory> 改變處理根目錄10. class_start<serviceclass> 啟動所有指定服務(wù)類下的未運行服務(wù)。11 class_stop<serviceclass> 停止指定服務(wù)類下的所有已運行的服務(wù)。12. domainname <name> 設(shè)置域名13.
27、0; insmod <path> 加載<path>指定的驅(qū)動模塊14. mkdir <path> modeowner group 創(chuàng)建一個目錄<path> ,可以選擇性地指定mode、owner以及group。如果沒有指定,默認(rèn)的權(quán)限為755,并屬于root用戶和 root組。15. mount <type> <device> <dir> <mountoption> * 試圖在目錄<dir>掛載指定的設(shè)備
28、。<device> 可以是mtdname的形式指定一個mtd塊設(shè)備。<mountoption>包括 "ro"、"rw"、"re16. setkey 保留,暫時未用17. setprop <name><value> 將系統(tǒng)屬性<name>的值設(shè)為<value>。18. setrlimit <resource> <cur> <max> 設(shè)置<
29、resource>的rlimit (資源限制)19. start <service> 啟動指定服務(wù)(如果此服務(wù)還未運行)。20stop<service> 停止指定服務(wù)(如果此服務(wù)在運行中)。21. symlink <target> <path> 創(chuàng)建一個指向<path>的軟連接<target>。22. sysclktz <mins_west_of_gmt> 設(shè)置系統(tǒng)時鐘基準(zhǔn)(0代表時鐘滴答以格林威治
30、平均時(GMT)為準(zhǔn))23. trigger <event> 觸發(fā)一個事件。用于Action排隊24. wait <path> <timeout> 等待一個文件是否存在,當(dāng)文件存在時立即返回,或到<timeout>指定的超時時間后返回,如果不指定<timeout>,默認(rèn)超時時間是5秒。25. write <path> <string> <string> *向<path>指定的文件寫入一個或多個字符串。 服務(wù)(serv
31、ices)和選項(option)語法Services (服務(wù))是一個程序,他在初始化時啟動,并在退出時重啟(可選)。Services的語法格式如下: service <name> <pathname> <argument> * <option> <option> 例如,下面是一個標(biāo)準(zhǔn)的Service用法 service servicemanager /system/bin/servicemanager class core user system group system critical onrestart restart zygo
32、te onrestart restart media onrestart restart surfaceflinger onrestart restart drm Services的選項是服務(wù)的修飾符,可以影響服務(wù)如何以及怎樣運行。目前支持的選項(option)如下:1. critical表明這是一個非常重要的服務(wù)。如果該服務(wù)4分鐘內(nèi)退出大于4次,系統(tǒng)將會重啟并進(jìn)入 Recovery (恢復(fù))模式。2. disabled 表明這個服務(wù)不會和其他和他處于同一trigger (觸發(fā)器)下的服務(wù)自動啟動。該服務(wù)必須被明確的按名啟動。3. setenv <nam
33、e><value>在進(jìn)程啟動時將環(huán)境變量<name>設(shè)置為<value>。4. socket <name><type> <perm> <user> <group> Create a unix domain socketnamed /dev/socket/<name> and pass its fd to the launchedprocess. <type> must be"dgram&
34、quot;, "stream" or "seqpacket". User and group default to0. 創(chuàng)建一個unix域的名為/dev/socket/<name> 的套接字,并傳遞它的文件描述符給已啟動的進(jìn)程。<type> 必須是 "dgram","stream" 或"seqpacket"。用戶和組默認(rèn)是0。5. user <username>在啟動這個服務(wù)前改變該服務(wù)的用戶名。此時
35、默認(rèn)為 root。6. group <groupname> <groupname> *在啟動這個服務(wù)前改變該服務(wù)的組名。除了(必需的)第一個組名,附加的組名通常被用于設(shè)置進(jìn)程的補充組(通過setgroups函數(shù)),檔案默認(rèn)是root。7. oneshot 服務(wù)退出時不重啟。8. class <name> 指定一個服務(wù)類。所有同一類的服務(wù)可以同時啟動和停止。如果不通過class選項指定一個類,則默認(rèn)為"default"類服務(wù)。9. onrestart
36、0; 當(dāng)服務(wù)重啟,執(zhí)行一個命令(下詳)。4.2解析init.rc過程 前面分析init.c的main函數(shù)的時候,粗略分析了下init.rc的解析過程,這里再回到init_parse_config_file函數(shù)并從這里開始,分析詳細(xì)的解析過程:4.2.1init_parse_config_file和parse_config函數(shù)的實現(xiàn)在systemcoreinit init_parser.c下init_parse_config_file("/init.rc");這個方法主要負(fù)責(zé)初始化和分析init.rc文件
37、。init_parse_config_file函數(shù)在init_parser.c文件中實現(xiàn),代碼如下: int init_parse_config_file(const char *fn) char *data; data = read_file(fn, 0); if (!data) return -1; /* 實際分析init.rc文件的代碼 */ parse_config(fn, data); DUMP(); return 0; init_parse_config_file方法開始調(diào)用了read_file函數(shù)打開了/init.rc
38、文件,并返回了文件的內(nèi)容(char*類 型),然后最核心的函數(shù)是parse_config。該函數(shù)也在init_parser.c文件中實現(xiàn),代碼如下: static void parse_config(const char *fn, char *s) struct parse_state state; struct listnode import_list; struct listnode *node; char *argsINIT_PARSER_MAXARGS; int nargs; nargs = 0; state.filename = fn; state.line = 0; state.p
39、tr = s; state.nexttoken = 0; state.parse_line = parse_line_no_op; list_init(&import_list); state.priv = &import_list; /* 開始獲取每一個token,然后分析這些token,每一個token就是有空格、字表符和回車符分隔的字符串,簡單說就是找出全部我們能看到的一個個的字符串。 */ for (;) /* next_token函數(shù)相當(dāng)于詞法分析器 */ switch (next_token(&state) case T_EOF: /* init.rc文件分
40、析完畢 */ state.parse_line(&state, 0, 0); goto parser_done; case T_NEWLINE: /* 分析每一行的命令 */ /* 下面的代碼相當(dāng)于語法分析器 */ state.line+; if (nargs) int kw = lookup_keyword(args0); if (kw_is(kw, SECTION) state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); else state.parse_line(&am
41、p;state, nargs, args); nargs = 0; break; case T_TEXT: /* 處理每一個token */ if (nargs < INIT_PARSER_MAXARGS) argsnargs+ = state.text; break; parser_done: /* 最后處理由import導(dǎo)入的初始化文件 */ list_for_each(node, &import_list) struct import *import = node_to_item(node, struct import, list); int ret; INFO("
42、;importing '%s'", import->filename); /* 遞歸調(diào)用 */ ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'n", import->filename, fn); parse_config方法的代碼就比較復(fù)雜了,現(xiàn)在先說說該方法的基本處理流程。首先會調(diào)用 list_i
43、nit(&import_list)初始化一個鏈表,該鏈表是用于存儲通過import語句導(dǎo)入的初始化文件名。然后開始開始在 for循環(huán)中分析init.rc文件中的每一行代碼。最后將init.rc文件分析完后,就會進(jìn)入parser_done部分,并遞歸調(diào)用 init_parse_config_file方法分析通過import導(dǎo)入的初始化文件。 通過分析parse_config方法的原理,感覺也并不是很復(fù)雜。不過分析parse_config方法的具體代碼,還需要點編譯原理的知識(只是概念 上的就可以)。在for循環(huán)中調(diào)用了一個nex
44、t_token方法不斷從init.rc文件中獲取token。這里的token,就是一種編程語言的最小 單元,也就是不可再分。例如,對于傳統(tǒng)的編程語言,if、then等關(guān)鍵字、變量名等標(biāo)識符都屬于一個token。而對于init.rc文件來 說,import、on、以及觸發(fā)器的參數(shù)值,都屬于一個token。4.2.2 next_token函數(shù)的實現(xiàn)在systemcoreinit parser.c下。 一個完整的編譯器(或解析器)最開始需要進(jìn)行詞法和語法分析,詞法分析就是在源代碼文件中挑出一個個的Token,也就是說,詞法分析器的返回值是 Token,
45、而語法分析器的輸入就是詞法分析器的輸出。也就是說,語法分析器需要分析一個個的token,而不是一個個的字符。由于init解析語言很簡 單,所以就將詞法和語法分析器放到了一起。詞法分析器就是next_token函數(shù),而語法分析器就是T_NEWLINE分支中的代碼。這些就清楚多了。 現(xiàn)在先看看next_token函數(shù)(在parser.c文件中實現(xiàn))是如何獲取每一個token的。 int next_token(struct parse_state *state) char *x = state->ptr; char *s; if (state->nexttoken) int t = st
46、ate->nexttoken; state->nexttoken = 0; return t; /* 在這里開始一個字符一個字符地分析 */ for (;) switch (*x) case 0: state->ptr = x; return T_EOF; case 'n': x+; state->ptr = x; return T_NEWLINE; case ' ': case 't': case 'r': x+; continue; case '#': while (*x &&a
47、mp; (*x != 'n') x+; if (*x = 'n') state->ptr = x+1; return T_NEWLINE; else state->ptr = x; return T_EOF; default: goto text; textdone: state->ptr = x; *s = 0; return T_TEXT; text: state->text = s = x; textresume: for (;) switch (*x) case 0: goto textdone; case ' '
48、: case 't': case 'r': x+; goto textdone; case 'n': state->nexttoken = T_NEWLINE; x+; goto textdone; case '"': x+; for (;) switch (*x) case 0: /* unterminated quoted thing */ state->ptr = x; return T_EOF; case '"': x+; goto textresume; default:
49、*s+ = *x+; break; case '': x+; switch (*x) case 0: goto textdone; case 'n': *s+ = 'n' break; case 'r': *s+ = 'r' break; case 't': *s+ = 't' break; case '': *s+ = '' break; case 'r': /* <cr> <lf> -> line co
50、ntinuation */ if (x1 != 'n') x+; continue; case 'n': /* <lf> -> line continuation */ state->line+; x+; /* eat any extra whitespace */ while(*x = ' ') | (*x = 't') x+; continue; default: /* unknown escape - just copy */ *s+ = *x+; continue; default: *s+ = *
51、x+; return T_EOF; next_token函數(shù)的代碼還是很多的,不過原理到很簡單。就是逐一讀取init.rc文件(還有import導(dǎo)入的初始化文件)的字符,并將 由空格、“/t”和“/r”分隔的字符串挑出來,并通過state->text返回。如果返回了正常的token,next_token函數(shù)就返回 T_TEXT。如果一行結(jié)束,就返回T_NEWLINE,如果init.rc文件的內(nèi)容已讀取完,就返回T_EOF。當(dāng)返回T_NEWLINE時,開始語 法分析(由于init初始化語言是基于行的,所以語言分析實際上就是分析init.rc文件的每一行,只是這些
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- T-ZZB 1584-2023 低壓電源系統(tǒng)的電涌保護(hù)器(SPD)
- 二零二五年度專業(yè)技術(shù)師徒傳承合作合同
- 2025年度門店合作線上線下融合營銷協(xié)議
- 二零二五年度不占股份分紅權(quán)益共享協(xié)議
- 二零二五年度招商引資合同中的政府與企業(yè)合作模式創(chuàng)新
- 2025年度終止供貨協(xié)議函范文模板與簽訂程序指導(dǎo)
- 二零二五年度綠色建筑產(chǎn)業(yè)廠房租賃服務(wù)協(xié)議
- 二零二五年度勞動合同法未簽訂合同員工競業(yè)禁止協(xié)議
- 二零二五年度物業(yè)安全管理人員勞動合同范本
- 二零二五年度消防安全設(shè)施設(shè)備安全評估與整改服務(wù)合同
- 《Spring框架》教學(xué)課件
- 七年級下冊《平行線的判定》課件與練習(xí)
- 2025年中考英語時文閱讀 6篇有關(guān)電影哪吒2和 DeepSeek的英語閱讀(含答案)
- 修高速土方合同范例
- 2024年形勢與政策復(fù)習(xí)題庫含答案(綜合題)
- 江蘇省南通市2025屆高三第一次調(diào)研測試數(shù)學(xué)試題(南通一模)(含答案)
- DCMM數(shù)據(jù)管理師練習(xí)測試卷
- 油氣行業(yè)人才需求預(yù)測-洞察分析
- 檢修安全知識培訓(xùn)課件
- 學(xué)校心理健康教育存在的問題及改進(jìn)措施
- 合成生物學(xué)研發(fā)平臺與年產(chǎn)200噸合成生物制品項目可行性研究報告寫作模板-申批備案
評論
0/150
提交評論