Android 啟動(dòng)流程

image.png
image.png

1、Loader
Loader層首先就是Boot ROM,當(dāng)手機(jī)處于關(guān)機(jī)狀態(tài)時(shí),長(zhǎng)按電源鍵開機(jī),引導(dǎo)芯片從固化在ROM里的預(yù)設(shè)代碼開始執(zhí)行,然后機(jī)制引導(dǎo)程序到RAM中。
而Boot Loader就是引導(dǎo)程序,主要是檢查RAM,初始化硬件參數(shù)等功能。
Linux內(nèi)核層前面我們知道Android系統(tǒng)是基于Linux內(nèi)核,而這時(shí)會(huì)啟動(dòng)Linux內(nèi)核的倆個(gè)主要進(jìn)程:

2、Kernel
啟動(dòng)Kernel的swapper進(jìn)程(pid=0),該進(jìn)程又稱為是idle進(jìn)程,是Kernel由無(wú)到有的第一個(gè)進(jìn)程,用于初始化進(jìn)程管理、內(nèi)存管理,加載Display、Camera Driver、Binder Driver等工作。
啟動(dòng)kthreadd進(jìn)程(pid=2),該進(jìn)程是Linux系統(tǒng)的內(nèi)核進(jìn)程,會(huì)創(chuàng)建內(nèi)核工作線程kworkder,軟中斷線程ksoftirqd等內(nèi)核守護(hù)進(jìn)程。kthreadd進(jìn)程是所有內(nèi)核進(jìn)程的鼻祖。

3、C++ Framework
Native層上面所說(shuō)的都是Linux內(nèi)核進(jìn)程,而到Native層會(huì)創(chuàng)建init進(jìn)程(pid=1),該進(jìn)程是用戶進(jìn)程,也是所有用戶進(jìn)程的鼻祖。
init進(jìn)程的主要作用:

init進(jìn)程會(huì)孵化出ueventd、logd、installd、adbd等用戶守護(hù)進(jìn)程(系統(tǒng)必需的一些服務(wù))。
init進(jìn)程還會(huì)啟動(dòng)servicemanager(binder服務(wù)管家)、bootanim開機(jī)動(dòng)畫等重要服務(wù)。
init進(jìn)程還會(huì)孵化出用來(lái)管理C++ Framework庫(kù)的Media Server進(jìn)程。
init進(jìn)程會(huì)孵化出Zygote進(jìn)程,Zygote進(jìn)程是Android系統(tǒng)第一個(gè)Java進(jìn)程(虛擬機(jī)進(jìn)程),所以Zygote是所有Java進(jìn)程的父進(jìn)程。

而這里Native層和Linux內(nèi)核層的通信是利用系統(tǒng)調(diào)用,關(guān)于系統(tǒng)調(diào)用簡(jiǎn)單來(lái)說(shuō)就是Linux內(nèi)核為了防止用戶態(tài)的程序隨意調(diào)用內(nèi)核代碼導(dǎo)致內(nèi)核掛掉,所有想使用內(nèi)核的服務(wù)都必須通過(guò)系統(tǒng)調(diào)用。
這里有一些同學(xué)之前認(rèn)為C++層的代碼就是內(nèi)核層,其實(shí)不是的,真正內(nèi)核層的只有Linux內(nèi)核層,Native層是用戶態(tài)的C/C++實(shí)現(xiàn)部分。
Java Framework層Zygote進(jìn)程是由init進(jìn)程通過(guò)解析init.rc后fork而來(lái),由Zygote進(jìn)程開啟Java世界,主要包括:

4、Framework
加載ZygoteInit類,注冊(cè)Zygote Socket服務(wù)端套接字,這個(gè)是為了響應(yīng)后面fork新進(jìn)程的需求。
加載虛擬機(jī),即創(chuàng)建ART虛擬機(jī)。
預(yù)加載類preloadClass。
預(yù)加載資源preloadResources。
然后Zygote進(jìn)程還會(huì)孵化出System Server進(jìn)程,該進(jìn)程同時(shí)也是Zygote孵化的第一個(gè)進(jìn)程,該進(jìn)程非常熟悉了,它管理著Java framework,包括AMS、WMS等各種服務(wù)。
這里有個(gè)非常重要的點(diǎn),就說(shuō)JNI技術(shù),通過(guò)JNI技術(shù)打通了Java世界和C/C++世界。

5、APPS
應(yīng)用層Zygote進(jìn)程會(huì)孵化出第一個(gè)APP進(jìn)程就是Launcher了,即桌面APP,每個(gè)APP至少運(yùn)行在一個(gè)進(jìn)程上,而這些進(jìn)程都是由Zygote進(jìn)程孵化而來(lái)。

經(jīng)過(guò)上面的流程梳理,我們更可以發(fā)現(xiàn)Android系統(tǒng)設(shè)計(jì)的巧妙,每一層都有對(duì)應(yīng)的作用,都由相應(yīng)的進(jìn)程來(lái)管理,我們可以通過(guò)Linux的ps命令來(lái)簡(jiǎn)單查看當(dāng)前系統(tǒng)的所有進(jìn)程。

C++ Framework

Linux 內(nèi)核啟動(dòng)過(guò)程中會(huì)創(chuàng)建 init 進(jìn)程,init 進(jìn)程是用戶空間的第一個(gè)進(jìn)程(pid=1),對(duì)應(yīng)的可執(zhí)行程序的源文件文件為 它的 main 方法如下:
[/system/core/init/Main.cpp]

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"

#include <android-base/logging.h>

#if __has_feature(address_sanitizer)
#include <sanitizer/asan_interface.h>
#endif

#if __has_feature(address_sanitizer)
// Load asan.options if it exists since these are not yet in the environment.
// Always ensure detect_container_overflow=0 as there are false positives with this check.
// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
extern "C" const char* __asan_default_options() {
    return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
}

__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
__sanitizer_report_error_summary(const char* summary) {
    LOG(ERROR) << "Init (error summary): " << summary;
}

__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
AsanReportCallback(const char* str) {
    LOG(ERROR) << "Init: " << str;
}
#endif

using namespace android::init;

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

android 13 .rc 文件位置
/system/core/rootdir/init.rc
1、里面包含了 ueventd 的啟動(dòng),

## Daemon processes to be run by init.
##
service ueventd /system/bin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical

service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0
    setenv HOSTNAME console

2、包含了 servermanager 啟動(dòng)

start servicemanager
start hwservicemanager
start vndservicemanager
AndroidRuntime

AndroidRuntime.cpp
start
startVm
startReg //注冊(cè)JNI
反射調(diào)用ZygoteInit.java 的main

/*
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
    bool primary_zygote = false;

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {
            primary_zygote = true;
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }

    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);

    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

ZygoteInit.java
main()
preLoad();//預(yù)加載

 static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
        beginPreload();
        bootTimingsTraceLog.traceEnd(); // BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
        cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
        maybePreloadGraphicsDriver();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endPreload();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

/system/bin/app_process64
是通過(guò) zygote fork 出來(lái), 具備vm 和完整 sdk結(jié)構(gòu) , 可執(zhí)行 dex文件;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android啟動(dòng)流程 個(gè)人理解的Android啟動(dòng)流程,有沒有大佬幫忙看下對(duì)不對(duì)。 1. Loader層 Boo...
    懶貓1105閱讀 807評(píng)論 0 2
  • 這篇是自己學(xué)習(xí)所用,請(qǐng)謹(jǐn)慎觀看,具體內(nèi)容可看下面博客:Android啟動(dòng)流程簡(jiǎn)析[https://www.jian...
    QGv閱讀 1,550評(píng)論 0 0
  • 啟動(dòng)過(guò)程 老是有在群里看到大佬們討論Android系統(tǒng)的第一個(gè)始祖進(jìn)程是init進(jìn)程,對(duì)于有過(guò)多年開發(fā)經(jīng)驗(yàn)的我,應(yīng)...
    鼻涕粑粑閱讀 1,303評(píng)論 0 5
  • Android面試季必問(wèn)——AMS的核心原理 系列Android啟動(dòng)流程 https://www.jianshu...
    flynnny閱讀 660評(píng)論 0 3
  • Android系統(tǒng)完成的啟動(dòng)流程,從系統(tǒng)層次角度可分為L(zhǎng)inux系統(tǒng)層、Android 系統(tǒng)服務(wù)層、Zygote進(jìn)...
    渾水摸魚哲閱讀 256評(píng)論 0 1

友情鏈接更多精彩內(nèi)容