[转载]Android创世纪 - 第二天
轉(zhuǎn)自:http://www.cnblogs.com/hangxin1940/archive/2011/10/14/2206754.html
第二天,google說,荒蕪要被開墾,系統(tǒng)便運(yùn)作了,它是linux。
?????????????? --xxx
???? 荒蠻大地就要變得肥沃,linux已經(jīng)運(yùn)行起來了。。。。
?
???? linux就不多講了,這里只講講被google大刀闊斧改了內(nèi)核后的linux。
?
???? 第一天最后,內(nèi)核init已經(jīng)干完了自己的事,把控制權(quán)交給了第一個(gè)用戶級(jí)進(jìn)程,也叫做init。
?
???? 想知道這個(gè)init干了什么事,我們只能看看源碼,不貼代碼,這里只說說它干了什么。
???? (system/core/init/init.c -->main)
?
一、清空umask
???? 也就是設(shè)置缺省權(quán)限,這里設(shè)置為0,umask為0000的話,就相當(dāng)于chmod中的0777,經(jīng)常使用linux對(duì)于chmod 777應(yīng)該很熟悉,就是賦予某個(gè)文件的權(quán)限為,所有組、所有用戶可讀可寫可運(yùn)行,也就是最寬松的權(quán)限。
?
二、創(chuàng)建并掛載一些基本的目錄
????? 創(chuàng)建目錄并掛載相應(yīng)系統(tǒng):
??????? /dev?? 設(shè)備目錄,所有的外圍設(shè)備都在這里了,包括真實(shí)的設(shè)備如sim卡,也包括虛擬的設(shè)備如必不可少的null設(shè)備。掛載關(guān)系是 /dev -> tmpfs,tmpfs顧名思義就是臨時(shí)文件系統(tǒng),這個(gè)系統(tǒng)只占用內(nèi)存空間。
?????? /proc? 系統(tǒng)信息目錄,包含了當(dāng)前系統(tǒng)的所有信息,比如進(jìn)程、時(shí)鐘等等動(dòng)態(tài)的信息。掛載關(guān)系是 /proc -> proc
??????? /sys? 這里存儲(chǔ)的東西,都是硬件設(shè)備在linux上映射的對(duì)象,比如pci設(shè)備。掛載關(guān)系是 /sys -> sysfs
??????? /dev/pts? 這個(gè)是遠(yuǎn)程終端控制臺(tái)設(shè)備,字符終端啦,如果木有這個(gè)的話,就不可能adb shell調(diào)試android。掛載關(guān)系是 /dev/pts -> devpts
??????? /dev/socket? 服務(wù)于android的,socket是linux中進(jìn)程通信的一種方式,/dev/socket下面就是已經(jīng)被系統(tǒng)分配的soket資源,這里基本上是一些本地服務(wù),比如ridl,有興趣可以adb shell查看一下。
?
三、初始化NULL設(shè)備,重定向標(biāo)準(zhǔn)輸入輸出,初始化kmsg系統(tǒng),并且解析init.rc文件
????? null是Linux的一個(gè)標(biāo)準(zhǔn)設(shè)備,也就是所謂的黑洞,至于為什么有它,就得從輸入輸出重定向說起,比如linux控制臺(tái)下運(yùn)行一個(gè)程序,有時(shí)會(huì)輸出一 大堆東西,這是它向標(biāo)準(zhǔn)輸出寫的,我們不想讓它顯示出來,就是用 > NULL給它的輸出重定向到了這個(gè)黑洞設(shè)備,系統(tǒng)呢會(huì)給這個(gè)程序返回一個(gè)寫入成功的操作,實(shí)質(zhì)上,系統(tǒng)什么都木有干。
????? kmsg是linux下的一個(gè)內(nèi)核級(jí)的日志系統(tǒng),kernel message。就好比anroid提供的Log系統(tǒng)一樣,只是針對(duì)內(nèi)核級(jí)別的。
????? 對(duì)于init.rc文件,這里只進(jìn)行了解析,并沒有執(zhí)行里面的一些命令。
?
四、獲得內(nèi)核命令參數(shù)并且解析特定機(jī)型的init.*.rc文件
????? 獲得內(nèi)核命令參數(shù),也就是顯式說明的一些參數(shù),如果配置過grub或者Loli的話,就可能與這個(gè)打過交道。
?????
????? 每個(gè)手機(jī)硬件平臺(tái)都不一樣,adb shell一下,會(huì)發(fā)現(xiàn)有兩個(gè)rc文件,其中一個(gè)就是與特定平臺(tái)有關(guān)的rc配置文件,比如我的defy就是init.mapphone_umts.rc, 為什么叫這個(gè)?中間就是手機(jī)硬件平臺(tái)的名字,可以 cat /proc/cpuinfo來獲得Hardware信息,我的如下:
| 01 | # cat cpuinfo |
| 02 | cat cpuinfo |
| 03 | Processor?????? : ARMv7 Processor rev 2 (v7l) |
| 04 | BogoMIPS??????? : 299.11 |
| 05 | Features??????? : swp half thumb fastmult vfp edsp neon vfpv3 |
| 06 | CPU implementer : 0x41 |
| 07 | CPU architecture: 7 |
| 08 | CPU variant???? : 0x3 |
| 09 | CPU part??????? : 0xc08 |
| 10 | CPU revision??? : 2 |
| 11 | ? |
| 12 | Hardware??????? : mapphone_UMTS |
| 13 | Revision??????? : 0000 |
| 14 | Serial????????? : 0000000000000000 |
| 15 | CPU Tier??????? : 10 |
?
可以看到Hardware的值就是rc的副名稱。
?????? init首先會(huì)獲得/porc/cpuinfo中的這個(gè)屬性值,然后根據(jù)這個(gè)字符串查找特定的rc文件,最后根據(jù)rc中的配置內(nèi)容,解析它。
?
五、執(zhí)行rc文件中的命令
????? 上一步,init已經(jīng)解析了那兩個(gè)rc文件,這里,會(huì)根據(jù)rc文件中的具體內(nèi)容,來分別執(zhí)行對(duì)應(yīng)的動(dòng)作,后面會(huì)獨(dú)立分析rc文件的格式內(nèi)容,以及執(zhí)行方法。
?
六、變?yōu)槭刈o(hù)神
??????? 到這里,init就進(jìn)入了死循環(huán)了for(;;){}。那么它都守護(hù)了些什么?
???
??? 1、porpety service? 啟動(dòng)并守護(hù)屬性服務(wù)
??????? android下特有的。就好比windows下面的注冊(cè)表,記錄了各種信息。大到系統(tǒng)是否成功運(yùn)行的標(biāo)志,小到短信聲音。用戶在設(shè)置一些手機(jī)設(shè)置的時(shí)候,在底層,實(shí)際就是和propety service打交道。
? ? ? ??
| 屬性前綴 | 描述 | 示例(shell下操作) |
| ro. | 只讀屬性 | setprop ro.media.capture.maxres 5m 攝像頭的最大像素 |
| persist. | 額外存儲(chǔ)到/data/property目錄下 | setprop persist.sys.country CN 不解釋。注意,每個(gè)屬性都存儲(chǔ)為單獨(dú)的一個(gè)文件 |
| net. | 聯(lián)網(wǎng)相關(guān),比如gprs、藍(lán)牙… | setprop net.bt.name CAPF 藍(lán)牙的網(wǎng)絡(luò)名稱為CAPF net.change的值為最后一次更改net.*屬性的屬性名,例如: net.change=net.gprs.local-ip |
| ctrl.start 控制命令 | 啟動(dòng)init.rc中標(biāo)注為service的服務(wù) | setprop ctl.start bootanim 啟動(dòng)boot動(dòng)態(tài)圖像(第二屏啟動(dòng)畫面) 一個(gè)服務(wù)設(shè)置后,其結(jié)果會(huì)以下面的屬性返回,例如 init.svc.bootanim=running |
| ctrl.stop | 停止init.rc中標(biāo)注為service的服務(wù) | setprop ctl.stop bootanim 停止boot動(dòng)態(tài)圖像(第二屏啟動(dòng)畫面) 一個(gè)服務(wù)設(shè)置后,其結(jié)果會(huì)以下面的屬性返回,例如 init.svc.bootanim=stoped |
??????? 想要查看并設(shè)置屬性,可以通過以下三種途徑:
??? shell瀏覽文件:
?????????? /default.prop
?????????? /system/build.prop
?????????? /data/property/*
??? java:
?????????? System.getProperty(“xxxx”);
?????????? System.setProperty(“xxxx”);
?? ? c/c++:
?????????? demo.c:
| 01 | #include <cutils/properties.h> |
| 02 | #include <stdio.h> |
| 03 | void print_prop(const char* key,const char* value,void* cookie) |
| 04 | { |
| 05 | ????printf("key=%s,value=%s/n",key,value); |
| 06 | } |
| 07 | ? |
| 08 | int main() |
| 09 | { |
| 10 | ????property_list(print_prop,NULL); |
| 11 | } |
?
?????????? Android.mk:
| 01 | LOCAL_PATH:= $(call my-dir) |
| 02 | ? |
| 03 | include $(CLEAR_VARS) |
| 04 | ? |
| 05 | LOCAL_SRC_FILES:= / |
| 06 | ? |
| 07 | list_property.cpp / |
| 08 | ? |
| 09 | LOCAL_SHARED_LIBRARIES := / |
| 10 | ? |
| 11 | libcutils / |
| 12 | ? |
| 13 | libutils / |
| 14 | ? |
| 15 | LOCAL_MODULE:= list_prop |
| 16 | ? |
| 17 | include $(BUILD_EXECUTABLE) |
| 18 | ? |
| 19 | include $(call all-makefiles-under,$(LOCAL_PATH)) |
?
??? 2、動(dòng)態(tài)生成設(shè)備節(jié)點(diǎn)
?????? android的linux下面是沒有udev的,udev可以說是一個(gè)根據(jù)內(nèi)核的硬件消息來自動(dòng)發(fā)現(xiàn)設(shè)備的一個(gè)程序,android下面根據(jù)硬件相應(yīng) 的,也就是鍵盤與內(nèi)存卡,在平板上面的話就更多了,比如鼠標(biāo)、鍵盤等等。沒有udev的話,android是如何實(shí)現(xiàn)硬件的熱插拔呢?
?????? 和udev一樣,init守護(hù)神同樣監(jiān)聽了uevent事件,自己根據(jù)uevent的內(nèi)容來做相應(yīng)的事情,與udev做了異曲同工之事。
?????? 看一下大致流程。首先設(shè)備狀態(tài)更改,內(nèi)核會(huì)檢測(cè)到,并發(fā)出uevent消息(字符串),init檢測(cè)到消息,交給相應(yīng)函數(shù)處理,這個(gè)函數(shù)根據(jù)uevent 的內(nèi)容,再做進(jìn)一步處理。除了插拔內(nèi)存卡等(android有專門的外存管理機(jī)制,就是vold),其它(比如數(shù)據(jù)線插入、鼠標(biāo)插入)都會(huì)處理。
?
??? 3、監(jiān)聽keychord事件
?????? keychord是組合按鍵,從源碼的行為來看,應(yīng)該是考慮到組合鍵盤這種外設(shè),大部分情況不會(huì)用到手機(jī)上,而多用在智能設(shè)備上,也就是沒有觸屏以及按鍵 很少的android設(shè)備,比如運(yùn)行android的手表神馬的,通過不同的按鍵組合,來代表一個(gè)標(biāo)準(zhǔn)鍵盤的輸入。
?????? 這個(gè)東東估計(jì)用的不多。
?
??? 4、殺死僵尸進(jìn)程
?????? 什么是僵尸進(jìn)程?
?????? linux的進(jìn)程有個(gè)特點(diǎn),一個(gè)主進(jìn)程可以分裂(fork)子進(jìn)程(android的受精卵zygote完美的發(fā)揚(yáng)了這種精神),在桌面版的一些 linux中,查看系統(tǒng)監(jiān)視器,仔細(xì)看看進(jìn)程信息,會(huì)發(fā)現(xiàn)很多進(jìn)程會(huì)是樹狀結(jié)構(gòu),點(diǎn)擊一個(gè)進(jìn)程后面又展開了好幾個(gè)進(jìn)程,而且是個(gè)多級(jí)樹。這都是一個(gè)進(jìn)程有 fork了好幾個(gè)子進(jìn)程的結(jié)果。
?????? 如果主進(jìn)程被kill的話,那么它的子進(jìn)程就有可能成為僵尸進(jìn)程,所謂僵尸就是不干活但占用空間的程序死尸,這時(shí),init守護(hù)神就負(fù)責(zé)回收這些無辜的靈魂,來釋放本來就稀缺的內(nèi)存資源。
?
???? 5、守護(hù)重要服務(wù)
? ? ? ? 這些服務(wù)是native層面的服務(wù),比如servicemanager、vold。例如重要的zygote,有時(shí)候(不經(jīng)常)碰到的感覺和突然重啟一樣,這八成就是zygote崩潰并重啟了,要知道java世界可是zygote孵化出來的。
???????
?
?
解讀init.rc
? ? ? ?android的init.rc語法是獨(dú)有的,可以說是一種語言吧。
? ? ? ?init.rc的語法分為行為(Actions),、命令(Commands)?、服務(wù)(Services)、選項(xiàng)(Options)。
| 類別 | 名稱 | 描述 |
| SECTION | on | 觸發(fā)條件 |
| 同上.. | service | 解析service |
| COMMAND | chdir | 更改當(dāng)前工作目錄 |
| 同上.. | chroot | 更改參考的根目錄位置 |
| .. | class_start | 啟動(dòng)某個(gè)設(shè)置了class名稱的服務(wù) |
| .. | class_stop | 停止某個(gè)設(shè)置了class名稱的服務(wù) |
| .. | domainname | 域名 |
| .. | exec | 調(diào)用程序并轉(zhuǎn)移進(jìn)程 |
| .. | export | 提交變量 |
| .. | hostname | 主機(jī)名 |
| .. | ifup | 激活網(wǎng)卡 |
| .. | insmod | 掛載模塊 |
| .. | import | 引入配置,比如etc下的一些rc文件,和java中的import差不多 |
| .. | mkdir | 建立目錄 |
| .. | mount | 掛載文件系統(tǒng) |
| .. | setkey | 從源碼看,應(yīng)該是設(shè)置一個(gè)命令的關(guān)鍵字縮寫,比如可以將domainname映射為dn |
| .. | setprop | 設(shè)置一個(gè)屬性 |
| .. | setrlimit | 設(shè)置當(dāng)前程序可以打開的最大文件數(shù)到系統(tǒng)規(guī)定程序可以打開的最大文件數(shù) |
| .. | start | 啟動(dòng)服務(wù) |
| .. | stop | 停止服務(wù) |
| .. | trigger | 不清楚,難道是自定義觸發(fā)器? |
| .. | symlink | 建立符號(hào)鏈接 |
| .. | sysclktz | 設(shè)置基準(zhǔn)時(shí)間 |
| .. | wait | 等待文件準(zhǔn)備好?Linux中這是進(jìn)程調(diào)度的函數(shù) |
| .. | write | 向文件、設(shè)備寫個(gè)什么東西。肯定不是傳消息的那個(gè)wirte |
| .. | copy | 不解釋 |
| .. | chown | 更改所有者 |
| .. | chmod | 更改權(quán)限 |
| .. | loglevel | Log輸出級(jí)別,低于這個(gè)級(jí)別的就輸出 |
| .. | restart | 重啟服務(wù) |
| OPTION | capability | 能力,也就是系統(tǒng)對(duì)進(jìn)程的一種權(quán)限控制。 |
| 同上.. | class | 設(shè)置class name |
| .. | console | 啟用控制臺(tái) |
| .. | critical | 是否關(guān)鍵,也就是4分鐘之內(nèi)重啟超過4次的話,重啟之后就進(jìn)入recovery模式 |
| .. | disabled | 不隨class自動(dòng)啟動(dòng) |
| .. | group | 組歸屬 |
| .. | keycodes | 不明白。。。。。 |
| .. | oneshot | 只啟動(dòng)一次,意外退出后不必重啟 |
| .. | onrestart | 重啟時(shí) |
| .. | setenv | 增加環(huán)境變量 |
| .. | socket | 申請(qǐng)socket資源 |
| .. | user | 用戶歸屬 |
| .. | ioprio | io調(diào)度優(yōu)先級(jí) |
(很多屬性與命令用法都與linux中同名命令差球不多)
? ? ? ?init是分段(section)解析init.rc的,在keywords.h中可以查看關(guān)鍵字的定義。init是以什么標(biāo)志來分段解析 init.rc呢?結(jié)合init.rc的內(nèi)容,可以看出,分段標(biāo)記是以on 和 service來標(biāo)記的。下面詳細(xì)說明。
? ? on ? 啥時(shí)候干什么
? ? ? ? on屬于行為。
? ? ??on early-init? ?
? ? ? ? ? ? ?init之前、加載完所有rc文件后即執(zhí)行,在miui的rom中,init.rc在early-init執(zhí)行的是start ueventd,根據(jù)keywords.h的定義,start是個(gè)命令(COMMAND)。
? ? ? ? ? ? ?這里順便說下ueventd,android中底層(一般指驅(qū)動(dòng))通知上層的事件,用的是uevent,java層通過觀察者模式實(shí)現(xiàn),用到的類為?UEventObserver,使用intent來傳遞;native層用的是android_os_UEventObserver.cpp,使用uevent.c通過socket傳遞。當(dāng)然,這是framework及以下的層面,一般開發(fā)不經(jīng)常用到,更何況這幾個(gè)類都沒有被暴露出來。
? ? ? on init
? ? ? ? ? ? ?加載propety各項(xiàng)屬性文件之前執(zhí)行,在init變?yōu)閜ropety service之前都屬于init階段。? ? ? ? ? ??
? ? ? on early-boot
? ? ? ? ? ? ?啟動(dòng)屬性服務(wù)后即執(zhí)行。
? ? ? on boot
? ? ? ? ? ? ?boot的時(shí)候執(zhí)行。
? ? ? on property:xxxxx=x
? ? ? ? ? ? ?當(dāng)某個(gè)屬性設(shè)置為預(yù)期值時(shí)執(zhí)行。?
? ? ?關(guān)于init.rc,其實(shí)結(jié)合/src/system/core/init/* 源碼和init.rc文件來看,會(huì)明白許多。
水平有限,錯(cuò)誤之處請(qǐng)指正,多謝!??
轉(zhuǎn)載于:https://www.cnblogs.com/super119/archive/2011/10/14/2211125.html
總結(jié)
以上是生活随笔為你收集整理的[转载]Android创世纪 - 第二天的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MVC3教程之新手入门(转)
- 下一篇: 关于若干数据库数据插入性能的对比