美文网首页
Android 启动流程

Android 启动流程

作者: LiuJP | 来源:发表于2024-04-15 00:44 被阅读0次
    image.png image.png

    1、Loader
    Loader层首先就是Boot ROM,当手机处于关机状态时,长按电源键开机,引导芯片从固化在ROM里的预设代码开始执行,然后机制引导程序到RAM中。
    而Boot Loader就是引导程序,主要是检查RAM,初始化硬件参数等功能。
    Linux内核层前面我们知道Android系统是基于Linux内核,而这时会启动Linux内核的俩个主要进程:

    2、Kernel
    启动Kernel的swapper进程(pid=0),该进程又称为是idle进程,是Kernel由无到有的第一个进程,用于初始化进程管理、内存管理,加载Display、Camera Driver、Binder Driver等工作。
    启动kthreadd进程(pid=2),该进程是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd等内核守护进程。kthreadd进程是所有内核进程的鼻祖。

    3、C++ Framework
    Native层上面所说的都是Linux内核进程,而到Native层会创建init进程(pid=1),该进程是用户进程,也是所有用户进程的鼻祖。
    init进程的主要作用:

    init进程会孵化出ueventd、logd、installd、adbd等用户守护进程(系统必需的一些服务)。
    init进程还会启动servicemanager(binder服务管家)、bootanim开机动画等重要服务。
    init进程还会孵化出用来管理C++ Framework库的Media Server进程。
    init进程会孵化出Zygote进程,Zygote进程是Android系统第一个Java进程(虚拟机进程),所以Zygote是所有Java进程的父进程。

    而这里Native层和Linux内核层的通信是利用系统调用,关于系统调用简单来说就是Linux内核为了防止用户态的程序随意调用内核代码导致内核挂掉,所有想使用内核的服务都必须通过系统调用。
    这里有一些同学之前认为C++层的代码就是内核层,其实不是的,真正内核层的只有Linux内核层,Native层是用户态的C/C++实现部分。
    Java Framework层Zygote进程是由init进程通过解析init.rc后fork而来,由Zygote进程开启Java世界,主要包括:

    4、Framework
    加载ZygoteInit类,注册Zygote Socket服务端套接字,这个是为了响应后面fork新进程的需求。
    加载虚拟机,即创建ART虚拟机。
    预加载类preloadClass。
    预加载资源preloadResources。
    然后Zygote进程还会孵化出System Server进程,该进程同时也是Zygote孵化的第一个进程,该进程非常熟悉了,它管理着Java framework,包括AMS、WMS等各种服务。
    这里有个非常重要的点,就说JNI技术,通过JNI技术打通了Java世界和C/C++世界。

    5、APPS
    应用层Zygote进程会孵化出第一个APP进程就是Launcher了,即桌面APP,每个APP至少运行在一个进程上,而这些进程都是由Zygote进程孵化而来。

    经过上面的流程梳理,我们更可以发现Android系统设计的巧妙,每一层都有对应的作用,都由相应的进程来管理,我们可以通过Linux的ps命令来简单查看当前系统的所有进程。

    C++ Framework

    Linux 内核启动过程中会创建 init 进程,init 进程是用户空间的第一个进程(pid=1),对应的可执行程序的源文件文件为 它的 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 的启动,

    ## 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 启动

    start servicemanager
    start hwservicemanager
    start vndservicemanager
    
    AndroidRuntime

    AndroidRuntime.cpp
    start
    startVm
    startReg //注册JNI
    反射调用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();//预加载

     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
    是通过 zygote fork 出来, 具备vm 和完整 sdk结构 , 可执行 dex文件;

    相关文章

      网友评论

          本文标题:Android 启动流程

          本文链接:https://www.haomeiwen.com/subject/rmllxjtx.html