Android 啓動過程

分別來自

http://dingpwen.spaces.live.com/blog/cns!4CADD02D22459860!208.entry?fl=cat

http://www.eepw.com.cn/article/89567.htm

http://blog.csdn.net/guiterb/archive/2009/04/03/4047369.aspx

#####################################################

1. Boot 系統初始化, 具體過程參見 (system/core/init/Init.c) 中的 main 函數,這時候,手機或者模擬器出現的畫面是一個 console ,顯示 “ANDROID”msg

 

2. 初始化成功後,就開始 mounting 系統,具體參見 (system/core/mountd/Mountd.c)  中的 main 函數。

 

3 .接下來運行 ndroidRuntime ,並開始啓動 java 虛擬機 dalvikvm

 

4. Java 虛擬機啓動成功後,開始系統初始化。系統初始的第一步是用 JNI 方式實現的,對應 java 代碼爲 (frameworks/base/services/java/com/android/server/SystemServer.java) init1 Native )函數,對應的 JNI C++ 代碼爲 (frameworks/base/core/jni/server/com_android_server_SystemServer.cpp) ,而實現的 C++ 代碼爲

(frameworks/base/cmds/system_server/library/ System_init.cpp)   中的 system_init ()函數。

 

5. system_init 調用 SurfaceFlinger SurfaceFlinger readyToRun() 函數用 BootAnimation 來實現開機動畫,這時候手機或者模擬器顯示是一副背景圖加一個動態的小機器人。

 

6. 系統初始化的第二步,將啓動 ServerThread 進程,參見 SystemServer.init2() ServerThread 將啓動各種系統服務,如 Power Manager Activity Manager 等等,具體參見 ServerThread run 函數, ServerThread 同在 SystemServer.java 中。

 

7. 這之後的事,應該就是進入系統了。(這部分沒有調查過)。


#####################################################

對於關注 底層的朋友來說,其具體的啓動過程應該是比較吸引我們的。但是很多啓動文件什麼的,都得adb push到host上來看,挺不方便的,都怪 自帶的Toolbox太簡略了。所以在深入瞭解 的啓動流程之前,我們來把Busybox安裝到 上去,這樣,就有很多工具供我們使用了。

  首先去busybox主頁 下載最新版本的源代碼,然後用arm的交叉編譯器編譯出busybox的可執行程序,編譯的時候需要注意一些設置選項,例如

  Build Options —>

  Build BusyBox as a static binary (no shared libs) 這個要選上,因上這樣子編譯出來的busyBox纔是可以獨立運行的。

  │Do you want to build BusyBox with a Cross Compiler? │ │

  │ │(/HOME/toolchains/gcc-4.0.2-glibc-2.3.5/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu│ 這是交叉編譯器的路徑,要根據具體的情況來設置。

  Installation Options —>

  Don’t use /usr

  這樣子編譯出來的busybox纔不會安裝到你主機的/usr目錄下。一定要選上。

  busybox的功能選項根據需要自選,但是不要太貪心.

  OK,這裏就不糾纏於編譯busybox的東西了,網上資料無數。接下來,我們把busybox安裝到模擬器上去。先在模擬器上隨便建一個busybox的文件夾,然後進入busybox可執行文件目錄,使用命令

  adb push busybox.asc /data/busybox/busybox

  然後進入adb shell,chmod 777 ./busybox,就可以直接使用了。但現在還是不方便,總不能每用一個命令就輸一次busybox吧?所以,我們可以先用./busybox --install將程序都安裝到當前目錄下,然後把當前目錄添加到PATH變量中即可。暫時使用export來添加吧,如果想永久添加,往下看。

  好了,準備工作完成,開始研究的工作了。既然是研究啓動過程,那當然是先看看init.rc文件。去etc目錄打開它,分析一下內容,首先是對 env的定義,也就是全局環境變量的定義,接下來的建立和初始化裏面的內容目前還不清楚什麼意思,緊接着就是系統啓動時運行的初始進程信息,這個比較有意 思,包括了usbd-config和qemu,qemu自不用說,而usbd-config作爲初始啓動的進程,應該就是和上一篇文章猜的一樣,用來調試 或者usb通信的。往下看,是在初始啓動進程完成之後開始啓動的服務進程,這些進程如果因故退出,會自動重啓。這裏麪包括了console控制 臺,adbd監護進程,usbd監護進程,debuggerd監護進程等.除去這些守護進程,能引起我們注意的,是runtime和zygote。這兩個 進程似乎掌管着其他進程以及應用程序的啓動。

  現在,來讓我們做一個實驗吧,將自動調用的啓動過程變成手動,看看啓動流程具體是什麼樣的。想達到這個目的,首先就是要修改init.rc文 件,當然不是在模擬器的console中改,一是不能改,二是你改了也沒用,下次加載就會給你覆蓋了。所以,我們要從原始鏡像ramdisk.img入手 了。從2.6標準Linux內核開始,initrd.img都採用cpio壓縮,猜測ramdisk.img也一樣,需要使用gunzip解壓縮,然後再 使用cpio解包。好,進入tools/lib/images目錄下,先用file命令看看ramdisk.img的類型,沒錯,系統提示

  ramdisk.img: gzip compressed data, from Unix

  很好,然後將ramdisk.img複製一份到任何其他目錄下,將其名稱改爲ramdisk.img.gz,並使用命令

  gunzip ramdisk.img.gz

  然後新建一個文件夾,叫ramdisk吧,進入,輸入命令

  cpio -i -F ../ramdisk.img

  這下,你就能看見並操作ramdisk裏面的內容了。當然你也可以直接在外面進行操作,但是還是建議把cpio解壓縮出來的內容全部集中在一個文件夾裏面,因爲一會我們還要將其壓縮成新的ramdisk.img。

  OK,現在開始修改步驟吧。用任何一款編輯器打開init.rc,首先在PATH那裏加上你的Busybox安裝路徑,然後註釋內容,我們要手工啓動他們。

  # zygote {
  # exec
/ system / bin / app_process
  # args {
  #
0 - Xzygote
  #
1 / system / bin
  #
2 –zygote
  # }
  # autostart
1
  # }# runtime {
  # exec
/ system / bin / runtime
  # autostart
1
  # }

  在這裏需要注意,不要同時把兩者都註釋了,註釋某一個,再試驗手工啓動它,如果兩者同時註釋我這裏有問題,無法啓動。

  好,接下來,使用下列命令重新打包成鏡像

  cpio -i -t -F ../ramdisk.img > list

  cpio -o -H newc -O lk.img < list

  當前目錄下生成的lk.img就是我們的新鏡像了。使用自己的鏡像啓動emulator;

  emulator -console -ramdisk lk.img

  如果我們註釋的是zygote,那麼在#後輸入

  app_process -Xzygote /system/bin –zygote

  手工啓動,命令行中輸出的信息是

  Prepping: /system/app/AlarmProvider.apk:/system/app/Browser.apk:/system/app/
Calendar.apk:/system/app/Camera.apk:/system/app/Contacts.apk:

  /system/app/Development.apk:/system/app/GDataFeedsProvider.apk:/system/app/
Gmail.apk:/system/app/GmailProvider.apk:/system/app/GoogleApps.apk:

  /system/app/GoogleAppsProvider.apk:/system/app/Home.apk:/system/app/ImProvider.apk:
/system/app/Maps.apk:/system/app/MediaPickerActivity.apk:

  /system/app/MediaProvider.apk:/system/app/Phone.apk:/system/app/PimProvider.apk:/system/
app/ApiDemos.apk:/system/app/SettingsProvider.apk:

  /system/app/Sms.apk:/system/app/SyncProvider.apk:/system/app/TelephonyProvider.apk:
/system/app/XmppService.apk:/system/app/YouTube.apk

  File not found: /system/app/AlarmProvider.apk

  File not found: /system/app/Calendar.apk

  File not found: /system/app/Camera.apk

  File not found: /system/app/GDataFeedsProvider.apk

  File not found: /system/app/Gmail.apk

  File not found: /system/app/GmailProvider.apk

  File not found: /system/app/MediaPickerActivity.apk

  File not found: /system/app/PimProvider.apk

  File not found: /system/app/ApiDemos.apk

  File not found: /system/app/Sms.apk

  File not found: /system/app/SyncProvider.apk

  File not found: /system/app/YouTube.apk

  Prep complete

  嘿嘿,從File not found的信息中可以看到一些Google可能會即將推出的應用,比如Gmail什麼的。當然,這些都是Java框架的啓動信息,我們以後還要藉助其他工具來進行進一步探索。

  如果我們註釋的是runtime,那麼輸出信息是:

  +++ post-zygote

  老實說,沒有明白這是啥意思,呵呵,吃飯時間到了,懶得看了。

  好了,今天就說到這,基本的方法就是這樣,有興趣的朋友可以進一步深入研究。我們下一篇文章見。

 

#####################################################

[First written by Steve Guo, please keep the mark if forwarding.] .


init is the first process after kernel started. The corresponding source code lies in: device/system/init. It does the following tasks step by step:

1.       Initialize log system.

2.       Parse /init.rc and /init.%hardware%.rc.

3.       Execute early-init action in the two files parsed in step 2.

4.       Device specific initialize. For example, make all device node in /dev and download firmwares.

5.       Initialize property system. Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.

6.       Execute init action in the two files parsed in step 2.

7.       Start property service.

8.       Execute early-boot and boot actions in the two files parsed in step 2.

9.       Execute property action in the two files parsed in step 2.

10.   Enter into an indefinite loop to wait for device/property set/child process exit events. For example, if an SD card is plugined, init will receive a device add event, so it can make node for the device. Most of the important process is forked in init, so if any of them crashed, init will receive a SIGCHLD then translate it into a child process exit event, so in the loop init can handle the process exit event and execute the commands defined in *.rc(it will run command onrestart).

 

The .rc file is a script file defined by Android. The default is device/system/rootdir/init.rc. We can take a loot at the file format(device/system/init/readme.txt is a good overall introduction of the script). Basically the script file contains actions and services.

 

Actions

-------

Actions are named sequences of commands. Actions have a trigger which is used to determine when the action should occur.  When an event occurs which matches an action's trigger, that action is added to the tail of a to-be-executed queue (unless it is already on the queue).

Each action in the queue is dequeued in sequence and each command in that action is executed in sequence.  Init handles other activities (device creation/destruction, property setting, process restarting) "between" the execution of the commands in activities.

Actions take the form of:

on <trigger>

   <command>

   <command>

   <command>

...

 

Services

--------

Services are programs which init launches and (optionally) restarts when they exit.  Services take the form of:

service <name> <pathname> [ <argument> ]*

   <option>

   <option>

   ...

 

Options

-------

Options are modifiers to services.  They affect how and when init runs the service.

 

Triggers

--------

Triggers are strings which can be used to match certain kinds of events and used to cause an action to occur.

 

The builtin supported commands are defined in device/system/init/keywords.h. Commands are implementd in device/system/init/bultins.c.

 

The init program only executes five kinds of triggers: “early-init”, “init”, “early-boot”, “boot”, “property:*”. Take a look at the following line in default init.rc.

class_start default

This line is a command for the action corresponding to “boot” trigger. It will start all services whose class name equals to “default”. By default, if no class option is defined for a service, the service’s class name is “default”. So this line will start all the services in the order of position in the file by default. (BTW, you can start any service using start commands, if you like.) Any service is run as a forked process of init, take a look at the source code of service_start in device/system/init.c.

 

So according to the default init.rc, the following services will be executed step by step:

console : star a shell. The source is in device/system/bin/ash.

adbd : start adb daemon. The source is in device/tools/adbd. By default is disabled.

servicemanager : start binder system. The source is in device/commands/binder.

mountd : mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs. The source is in device/system/bin/mountd.

debuggerd : start debug system. The source is in device/system/bin/debuggerd.

rild : start radio interface layer daemon. The source is in device/commands/rind.

zygote : start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.

media : start AudioFlinger, MediaPlayerService and CameraService. The source is in device/commands/mediaserver.

bootsound : play the default boot sound /system/media/audio/ui/boot.mp3. The source is in device/commands/playmp3.

dbus : start dbus daemon, it’s only used by BlueZ. The source is in device/system/Bluetooth/dbus-daemon.

hcid : redirect hcid’s stdout and stderr to the Android logging system. The source is in device/system/bin/logwrapper. By default is disabled.

hfag : start Bluetooth handsfree audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.

hsag : start Bluetooth headset audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.

installd : start install package daemon. The source is in device/servers/installd.

flash_recovery : load /system/recovery.img. The source is in device/commands/recovery/mtdutils.

 

Zygote service does the following tasks step by step:

1.       Create JAVA VM.

2.       Register android native function for JAVA VM.

3.       Call the main function in the JAVA class named com.android.internal.os.ZygoteInit whose source is device/java/android/com/android/internal/os/ZygoteInit.java.

a)         Load ZygoteInit class

b)        Register zygote socket

c)        Load preload classes(the default file is device/java/android/preloaded-classes)

d)        Load preload resources

e)         Call Zygote::forkSystemServer (implemented in device/dalvik/vm/InternalNative.c) to fork a new process. In the new process, call the main function in the JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server.

                         i.              Load libandroid_servers.so

                       ii.              Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers. It only calls system_init implemented in device/servers/system/library/system_init.cpp.

l         If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.

l         Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server. This function is very critical for Android because it start all of Android JAVA services .

l         If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.

 

SystemServer::init2 will start a new thread to start all JAVA services as follows:

Core Services:

1.       Starting Power Manager

2.       Creating Activity Manager

3.       Starting Telephony Registry

4.       Starting Package Manager

5.       Set Activity Manager Service as System Process

6.       Starting Context Manager

7.       Starting System Context Providers

8.       Starting Battery Service

9.       Starting Alarm Manager

10.   Starting Sensor Service

11.   Starting Window Manager

12.   Starting Bluetooth Service

13.   Starting Mount Service

Other services

1.       Starting Status Bar Service

2.       Starting Hardware Service

3.       Starting NetStat Service

4.       Starting Connectivity Service

5.       Starting Notification Manager

6.       Starting DeviceStorageMonitor Service

7.       Starting Location Manager

8.       Starting Search Service

9.       Starting Clipboard Service

10.   Starting Checkin Service

11.   Starting Wallpaper Service

12.   Starting Audio Service

13.   Starting HeadsetObserver

14.   Starting AdbSettingsObserver

Finally SystemServer::init2 will call ActivityManagerService.systemReady to launch the first activity by senting Intent.CATEGORY_HOME intent .

 

There is another way to start system server, which is through a program named system_server whose source is device/servers/system/system_main.cpp. It also calls system_init to start system services. So there is a question: why does Android have two methods to start system services? My guess is that directly start system_server may have synchronous problem with zygote because system_server will call JNI to start SystemServer::init2, while at that time zygote may not start JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to start system services

發佈了1 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章