Android 创世纪 第二天
第二天,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 cpuinfo cat cpuinfo Processor : ARMv7 Processor rev 2 (v7l) BogoMIPS : 299.11 Features : swp half thumb fastmult vfp edsp neon vfpv3 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x3 CPU part : 0xc08 CPU revision : 2Hardware : mapphone_UMTS Revision : 0000 Serial : 0000000000000000 CPU 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
總結
以上是生活随笔為你收集整理的Android 创世纪 第二天的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何得到自增id值
- 下一篇: 第八章 基本脚本编译