Android-源代码分析
本文從Android系統的源代碼下載開始介紹,緊接著介紹了如何將Android系統源代碼編譯成Android系統鏡像文件,然后對Android系統的啟動流程進行了較為深入的講解
Android源碼下載
Android系統的編譯環境目前只支持 Linux 以及 Mac OS 兩種操作系統。如果采用虛擬機安裝時需要考慮占用磁盤空間(源碼+編譯) ,如果是2.3 源碼需要5G,編譯需要10G。google推薦使用64位的操作系統。源碼下載編譯環境初始化官網地址,很可惜,目前該網址是訪問不了的,已經被屏蔽了。想要訪問可以采取翻墻的方法。
Android源碼編譯
Android源碼查看
首先給大家介紹一個查看源碼工具:SourceInsight
通過上面的軟件我們就可以查看任意我們想看的源碼了,其實如果我們的eclipse關聯了sdk源碼,那么看起來比這個軟件方便多了,那么為什么還用這個軟件呢,因為該軟件可以看整個Android系統的任意文件,這一點是比較強大的。
那么下面就讓我帶大家一起查看一下Android系統啟動流程吧。
Android啟動流程
Init進程的啟動
init進程,它是一個由內核啟動的用戶級進程。內核自行啟動(已經被載入內存,開始運行,并已初始化所有的設備驅動程序和數據結構等)之后,就通過啟動一個用戶級程序init的方式,完成引導進程。init始終是第一個進程。啟動過程就是代碼init.c中main函數執行過程:system\core\init\init.c
int main(int argc, char **argv) {/* Get the basic filesystem setup we need put* together in the initramdisk on / and then we'll* let the rc file figure out the rest.*/mkdir("/dev", 0755);mkdir("/proc", 0755);mkdir("/sys", 0755);mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");mkdir("/dev/pts", 0755);mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);mount("proc", "/proc", "proc", 0, NULL);mount("sysfs", "/sys", "sysfs", 0, NULL);/* We must have some place other than / to create the* device nodes for kmsg and null, otherwise we won't* be able to remount / read-only later on.* Now that tmpfs is mounted on /dev, we can actually* talk to the outside world.*/open_devnull_stdio();log_init();INFO("reading config file\n");init_parse_config_file("/init.rc");/* pull the kernel commandline and ramdisk properties file in */import_kernel_cmdline(0);get_hardware_name(hardware, &revision);snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);init_parse_config_file(tmp);action_for_each_trigger("early-init", action_add_queue_tail);queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");queue_builtin_action(property_init_action, "property_init");queue_builtin_action(keychord_init_action, "keychord_init");queue_builtin_action(console_init_action, "console_init");queue_builtin_action(set_init_properties_action, "set_init_properties");/* execute all the boot actions to get us started */action_for_each_trigger("init", action_add_queue_tail);action_for_each_trigger("early-fs", action_add_queue_tail);action_for_each_trigger("fs", action_add_queue_tail);action_for_each_trigger("post-fs", action_add_queue_tail);queue_builtin_action(property_service_init_action, "property_service_init");queue_builtin_action(signal_init_action, "signal_init");queue_builtin_action(check_startup_action, "check_startup");/* execute all the boot actions to get us started */action_for_each_trigger("early-boot", action_add_queue_tail);action_for_each_trigger("boot", action_add_queue_tail);/* run all property triggers based on current state of the properties */queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");#if BOOTCHARTqueue_builtin_action(bootchart_init_action, "bootchart_init"); #endiffor(;;) {int nr, i, timeout = -1;execute_one_command();restart_processes();上面源代碼已經省略去了非重要部分。
通過上面的代碼我們可以看到在main函數中執行了:文件夾建立,掛載,rc文件解析,屬性設置,啟動服務,執行動作,socket監聽等一系列操作。
下面看兩個重要的過程:rc文件解析和服務啟動。
1.1 rc文件的解析
.rc文件是Android使用的初始化腳本文件,系統初始化要觸發的動作和要啟動的服務及其各自屬性都在rc腳本文件中定義。 具體看一下啟動腳本:\system\core\rootdir\init.rc
該腳本定義的內容如下:
service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
在解析rc腳本文件時,將相應的類型放入各自的List中:
\system\core\init\Init_parser.c:init_parse_config_file( )存入到action_queue、action_list、service_list中,解析過程可以看一下parse_config函數。
這其中包含了服務:adbd、servicemanager、vold、ril-daemon、debuggerd、surfaceflinger、zygote、media……
1.2 服務啟動
文件解析完成之后將service放入到service_list中。在main函數中,調用restart_process();
在restart_processes()方法中調用了restart_service_if_needed。
在restart_service_if_needed()中調用了service_start()。
在service_start中開啟了子進程去運行各個服務。
Init.rc中第一個Service是servicemanager
ServiceManager用來管理系統中所有的binder service,不管是本地的c++實現的還是java語言實現的都需要這個進程來統一管理,最主要的管理就是,注冊添加服務,獲取服務。所有的Service使用前都必須先在servicemanager中進行注冊。
代碼位置:frameworks\base\cmds\servicemanager\Service_manager.c
系統開啟了很多個服務,其中最重要的就是zygote服務。該服務是在Init.rc中定義的。
2、Zygote進程的啟動
Zygote這個進程是非常重要的一個進程,Zygote進程的建立是真正的Android運行空間,初始化建立的Service都是Navtive service。
代碼位置:frameworks/base/cmds/app_process/App_main.cpp
上面是App_main.cpp的代碼片段,最重要的就是通過AppRuntime開啟了com.andrioid.internal.os.ZygoteInit程序。這是一個質的飛躍,讓我們從c/c++的世界跑到了Java世界。
上面調用了AndroidRuntime類中的start方法。
AndroidRuntime.cpp代碼位置:frameworks\base\core\jni\AndroidRuntime.cpp
我們需要關注的就是其中的start方法。
3、Java界的第一個類ZygoteInit
代碼地址:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
該類是Java的入口函數,包含了Java的main函數。
在ZygoteInit中完成了Android核心類和資源的加載,并啟動了Android的系統服務。
3.1 preloadClasses();
在preloadClasses()方法中加載了1.8k多個Android類。這些類是定義在一個名為preloaded-classes的文件中。
3.2 startSystemServer();
startSystemServer()正如其名稱,開啟了系統服務進程。開啟服務進程是通過參數調用Linux命令行進行的。這些命令參數作為開啟服務的參數事先被設置。開啟系統服務調用的是Zygote.forkSystemServer方法,該方法如下:
可以看到上面的方法是一個native方法,這里Java又調回到C語言的內容了,具體是怎么開啟的Android系統服務暫且不去追究。我們繼續往下走。
如果開啟子進程成功的話 ,那么返回的pid==0,這時候調用了handleSystemServerProcess(parsedArgs);
方法。我們有必要看看該方法都干了啥。
上面的代碼完成了系統服務進程的剩余工作。剩余工作是在RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
方法中完成。
這里面完成的工作包括:設置輸如輸出流為AndroidPrintStream、設置默認未捕獲異常處理handler、設置日志管理器、設置user-Agent、設置VM Trace參數,給系統服務進程設置nice-name ,起個好聽的名字也就是。
最后通過拋出一個異常,在捕獲異常的代碼通過反射的方法調用SystemServer的main方法,將SystemServer進程給運行起來,這里就是一個非常有意思的地方,Android系統服務進程是用通過拋出異常然后捕獲異常,然后處理捕獲的異常的時候運行起來的。為什么這么做呢?我從代碼中找到了如下的說明,這樣是唯一能找到的理由!
我翻譯一下吧,大概意思是這樣子的:
這里拋出的異常將在ZygoteInit.main()方法中捕獲到,這個main方法的職責是調用異常的run方法(通過看代碼我們可以發現這個異常是自定義的額包裝為Thread的異常,這也是設計者的高明之處)。這樣的安排清除了所有的棧隊列中的幀(frames,翻譯成幀并不能很好的表達Java中的思想),這些幀是用來設置進程用的(進程設置好了,你就通過拋異常的方法給人家干掉了,有點卸磨殺驢的感覺)。
補充知識:Stack frame(堆棧幀)是一個為函數保留的區域,用來存儲關于參數、局部變量和返回地址的信息。堆棧幀通常是在新的函數調用的時候創建,并在函數返回的時候銷毀。通常main是棧中的第一個幀,一個方法的調用就會創建一個幀。當遇到return或遇到Exception時幀會被銷毀。
4、SystemServer進程
在上一節中我們知道ZygoteInit進程啟動了SystemServer進程,雖然是在異常中啟動的,SystemServer就像一個私生子就這么誕生了。那么這一節我們重點分析一下這個私生子生活的怎么樣。
源碼位置:frameworks\base\services\java\com\android\server\SystemServer.java
SystemServer作為一個獨立的進程(也是一個獨立的Java程序),入口函數當然也是main。那么顯然分析該類必須從main函數開始。
在main函數中做了以下工作:
1)如果系統時間早于1970年,則把時間設置為1970年。
2)如果性能統計開關已經打開,則開始統計性能,同時開啟周期任務每一個小時打印一次日志。
3)設置目標堆內容使用率上限為0.8倍
4)加載C/C++庫
5)調用init1()方法進行初始化
4.1 init1()
該方法的注釋意思是:該方法被Zygote方法調用用于初始化系統。這將導致本地服務(SurfaceFlinger、AudioFlinger)的運行。最后該方法又調用了init2()方法,用于啟動Android服務。
4.2 init2()
在init2()方法中開啟了一個android.server.ServerThread線程。那么就看看該線程都干了些什么吧?
ServerThread的run()方法太長了,不可能把所有的代碼都粘貼出來,這里就截取一部分,略窺一斑吧。
大家看到了上面的代碼有沒有驚呆呢,原來我們經常用的各種Service都是這里啟動的,這次終于找到服務的源頭了吧。這些服務都通過 ServiceManager.addService()添加到了ServiceManager中。這樣得以讓我們在Activity中可以拿到這些Service。
代碼追溯到這里我們的桌面也該啟動了吧,因為ActivityManagerService已經啟動。那么接下來我們就看看((ActivityManagerService)ActivityManagerNative.getDefault()) .systemReady()都干了什么事情吧。
5、HomeActivity的啟動
上面代碼執行很長一段邏輯,很難看的懂,但是最后一行調用了resumeTopActivityLocked方法。我們看看這個方法里面都干了些什么事情。
上面代碼高亮部分執行了HomeActivity。至此我們的桌面系統就開始加載。
6、啟動流程圖
上面的啟動流程是從Linux的內核啟動好開始啟動Init進程開始,到啟動好桌面為止的,相信絕大多數人看了上面的整個流程已經暈掉了。為了幫助大家簡單的記住Android系統大致的啟動流程,我從網上找了如下一張圖片,供大家參考。
總結
以上是生活随笔為你收集整理的Android-源代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AlarmManager深入浅出
- 下一篇: Android Loader机制