第二天,google說,荒蕪要被開墾,系統便運作了,它是linux。
--xxx
荒蠻大地就要變得肥沃,linux已經運行起來了。。。。
linux就不多講了,這裡只講講被google大刀闊斧改了核心後的linux。
第一天最後,核心init已經幹完了自己的事,把控制權交給了第一個使用者級進程,也叫做init。
想知道這個init幹了什麼事,我們只能看看源碼,不貼代碼,這裡只說說它幹了什麼。
(system/core/init/init.c -->main)
一、清空umask
也就是設定預設許可權,這裡設定為0,umask為0000的話,就相當於chmod中的0777,經常使用linux對於chmod 777應該很熟悉,就是賦予某個檔案的許可權為,所有組、所有使用者可讀可寫可運行,也就是最寬鬆的許可權。
二、建立並掛載一些基本的目錄
建立目錄並掛載相應系統:
/dev 裝置目錄,所有的外圍裝置都在這裡了,包括真實的裝置如sim卡,也包括虛擬裝置如必不可少的null裝置。掛載關係是 /dev -> tmpfs,tmpfs顧名思義就是臨時檔案系統,這個系統只佔用記憶體空間。
/proc 系統資訊目錄,包含了當前系統的所有資訊,比如進程、時鐘等等動態資訊。掛載關係是 /proc -> proc
/sys 這裡儲存的東西,都是硬體裝置在linux上映射的對象,比如pci裝置。掛載關係是 /sys -> sysfs
/dev/pts 這個是遠程終端控制台裝置,字元終端啦,如果木有這個的話,就不可能adb shell調試android。掛載關係是 /dev/pts -> devpts
/dev/socket 服務於android的,socket是linux中進程通訊的一種方式,/dev/socket下面就是已經被系統分配的soket資源,這裡基本上是一些本地服務,比如ridl,有興趣可以adb shell查看一下。
三、初始化NULL裝置,重新導向標準輸入輸出,初始化kmsg系統,並且解析init.rc檔案
null是Linux的一個標準裝置,也就是所謂的黑洞,至於為什麼有它,就得從輸入輸出重新導向說起,比如linux控制台下運行一個程式,有時會輸出一大堆東西,這是它向標準輸出寫的,我們不想讓它顯示出來,就是用 > NULL給它的輸出重新導向到了這個黑洞裝置,系統呢會給這個程式返回一個寫入成功的操作,實質上,系統什麼都木有幹。
kmsg是linux下的一個核心級的日誌系統,kernel message。就好比anroid提供的Log系統一樣,只是針對核心層級的。
對於init.rc檔案,這裡只進行瞭解析,並沒有執行裡面的一些命令。
四、獲得核心命令參數並且解析特定機型的init.*.rc檔案
獲得核心命令參數,也就是顯式說明的一些參數,如果配置過grub或者Loli的話,就可能與這個打過交道。
每個手機硬體平台都不一樣,adb shell一下,會發現有兩個rc檔案,其中一個就是與特定平台有關的rc設定檔,比如我的defy就是init.mapphone_umts.rc,為什麼叫這個?中間就是手機硬體平台的名字,可以 cat /proc/cpuinfo來獲得Hardware資訊,我的如下:
# cat cpuinfocat cpuinfoProcessor : ARMv7 Processor rev 2 (v7l)BogoMIPS : 299.11Features : swp half thumb fastmult vfp edsp neon vfpv3CPU implementer : 0x41CPU architecture: 7CPU variant : 0x3CPU part : 0xc08CPU revision : 2Hardware : mapphone_UMTSRevision : 0000Serial : 0000000000000000CPU Tier : 10
可以看到Hardware的值就是rc的副名稱。
init首先會獲得/porc/cpuinfo中的這個屬性值,然後根據這個字串尋找特定的rc檔案,最後根據rc中的配置內容,解析它。
五、執行rc檔案中的命令
上一步,init已經解析了那兩個rc檔案,這裡,會根據rc檔案中的具體內容,來分別執行對應的動作,後面會獨立分析rc檔案的格式內容,以及執行方法。
六、變為守護神
到這裡,init就進入了死迴圈了for(;;){}。那麼它都守護了些什嗎?
1、porpety service 啟動並守護屬性服務
android下特有的。就好比windows下面的註冊表,記錄了各種資訊。大到系統是否成功啟動並執行標誌,小到簡訊聲音。使用者在設定一些手機設定的時候,在底層,實際就是和propety service打交道。
屬性首碼 |
描述 |
樣本(shell下操作) |
ro. |
唯讀屬性 |
setprop ro.media.capture.maxres 5m 網路攝影機的最大像素 |
persist. |
額外儲存到/data/property目錄下 |
setprop persist.sys.country CN 不解釋。注意,每個屬性都儲存為單獨的一個檔案 |
net. |
連網相關,比如gprs、藍芽… |
setprop net.bt.name CAPF 藍芽的網路名稱為CAPF net.change的值為最後一次更改net.*屬性的屬性名稱,例如: net.change=net.gprs.local-ip |
ctrl.start 控制命令 |
啟動init.rc中標註為service的服務 |
setprop ctl.start bootanim 啟動boot生動影像(第二屏啟動畫面) 一個服務設定後,其結果會以下面的屬性返回,例如 init.svc.bootanim=running |
ctrl.stop |
停止init.rc中標註為service的服務 |
setprop ctl.stop bootanim 停止boot生動影像(第二屏啟動畫面) 一個服務設定後,其結果會以下面的屬性返回,例如 init.svc.bootanim=stoped |
想要查看並設定屬性,可以通過以下三種途徑:
shell瀏覽檔案:
/default.prop
/system/build.prop
/data/property/*
java:
System.getProperty(“xxxx”);
System.setProperty(“xxxx”);
c/c++:
demo.c:
#include <cutils/properties.h>#include <stdio.h>void print_prop(const char* key,const char* value,void* cookie){printf("key=%s,value=%s/n",key,value);}int main(){property_list(print_prop,NULL);}
Android.mk:
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= /list_property.cpp /LOCAL_SHARED_LIBRARIES := /libcutils /libutils /LOCAL_MODULE:= list_propinclude $(BUILD_EXECUTABLE)include $(call all-makefiles-under,$(LOCAL_PATH))
2、動態產生裝置節點
android的linux下面是沒有udev的,udev可以說是一個根據核心的硬體訊息來自動探索裝置的一個程式,android下面根據硬體相應的,也就是鍵盤與記憶卡,在平板上面的話就更多了,比如滑鼠、鍵盤等等。沒有udev的話,android是如何?硬體的熱插拔呢?
和udev一樣,init守護神同樣監聽了uevent事件,自己根據uevent的內容來做相應的事情,與udev做了異曲同工之事。
看一下大致流程。首先裝置狀態更改,核心會檢測到,並發出uevent訊息(字串),init檢測到訊息,交給相應函數處理,這個函數根據uevent的內容,再做進一步處理。除了插拔記憶卡等(android有專門的外存管理機制,就是vold),其它(比如資料線插入、滑鼠插入)都會處理。
3、監聽keychord事件
keychord是組合按鍵,從源碼的行為來看,應該是考慮到按鍵組合盤這種外設,大部分情況不會用到手機上,而多用在智慧型裝置上,也就是沒有觸屏以及按鍵很少的android裝置,比如運行android的手錶神馬的,通過不同的按鍵組合,來代表一個標準鍵盤的輸入。
這個東東估計用的不多。
4、殺死殭屍進程
什麼是殭屍進程?
linux的進程有個特點,一個主進程可以分裂(fork)子進程(android的受精卵zygote完美的發揚了這種精神),在案頭版的一些linux中,查看系統監視器,仔細看看進程資訊,會發現很多進程會是樹狀結構,點擊一個進程後面又展開了好幾個進程,而且是個多級樹。這都是一個進程有fork了好幾個子進程的結果。
如果主進程被kill的話,那麼它的子進程就有可能成為殭屍進程,所謂殭屍就是不幹活但佔用空間的程式死屍,這時,init守護神就負責回收這些無辜的靈魂,來釋放本來就稀缺的記憶體資源。
5、守護重要服務
這些服務是native層面的服務,比如servicemanager、vold。例如重要的zygote,有時候(不經常)碰到的感覺和突然重啟一樣,這八成就是zygote崩潰並重啟了,要知道java世界可是zygote孵化出來的。
解讀init.rc
android的init.rc文法是專屬的,可以說是一種語言吧。
init.rc的文法分為行為(Actions),、命令(Commands) 、服務(Services)、選項(Options)。
類別 |
名稱 |
描述 |
SECTION |
on |
觸發條件 |
同上.. |
service |
解析service |
COMMAND |
chdir |
更改當前工作目錄 |
同上.. |
chroot |
更改參考的根目錄位置 |
.. |
class_start |
啟動某個設定了class名稱的服務 |
.. |
class_stop |
停止某個設定了class名稱的服務 |
.. |
domainname |
網域名稱 |
.. |
exec |
調用程式並轉移進程 |
.. |
export |
提交變數 |
.. |
hostname |
主機名稱 |
.. |
ifup |
啟用網卡 |
.. |
insmod |
掛載模組 |
.. |
import |
引入配置,比如etc下的一些rc檔案,和java中的import差不多 |
.. |
mkdir |
建立目錄 |
.. |
mount |
掛載檔案系統 |
.. |
setkey |
從源碼看,應該是設定一個命令的關鍵字縮寫,比如可以將domainname映射為dn |
.. |
setprop |
設定一個屬性 |
.. |
setrlimit |
設定當前程式可以開啟的最大檔案數到系統規定程式可以開啟的最大檔案數 |
.. |
start |
啟動服務 |
.. |
stop |
停止服務 |
.. |
trigger |
不清楚,難道是自訂觸發器? |
.. |
symlink |
建立符號連結 |
.. |
sysclktz |
設定基準時間 |
.. |
wait |
等待檔案準備好?Linux中這是進程調度的函數 |
.. |
write |
向檔案、裝置寫個什麼東西。肯定不是傳訊息的那個wirte |
.. |
copy |
不解釋 |
.. |
chown |
更改所有者 |
.. |
chmod |
更改許可權 |
.. |
loglevel |
Log輸出層級,低於這個層級的就輸出 |
.. |
restart |
重啟服務 |
OPTION |
capability |
能力,也就是系統對進程的一種許可權控制。 |
同上.. |
class |
設定class name |
.. |
console |
啟用控制台 |
.. |
critical |
是否關鍵,也就是4分鐘之內重啟超過4次的話,重啟之後就進入recovery模式 |
.. |
disabled |
不隨class自動啟動 |
.. |
group |
組歸屬 |
.. |
keycodes |
不明白。。。。。 |
.. |
oneshot |
只啟動一次,意外退出後不必重啟 |
.. |
onrestart |
重啟時 |
.. |
setenv |
增加環境變數 |
.. |
socket |
申請socket資源 |
.. |
user |
使用者歸屬 |
.. |
ioprio |
io調度優先順序 |
(很多屬性與命令用法都與linux中同名命令差球不多)
init是分段(section)解析init.rc的,在keywords.h中可以查看關鍵字的定義。init是以什麼標誌來分段解析init.rc呢?結合init.rc的內容,可以看出,分區段標記是以on 和 service來標記的。下面詳細說明。
on 啥時候幹什麼
on屬於行為。
on early-init
init之前、載入完所有rc檔案後即執行,在miui的rom中,init.rc在early-init執行的是start ueventd,根據keywords.h的定義,start是個命令(COMMAND)。
這裡順便說下ueventd,android中底層(一般指驅動)通知上層的事件,用的是uevent,java層通過觀察者模式實現,用到的類為 UEventObserver,使用intent來傳遞;native層用的是android_os_UEventObserver.cpp,使用uevent.c通過socket傳遞。當然,這是framework及以下的層面,一般開發不經常用到,更何況這幾個類都沒有被暴露出來。
on init
載入propety各項屬性檔案之前執行,在init變為propety service之前都屬於init階段。
on early-boot
啟動屬性服務後即執行。
on boot
boot的時候執行。
on property:xxxxx=x
當某個屬性設定為預期值時執行。
關於init.rc,其實結合/src/system/core/init/* 源碼和init.rc檔案來看,會明白許多。
水平有限,錯誤之處請指正,多謝!
創世紀:第一天串連:http://www.cnblogs.com/hangxin1940/archive/2011/10/01/2196964.html
創世紀:第三天串連:http://www.cnblogs.com/hangxin1940/archive/2011/10/22/2221451.html
原創文章,轉載請說明出處:
http://www.cnblogs.com/hangxin1940/archive/2011/10/01/2196964.html