1. 程式人生 > >Android系統啟動過程學習

Android系統啟動過程學習

使用 android 手機已經長時間了,同時,從大學學習 android 開發開始,也進行過多款 android app 專案的開發,但是對 android 內部的啟動過程,即當我們從按下電源鍵開機開始, android 系統內部是如何執行的,由於android 系統的核心使用的是 linux 核心,那麼在啟動過程中,android 系統和桌面Linux系統的啟動過程是否是一樣的?我們在之前的一篇部落格中,曾學習過Linux核心的啟動過程,在這裡,我們學習一下android系統的啟動過程,並從大體程式碼上講解其啟動過程。

啟動步驟

在android系統的啟動過程中,大體可以分為以下幾個步驟:

這裡寫圖片描述

android啟動過程分析

第一步 啟動電源以及啟動系統

當電源按下的時候,會引導固化在晶片中的程式碼從預定義的位置開始啟動,並載入載入程式到記憶體,即RAM中,然後執行。

第二步 載入程式執行

載入程式,英文名稱為Boot Loader,顧名思義,其為啟動載入器,其主要作用是引導android系統核心的啟動。載入程式是執行的第一個程式。其主要作用是在引導核心啟動之前,檢測相關硬體以及外部的RAM,設定網路,記憶體等,並根據相關引數或輸入資料設定核心。
Boot Loader載入程式可以在\bootable\bootloader\legacy\usbloader中找到,一般的載入器包含著兩個重要的檔案:

  1. init.S初始化堆疊,清空BBS棧,呼叫main.c的_main()函式
  2. main.c初始化硬體(鬧鐘,主機板,鍵盤,控制檯),建立Linux標籤

第三步 核心執行

當載入程式引導核心啟動之後,android的核心執行和linux的核心執行相似。核心啟動的時候,設定快取,被保護的儲存器,計劃列表,載入驅動。當核心完成系統設定之後,便找到系統檔案中”init”檔案,然後啟動系統的第一個程序。

第四步 init執行

init程序是android系統執行的第一個程序,也就是說所有的android程序都是直接或間接的被init程序建立的。在init程序執行過程中,主要負責兩個事情,一個是掛載系統目錄,像/dev

,/proc,/sys等,另外一件事情是執行init.rc檔案。

  • init位於/system/core/init目錄中。
  • init.rc位於/system/core/rootdir目錄中。
  • /system/core/init/readme.txt檔案中可以學習.rc檔案的相關語法,我們將在下面的部落格中學習該語法。

總體來說,在init.rc檔案中,主要是啟動相關程序和服務,同時設定相關引數和掛載相關目錄。

我們先來看一下init中的相關程式碼:


int main(int argc, char **argv)
{
    //.....
#ifndef NO_DEVFS_SETUP
    mkdir("/dev", 0755);
    mkdir("/proc", 0755);
    mkdir("/sys", 0755);

    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);

    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));

    open_devnull_stdio();
    klog_init();
#endif
    property_init();

    //.......

    is_charger = !strcmp(bootmode, "charger");

    INFO("property init\n");
    if (!is_charger)
        property_load_boot_defaults();

    INFO("reading config file\n");

    if (!charging_mode_booting())
       init_parse_config_file("/init.rc");
    else
       init_parse_config_file("/lpm.rc");

    /* Check for an emmc initialisation file and read if present */
    if (emmc_boot && access("/init.emmc.rc", R_OK) == 0) {
        INFO("Reading emmc config file");
            init_parse_config_file("/init.emmc.rc");
    }

    /* Check for a target specific initialisation file and read if present */
    if (access("/init.target.rc", R_OK) == 0) {
        INFO("Reading target specific config file");
            init_parse_config_file("/init.target.rc");
    }

    //.......

在這些事情處理完成之後,在init.rc中便會啟動zygote程序。


service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

第五步 zygote程序

在java中不同的虛擬機器例項會為不同的應用分配不同的記憶體。假如android應用應該儘可能快的啟動,但如果android系統為每一個應用啟動不同的Dalvik虛擬機器例項,就會消耗大量的記憶體以及時間。因此為了解決這個問題,Android系統創造了Zygote。Zygote讓Dalvik虛擬機器共享程式碼,低記憶體佔用以及最小的啟動時間成為可能。Zygote是一個虛擬機器程序,正如我們在前一個步驟所說的在系統引導的時候啟動。Zygote預載入以及初始化核心庫類。

Zygote載入程序:


 public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());

            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            gcAndFinalize();

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // If requested, start system server directly from Zygote
            if (argv.length != 2) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            if (argv[1].equals("start-system-server")) {
                startSystemServer();  //啟動系統服務
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            Log.i(TAG, "Accepting command socket connections");

            runSelectLoop();

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
  1. 載入ZygoteInit類,程式碼位於/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中。
  2. registerZygoteSocket()為zygote命令連線註冊一個伺服器套接字。
  3. preload()預載入類,資原始檔以及OpenGL。

第六步 系統服務或服務

在Zygote完成相應的初始化之後,開始申請啟動系統服務,系統服務是android系統中供上層執行的基礎。系統服務同時使用native以及java編寫,系統服務可以認為是一個程序。同一個系統服務在Android SDK可以讓System Services形式獲得。

核心服務:

  1. 啟動電源管理器;
  2. 建立Activity管理器;
  3. 啟動電話註冊;
  4. 啟動包管理器;
  5. 設定Activity管理服務為系統程序;
  6. 啟動上下文管理器;
  7. 啟動系統Context Providers;
  8. 啟動電池服務;
  9. 啟動定時管理器;
  10. 啟動感測服務;
  11. 啟動視窗管理器;
  12. 啟動藍芽服務;
  13. 啟動掛載服務。

其他服務:

  1. 啟動狀態列服務;
  2. 啟動硬體服務;
  3. 啟動網路狀態服務;
  4. 啟動網路連線服務;
  5. 啟動通知管理器;
  6. 啟動裝置儲存監視服務;
  7. 啟動定位管理器;
  8. 啟動搜尋服務;
  9. 啟動剪下板服務;
  10. 啟動登記服務;
  11. 啟動桌布服務;
  12. 啟動音訊服務;
  13. 啟動耳機監聽;
  14. 啟動AdbSettingsObserver(處理adb命令)。

第七步 引導完成

一單系統服務啟動,android系統的引導過程就完成了。此時,”ACTION_BOOT_COMPLETE”開機啟動廣播就發出去了。