Android啟動過程-萬字長文(Android14)

柳云居士發表於2024-05-30

計算機啟動過程Linux核心Kernel啟動過程介紹了計算機啟動和核心載入,本篇文章主要介紹Android系統是如何啟動的。

一、Android啟動流程

Android系統的啟動流程與Linux接近:

sequenceDiagram participant Bootloader as 引導載入程式 participant Kernel as 核心 participant Init as init 程序 participant Zygote as Zygote 程序 participant SystemServices as 系統服務 participant Launcher as 應用程式(桌面) Bootloader->>Kernel: 載入核心 Kernel->>Kernel: 初始化 Kernel->>Init: 啟動 init 程序 Init->>Init: 讀取系統配置檔案 Init->>Zygote: 啟動 Zygote 程序 Zygote->>Zygote: 預載入常用的 Java 類和資源 Zygote->>SystemServices: 啟動系統服務 SystemServices->>Launcher: 啟動桌面程式
  • 1.引導載入程式(Bootloader)啟動: 當裝置上電或者重啟時,首先會由引導載入程式負責啟動。引導載入程式通常儲存在裝置的韌體中,它的主要任務是初始化硬體,並載入並啟動作業系統核心。引導載入程式會首先執行自身的初始化程式碼,然後載入作業系統核心到記憶體中。
  • 2.核心載入: 引導載入程式會根據預定義的配置從裝置儲存中載入作業系統核心。在Android裝置中,通常使用的是Linux核心。引導載入程式將核心載入到記憶體中的指定位置。
  • 3.核心初始化: 一旦核心載入到記憶體中,引導載入程式會將控制權轉交給核心。核心開始執行初始化過程,包括對硬體進行初始化、建立虛擬檔案系統、建立程序和執行緒等。
  • 4.啟動 init 程序: 核心初始化完成後,會啟動名為init的使用者空間程序。init程序是Android系統的第一個使用者空間程序,它負責系統的進一步初始化和啟動。init程序會讀取系統配置檔案(例如 init.rc),並根據其中的指令啟動系統服務和應用程式。
  • 5.啟動 Zygote 程序: 在init程序啟動後,會啟動名為Zygote的程序。Zygote程序是Android應用程式的孵化器,它會預載入常用的Java類和資源,以加速應用程式的啟動。
  • 6.啟動系統服務: 在Zygote程序啟動後,還會啟動一系列系統服務,例如SurfaceFlinger、ActivityManager、PackageManager等。這些系統服務負責管理系統的各個方面,包括顯示、應用程式生命週期、包管理等。
  • 7.啟動桌面程式: 一旦系統服務啟動完成,Android系統就處於可用狀態。就會啟動桌面程式,使用者可以開始啟動應用程式並使用裝置進行各種操作了。

計算機啟動過程Linux核心Kernel啟動過程已經介紹了計算機啟動和核心載入,所以本篇文章從Zygote程序開始介紹。

二、Zygote程序(孵化器程序)

1.Zygote簡介

  • Zygote程序是一個使用者程序,由init程序(1號程序)fork而來。
  • Zygote程序的主要任務是載入系統的核心類庫(如Java核心庫和Android核心庫)和安卓系統服務(SystemService),然後進入一個迴圈,等待請求來建立新的 Android 應用程式程序。
  • Zygote程序透過fork的方式建立新的應用程式程序。

2.Zygote程序的建立

Zygote程序在系統啟動時由init程序建立。init程序是Linux系統中的第一個使用者空間程序,它透過解析init.rc檔案來啟動各種服務和程序,包括Zygote。具體流程如下:

2.1 啟動init程序:

  • 系統啟動後,核心會載入並執行init程序
  • init程序讀取並解析init.rc配置檔案。

init程序的啟動可參考Linux核心Kernel啟動過程

2.2 init.rc指令碼:

init.rc檔案中包含啟動Zygote的指令指令碼的主要程式碼:

// 建立zygote服務
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
// 建立zygote socket,與系統和應用程式做通訊
socket zygote stream 660 root system
// 定義了zygote服務重啟時的一些操作
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server:

  • service zygote: 定義一個名為zygote的服務
  • /system/bin/app_process:這是啟動Zygote程序的可執行檔案,64位系統為app_process64
  • -Xzygote:標誌表明這是一個Zygote程序啟動的特殊模式。
  • /system/bin:指定程序的工作目錄。
  • --zygote:告訴app_process以Zygote模式啟動。
  • --start-system-server:Zygote啟動時還要啟動System Server程序,這是Android系統中管理關鍵系統服務的核心程序。

class main:

  • 將Zygote服務歸類為main類別。
  • Android系統在啟動過程中會啟動所有“main”類別的服務。

socket zygote stream 660 root system:
建立了一個名為zygote的UNIX域Socket套接字,用於其他程序與Zygote程序通訊。

onrestart write /sys/android_power/request_state wake
當zygote服務重啟時,系統應該將“/sys/android_power/request_state”檔案的內容設定為“wake”,以喚醒裝置。

onrestart write /sys/power/state on
當zygote服務重啟時,系統應該將“/sys/power/state”檔案的內容設定為 “on”,以開啟電源。

onrestart restart media
當zygote服務重啟時,系統應該重啟媒體服務(如音訊、影片等),以恢復媒體功能。

onrestart restart netd
當zygote服務重啟時,系統應該重啟網路守護程序(netd),以恢復網路功能。

2.3 app_process檔案

/system/bin/app_process是Android中的一個關鍵可執行檔案,負責啟動Zygote程序和應用程序。

Android14的app_process原始碼地址

2.3.1 main方法

app_process主入口點是main方法,它是整個程序啟動流程的起點。以下是其主要程式碼和解釋:

以下是關鍵程式碼說明:

int main(int argc, char* const argv[])
{
    // 建立並初始化AppRuntime物件runtime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    
    // 初始化引數zygote,startSystemServer,application,niceName,className
    // 程式碼見原始碼,此處略
    
    // 解析命令列引數
    // 程式碼見原始碼,此處略

    // 構建傳遞給 Java 初始化類的引數列表
    // 程式碼見原始碼,此處略
    
    if (zygote) {
        // 呼叫AppRuntime的start方法,開始載入ZygoteInit類
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.isEmpty()) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

2.3.2 AppRuntime類(AndroidRuntime)

AppRuntime繼承自AndroidRuntime(ART),是Android中的一個關鍵類,負責管理和啟動 Android 應用程式或系統服務的 Java 虛擬機器 (JVM)。

Android14的AndroidRuntime原始碼地址

2.3.2.1 AndroidRuntime類的start方法

app_process的main方法呼叫了AppRuntime的start方法,也就是AppRuntime的父類AndroidRuntime的start方法

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    // 初始化Java Native Interface (JNI)。JNI是Java和C/C++之間的介面,它允許Java程式碼和C/C++程式碼相互呼叫
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    
    JNIEnv* env;  // JNIEnv環境指標
    // 初始化虛擬機器
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }

    // 註冊JNI方法
    if (startReg(env) < 0) {
        return;
    }

    /*
     * 以下程式碼執行後,當前執行緒(即執行 AndroidRuntime::start 方法的執行緒)將成為Java虛擬機器(JVM)的主執行緒,並且在呼叫env->CallStaticVoidMethod啟動指定的Java類的 main 方法後,這個方法不會返回,直到 JVM 退出為止。(官方文件說明)
     */
    
    // 將"com.android.internal.os.ZygoteInit"轉換為"com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        // 沒有找到ZygoteInit.main()方法
    } else {
        // 透過JNI呼叫ZygoteInit.main()方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
    }
}
  • 建立虛擬機器
  • 註冊JNI方法
  • 透過JNI呼叫ZygoteInit.main()

3.Zygote程序

AndroidRuntimestart方法,透過JNI呼叫ZygoteInit.main(),系統第一次進入Java層(ZygoteInit是系統執行的第一個Java類),當前執行緒也正式成為Java虛擬機器(JVM)的主執行緒。

Android14的ZygoteInit原始碼地址

3.1 ZygoteInit.main()

透過main方法完成資源預載入、啟動系統服務等功能,為Launcher桌面程式做準備。

public static void main(String[] argv) {
    // 建立ZygoteServer
    ZygoteServer zygoteServer = null;
    ...
    // 預載入資源
    preload(bootTimingsTraceLog);
    ...
    // 初始化ZygoteServer
    zygoteServer = new ZygoteServer(isPrimaryZygote);
    ...
    // 透過fork的形式初始化SystemServer
    Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
    if (r != null) {
        r.run();
        return;
    }
    ...
    // 啟動Loop,監聽訊息
    caller = zygoteServer.runSelectLoop(abiList);
    ...
}

3.2 ZygoteInit.preload()預載入

透過preload方法預載入系統常用的類、資源和庫,能夠顯著減少應用啟動時的延遲,並透過共享這些預載入的內容來降低記憶體使用,提高系統效能。

static void preload(TimingsTraceLog bootTimingsTraceLog) {
    preloadClasses(); //載入常用的Java類
    preloadResources(); //載入常用的資源(如佈局、圖片等)
    preloadOpenGL(); //載入OpenGL庫
    preloadSharedLibraries(); //載入常用的本地共享庫
    preloadTextResources(); //載入常用的文字資源
    ...
}

3.2.1 常用類

  • Android框架中的基礎類,如Activity、Service、BroadcastReceiver等。
  • 常用的UI元件類,如TextView、Button、ImageView等。

3.2.2 常用資源

常用佈局檔案(layout)。
常用圖片資源(drawable)。
常用字串(strings.xml)。

3.2.3 常用庫

標準C庫(libc.so)。
圖形處理庫(libskia.so)。
OpenGL ES庫(libGLESv2.so)。

3.3 啟動System Server

System Server是Android系統中的關鍵程序,負責啟動和管理核心系統服務。

啟動過程的核心程式碼:

public static void main(String argv[]) {
    // 初始化ZygoteServer
    ZygoteServer zygoteServer = new ZygoteServer();
    // 啟動System Server
    if (startSystemServer) {
        startSystemServer(abiList, socketName, zygoteServer);
    }
    // 進入Zygote的主迴圈,等待新程序的啟動請求
    zygoteServer.runSelectLoop();
}

private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {
    /* 呼叫native方法fork系統伺服器 */
    int pid = Zygote.forkSystemServer(...);
    if (pid == 0) {
        // 在子程序中執行System Server的main方法
        handleSystemServerProcess(parsedArgs);
    }
}

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
    // 透過反射呼叫SystemServer的main方法
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    Class<?> clz = cl.loadClass("com.android.server.SystemServer");
    Method m = clz.getMethod("main", new Class[] { String[].class });
    m.invoke(null, new Object[] { parsedArgs.remainingArgs });
}

  • ZygoteServer是一個Socket,Zygote程序透過這個Socket和SystemService及其他應用程式程序做通訊
  • 透過fork建立的SystemServer程序是一個獨立執行的程序,避免SystemServer程序受到其他程序的影響。
  • 關於SystemServer,後面還會更詳細的介紹

三、系統服務 System Server

Zygote中透過Zygote.forkSystemServer方法建立了System Server程序,然後透過Java的反射機制呼叫com.android.server.SystemServermain方法來啟動System Server。

Android14的System Server原始碼地址

3.1 SystemServer.java

SystemServer.javamain方法呼叫了自身的run方法,在run方法中啟動了具體的系統服務,程式碼如下:

public static void main(String[] args) {
    new SystemServer().run();
}

private void run() {
    // 初始化系統屬性,時區、語言、環境等,程式碼略
    ...
    // 載入本地服務
    System.loadLibrary("android_servers");
    ...
    // 初始化系統上下文
    createSystemContext();
    // 初始化主線模組
    ActivityThread.initializeMainlineModules();
    ...
    // 建立系統服務管理器
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    ...

    /* 啟動系統服務 */
    // 啟動引導服務
    startBootstrapServices(t);
    // 啟動核心服務
    startCoreServices(t);
    // 啟動其他服務
    startOtherServices(t);
    // 啟動 APEX 服務
    startApexServices(t);
    ...
}

3.2 System Server啟動的主要服務

以下為System Server啟動的主要服務列表,具體實現可在原始碼中檢視。

服務名稱 功能說明
Activity Manager Service (AMS) 管理應用程式的生命週期,包括啟動和停止應用、管理任務和活動棧、處理廣播等
Package Manager Service (PMS) 管理應用包的安裝、解除安裝、更新、許可權分配等
System Config Service 管理系統配置和資源
Power Manager Service 管理裝置的電源狀態和電源策略,如休眠、喚醒等
Display Manager Service 管理顯示裝置,如螢幕亮度、顯示模式等
User Manager Service 管理使用者賬戶和使用者資訊
Battery Service 監控和管理電池狀態和電池使用情況
Vibrator Service 控制裝置的振動功能
Sensor Service 管理裝置的感測器,如加速度計、陀螺儀等
Window Manager Service (WMS) 管理視窗和顯示內容,包括視窗的建立、刪除、佈局等
Input Manager Service 管理輸入裝置,如觸控式螢幕、鍵盤等
Alarm Manager Service 提供定時任務排程功能
Connectivity Service 管理網路連線,如 Wi-Fi、移動資料等
Network Management Service 管理網路介面和網路連線
Telephony Registry 管理電話和簡訊服務
Input Method Manager Service (IMMS) 管理輸入法框架
Accessibility Manager Service 管理無障礙服務,為有特殊需要的使用者提供輔助功能
Mount Service 管理儲存裝置的掛載和解除安裝
Location Manager Service 管理位置服務,如 GPS 和網路定位
Search Manager Service 管理系統搜尋功能
Clipboard Service 管理剪貼簿功能
DevicePolicy Manager Service 管理裝置的安全策略和企業管理功能
Status Bar Service 管理狀態列顯示和操作
Wallpaper Manager Service 管理桌布設定和操作
Media Router Service 管理媒體裝置路由

在系統服務全部啟動完成後,就開始啟動系統桌面程式Launcher了。

四、桌面程式Launcher

sequenceDiagram participant SystemServer participant ActivityManagerService participant ActivityTaskManagerService participant RootWindowContainer participant ActivityStartController participant Home SystemServer->>ActivityManagerService: systemReady() ActivityManagerService->>ActivityTaskManagerService: startHomeOnAllDisplays ActivityTaskManagerService->>RootWindowContainer: startHomeOnAllDisplays RootWindowContainer->>ActivityStartController: startHomeActivity ActivityStartController->>Home: Home application (Launcher) is started
  • SystemServer 啟動所有服務: SystemServer類在run方法中呼叫startOtherServices方法,啟動其他系統服務,包括ActivityManagerService。
  • ActivityManagerService準備系統: ActivityManagerService 在systemReady方法中呼叫mAtmInternal.startHomeOnAllDisplays方法,開始在所有顯示器上啟動桌面程式。
  • ActivityTaskManagerService啟動: Home Activity:ActivityTaskManagerService 呼叫RootWindowContainer的startHomeOnAllDisplays方法。
  • RootWindowContainer迴圈所有顯示器: RootWindowContainer 遍歷每個顯示器,並呼叫startHomeOnDisplay方法。
  • 啟動Home Activity: 在每個顯示器上,透過TaskDisplayArea呼叫ActivityStartController的startHomeActivity方法,最終呼叫ActivityManagerService的startActivity方法啟動Home Activity。
  • Home應用啟動: ActivityManagerService處理啟動請求,啟動Home應用的Activity展示桌面介面。

核心程式碼流轉:

4.1 SystemServer.java

Android14的System Server原始碼地址

private void run() {
    ...
    // 啟動其他服務
    startOtherServices(t);
    ...
}

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
    // 啟動ActivityManagerService
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    ...
    // 啟動Launcher
    mActivityManagerService.systemReady(...)
    ...
}

4.2 桌面程式Launcher(Home)的啟動流程

4.2.1 ActivityManagerService.java

Android14的ActivityManagerService原始碼地址

public void systemReady(final Runnable goingCallback, TimingsTraceAndSlog t) {
    ...
    // 在所有顯示器上啟動Launcher
    mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
    ...
}
  • 此行程式碼最終會呼叫到ActivityTaskManagerService.javastartHomeOnAllDisplays方法

4.2.2 ActivityTaskManagerService.java

Android14的ActivityTaskManagerService原始碼地址

void startHomeOnAllDisplays(int userId, String reason) {
    synchronized (mGlobalLock) {
        // 在所有顯示器上啟動Launcher
        return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
    }
}
  • 此行程式碼最終會呼叫到RootWindowContainer.javastartHomeOnAllDisplays方法

4.2.3 RootWindowContainer.java

Android14的RootWindowContainer原始碼地址


boolean startHomeOnAllDisplays(int userId, String reason) {
    boolean homeStarted = false;
    for (int i = getChildCount() - 1; i >= 0; i--) {
        final int displayId = getChildAt(i).mDisplayId;
        // 在每一個顯示器上啟動桌面程式
        homeStarted |= startHomeOnDisplay(userId, reason, displayId);
    }
    return homeStarted;
}

boolean startHomeOnDisplay(int userId, String reason, int displayId) {
    return startHomeOnDisplay(userId, reason, displayId, false, false);
}

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey) {
    ...
    // 呼叫startHomeOnTaskDisplayArea
    return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
                    result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
                            allowInstrumenting, fromHomeKey),false);
}

boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
        boolean allowInstrumenting, boolean fromHomeKey) {
    ...
    Intent homeIntent = mService.getHomeIntent();
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            taskDisplayArea);
    ...
    return true;
}

  • 最終透過Intent和startHomeActivity方法啟動了桌面程式

五、總結

透過上述介紹,從使用者按下電源鍵開始,經過Bootloader啟動、核心啟動、init程序啟動、Zygote程序啟動、SystemServer程序啟動,以及系統應用的啟動,最終進入桌面環境。

每個階段都的核心工作:

  1. Bootloader啟動:初始化硬體並載入核心。

  2. 核心啟動:核心是作業系統的核心,負責管理系統資源和硬體裝置。

  3. init程序啟動:init程序透過解析init.rc檔案來啟動和配置系統服務。

  4. Zygote程序啟動:Zygote是Android系統的獨有設計,負責建立應用程序。透過預載入資源和共享記憶體,Zygote大大提高了應用啟動的速度和系統資源的利用率。

  5. SystemServer程序啟動:SystemServer程序啟動了大量系統服務,如Activity Manager和Package Manager等,這些服務構成了Android系統的骨幹,管理和協調應用的執行。

  6. 啟動系統應用:Launcher應用的啟動標誌著系統啟動的完成。使用者進入桌面,可以開始正常使用裝置。

透過深入理解Android的啟動流程,可以更有效地進行系統開發和維護,從而提供更高效能和更穩定的使用者體驗。

如有任何疑問或建議,歡迎留言討論。

相關文章