首页
社区
课程
招聘
[原创]安卓启动流程初探
发表于: 2025-3-10 21:02 36600

[原创]安卓启动流程初探

2025-3-10 21:02
36600

APK,启动!

引导加载程序-内核启动-init进程启动-Zygote进程启动-System Server进程-启动框架和用户界面-应用程序启动

总体上,安卓的架构分布底层的内核空间以Linux Kernel为基础,上层的用户空间由Native系统库、虚拟机运行环境(ART)、框架层(Java API Framework)组成。两层空间由系统调用(Syscall)联通。

安卓架构示意图

相比于静态去看安卓的架构,任何系统是实时运行,不断交互的,逐步分析,庖丁解牛,可以发现架构间各层次的关系。

Boot Rom是记录了引导启动的只读寄存器(Read Only Memory),按下电源键后,改变引导芯片开始从固化在ROM里的预设代码开始执行,然后加载引导程序到RAM

随后,来到Boot Loader(我们熟悉的bl锁说的就是这里)启动安卓系统前的引导程序。 Bootloader有时被锁定,以防止未经授权的系统修改

Hardware Abstraction Layer 其中有多个库模块(蓝牙wifi等),当java框架层要访问硬件就会用到这

其中涉及到了我们最想关注的安卓层面的加载流程,虚拟机的作用就不再多说,经过swapper进程在native层启动了Init进程(pid = 1,也就是安卓源码中的init.cpp)init进程是所有用户进程的鼻祖为什么这么说,看他的作用

在此层次中,init进程解析了init.rc文件fork生成了关键的Zygote进程(翻译为受精卵,此进程也称为安卓的应用进程孵化器,是所有应用进程的父进程)对于此孵化进程,他会加载

Zygote孵化的第一个进程是System Server,此进程负责启动与管理整个Java Framework 包含了ActivityManager,WindowManager,PackageManager,PowerManager等服务。

Media Server不是由Zygote进程孵化而来的,而是由init生成,他负责启动与管理C++ framework包含AudioFlinger,Camera Service等服务。

Zygote进程孵化出的第一个app进程为Launcher,通俗来讲就是我们的桌面app;所有的app进程都是由zygote进程fork而来的

第一个系统调用是native与内核之间的联系,第二个JNI是java层与native层之间的联系

从内核启动的第一个进程init开始看,我们在相应的目录,也就是安卓源码/system/core/init/目录下的init.cpp文件

关注main函数,可以大致把init的加载流程分为一下几个部分

程序入口,判断调用uevent还是看门狗守护进程

第一阶段又分为以下几个部分

【最后步骤很关键,重新启动init的过程也讲加载的权限进一步降低,在整个第一阶段都是以权限极高的kernel执行,转化为init域后权限降低,更为安全,这个就是SELinux安全策略的作用】

第二阶段分为以下几个部分

至此章节开始的流程图初始化的Zygote和ServiceManager步骤就知道是在哪里实现的了

最后一部分是个主循环

Zygote的执行过程大致可以概括如下图,我们简单分析一下涉及到的源码和函数,蓝色加深的是涉及的三个源码

从上文我们知道了Zygote进程是在init.rc中创建的,他对应的可执行程序叫app_process,对应的源文件是app_main.cpp

较为关键的几个地方就是开始的AppRuntime初始化, 是后续启动 Android 平台服务或应用程序的核心接口。 他是AndroidRuntime的子类,通过调用会通过继承的方法调用AndroidRuntime中的方法

我们关注start中的函数,

此函数的体量过于庞大。主要的功能是设置了虚拟机的参数,利用了很多的parseRuntimeOption函数(对于不同的软硬件环境,函数的参数往往需要调整、优化,从而使系统达到最佳性能)

安卓6到10对源码进行了一些调整 但是基础功能并未做出太大变动,一下是gityuan师傅的安卓6.0的代码注释

这个函数层层套用,最终实现的功能就是启动一些native层的函数方法的注册

书接上文提到的AndroidRuntime.cpp的最后步骤,也就是

这里说的main就是ZygoteInit.main()(我们在app_main.cpp的最后是start了com.android.internal.os.ZygoteInit这个包,接下来就是去调用他的main)

在mian中是先开启了DDMS功能 然后为Zygote注册socket,preload函数预加载类和资源,启动SystemServer进程

最后用一张流程图概括Zygote的总体加载流程就很清楚了

我从始至终都坚信一点,那就是学校绝不会成为制约一个人成长的天花板,只要你肯学,只要你愿意努力,无论在哪,你就一定能有所作为。学校固然重要,但更重要的是自己的努力。为此,从研一便开始为自己的职业生涯做打算,并付之于行动。

学习力比知识更重要,因为知识可能落伍,但学习力能让你紧跟技术潮流,立于处不败之地。

Linux之父Linus Torvalds的一句名言:Read the fucking source code。

本文参考了很多Gityuan大师傅的博客文章,系统讲解了安卓的知识。

Android 操作系统架构开篇 - Gityuan博客 | 袁辉辉的技术博客

Android系统启动-zygote篇 - Gityuan博客 | 袁辉辉的技术博客

Android系统启动-Init篇 - Gityuan博客 | 袁辉辉的技术博客

安卓源码

int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
 
    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }
 
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
// namespace android
int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
 
    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }
 
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
// namespace android
add_environment("PATH", _PATH_DEFPATH);
 
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);//判断第一阶段
 
if (is_first_stage) {
    boot_clock::time_point start_time = boot_clock::now();
 
    // Clear the umask.
    umask(0);
    //这里加载必要的虚拟文件
     
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
    mkdir("/dev/socket", 0755);
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    #define MAKE_STR(x) __STRING(x)
    mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
    // Don't expose the raw commandline to unprivileged processes.
    chmod("/proc/cmdline", 0440);
    gid_t groups[] = { AID_READPROC };
    setgroups(arraysize(groups), groups);
    mount("sysfs", "/sys", "sysfs", 0, NULL);
    mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
    mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
    mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
    mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
 
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
    // talk to the outside world...
    InitKernelLogging(argv);
 
    LOG(INFO) << "init first stage started!";
 
    if (!DoFirstStageMount()) {
        LOG(ERROR) << "Failed to mount required partitions early ...";
        panic();
    }
 
    SetInitAvbVersionInRecovery();
    //这里设置SELinux安全策略
    // Set up SELinux, loading the SELinux policy.
    selinux_initialize(true);
 
    //恢复/init文件上下文
    // We're in the kernel domain, so re-exec init to transition to the init domain now
    // that the SELinux policy has been loaded.
    if (selinux_android_restorecon("/init", 0) == -1) {
        PLOG(ERROR) << "restorecon failed";
        security_failure();
    }
    //说明已经执行过了第一阶段
    setenv("INIT_SECOND_STAGE", "true", 1);
 
    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
    uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
    setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
 
    char* path = argv[0];
    char* args[] = { path, nullptr };
    //重新启动init程序/经过此步骤的重新加载,权限降低
    execv(path, args);
 
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(ERROR) << "execv(\"" << path << "\") failed";
    security_failure();
}
add_environment("PATH", _PATH_DEFPATH);
 
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);//判断第一阶段
 
if (is_first_stage) {
    boot_clock::time_point start_time = boot_clock::now();
 
    // Clear the umask.
    umask(0);
    //这里加载必要的虚拟文件
     
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
    mkdir("/dev/socket", 0755);
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    #define MAKE_STR(x) __STRING(x)
    mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
    // Don't expose the raw commandline to unprivileged processes.
    chmod("/proc/cmdline", 0440);
    gid_t groups[] = { AID_READPROC };
    setgroups(arraysize(groups), groups);
    mount("sysfs", "/sys", "sysfs", 0, NULL);
    mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
    mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
    mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
    mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
 
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
    // talk to the outside world...
    InitKernelLogging(argv);
 
    LOG(INFO) << "init first stage started!";
 
    if (!DoFirstStageMount()) {
        LOG(ERROR) << "Failed to mount required partitions early ...";
        panic();
    }
 
    SetInitAvbVersionInRecovery();
    //这里设置SELinux安全策略
    // Set up SELinux, loading the SELinux policy.
    selinux_initialize(true);
 
    //恢复/init文件上下文
    // We're in the kernel domain, so re-exec init to transition to the init domain now
    // that the SELinux policy has been loaded.
    if (selinux_android_restorecon("/init", 0) == -1) {
        PLOG(ERROR) << "restorecon failed";
        security_failure();
    }
    //说明已经执行过了第一阶段
    setenv("INIT_SECOND_STAGE", "true", 1);
 
    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
    uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
    setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
 
    char* path = argv[0];
    char* args[] = { path, nullptr };
    //重新启动init程序/经过此步骤的重新加载,权限降低
    execv(path, args);
 
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(ERROR) << "execv(\"" << path << "\") failed";
    security_failure();
}
//文件与属性的初始化操作
// At this point we're in the second stage of init.
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
 
    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
 
    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
    property_init();
 
    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    process_kernel_dt();
    process_kernel_cmdline();
 
    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    export_kernel_boot_props();
 
    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
 
    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
    // Clean up our environment.
    unsetenv("INIT_SECOND_STAGE");
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
     
    //重新初始化SELinux
 
    // Now set up SELinux for second stage.
    selinux_initialize(false);
    selinux_restore_context();
 
    //事件与信号处理
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }
 
    signal_handler_init();
//进一步解析脚本
    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    set_usb_controller();
 
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
 
    ActionManager& am = ActionManager::GetInstance();
    ServiceManager& sm = ServiceManager::GetInstance();
    Parser& parser = Parser::GetInstance();
 
    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    //解析init.rc脚本,我们最关注的Zygote进程会在这里进一步初始化
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }
 
//事件管理与服务启动
 
    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();
 
    am.QueueEventTrigger("early-init");
 
    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    am.QueueBuiltinAction(console_init_action, "console_init");
 
    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");
 
    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }
 
    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
//文件与属性的初始化操作
// At this point we're in the second stage of init.
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
 
    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
 
    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
    property_init();
 
    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    process_kernel_dt();
    process_kernel_cmdline();
 
    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    export_kernel_boot_props();
 
    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
 
    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
    // Clean up our environment.
    unsetenv("INIT_SECOND_STAGE");
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
     
    //重新初始化SELinux
 
    // Now set up SELinux for second stage.
    selinux_initialize(false);
    selinux_restore_context();
 
    //事件与信号处理
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }
 
    signal_handler_init();
//进一步解析脚本
    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    set_usb_controller();
 
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
 
    ActionManager& am = ActionManager::GetInstance();
    ServiceManager& sm = ServiceManager::GetInstance();
    Parser& parser = Parser::GetInstance();
 
    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
    parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    //解析init.rc脚本,我们最关注的Zygote进程会在这里进一步初始化
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }
 
//事件管理与服务启动
 
    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();
 
    am.QueueEventTrigger("early-init");
 
    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    am.QueueBuiltinAction(console_init_action, "console_init");
 
    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");
 
    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }
 
    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;
 
        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }
 
        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
            if (!shutting_down) restart_processes();
 
            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }
 
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }
 
        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
 
    return 0;
}
    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;
 
        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }
 
        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || sm.IsWaitingForExec())) {
            if (!shutting_down) restart_processes();
 
            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }
 
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }
 
        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
 
    return 0;
}
int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.c_str());
    }
 
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    argc--;
    argv++;
 
 
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;
 
    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
 
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }
 
        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }
 
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
 
        runtime.addOption(strdup(argv[i]));
 
        ALOGV("app_process main add option '%s'", argv[i]);
    }
//运行模式
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
 
    //提取argv中的模式与参数
    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = (arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className = arg;
            break;
        } else {
            --i;
            break;
        }
    }
 
    Vector<String8> args;
    if (!className.empty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
 
        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.c_str(), restOfArgs.c_str());
        }
    } else {
        //这里是在Zygote模式
        // We're in zygote mode.
        maybeCreateDalvikCache();//确保 Dalvik 缓存存在(如有必要则创建)
 
        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }
 
        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }
 
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);//从系统属性中获取 ABI 列表(支持的架构),并将其作为 --abi-list 选项传递给 Zygote。
        args.add(abiFlag);
 
        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
 
    if (!niceName.empty()) {
        runtime.setArgv0(niceName.c_str(), true /* setProcName */);
    }
//最后的部分是启动了java中的这个类/或者是独立模式
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.empty()) {
        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.");
    }
}
int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.c_str());
    }
 
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    argc--;
    argv++;
 
 
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;
 
    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
 
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }
 
        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }
 
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
 
        runtime.addOption(strdup(argv[i]));
 
        ALOGV("app_process main add option '%s'", argv[i]);
    }
//运行模式
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
 
    //提取argv中的模式与参数
    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = (arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className = arg;
            break;
        } else {
            --i;
            break;
        }
    }
 
    Vector<String8> args;
    if (!className.empty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2025-3-13 22:10 被xianyuuuan编辑 ,原因:
收藏
免费 27
支持
分享
最新回复 (17)
雪    币: 470
活跃值: (408)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
tql
2025-3-11 11:37
0
雪    币: 3042
活跃值: (2589)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
study
2025-3-18 14:22
0
雪    币: 30
活跃值: (1530)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
666
2025-3-26 08:42
0
雪    币: 603
活跃值: (655)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
66666
2025-3-26 14:57
0
雪    币: 39878
活跃值: (65356)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
6
2025-3-27 11:37
0
雪    币: 413
活跃值: (837)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
6666666666
2025-4-1 16:07
0
雪    币: 1002
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
666
2025-4-5 21:01
0
雪    币: 11852
活跃值: (18709)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
引导加载程序-内核启动
2025-4-5 22:34
0
雪    币: 3
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
1
2025-4-7 00:03
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
1
2025-4-8 14:10
0
雪    币: 3643
活跃值: (1891)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
1
2025-4-11 10:11
0
雪    币: 453
活跃值: (2188)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
13
1
2025-4-12 14:40
0
雪    币: 3934
活跃值: (5768)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
学校绝不会成为制约一个人成长的天花板,只要你肯学,只要你愿意努力,无论在哪,你就一定能有所作为;是的,知识虽然会落伍,但有些知识不会落伍,而且知识和能力是分不开的,比如关于思维方法,怎么做好事情,这些也是知识,却不会落伍,还能提高能力
2025-4-15 06:04
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
1
2025-4-15 11:24
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
支持
2025-4-15 14:07
0
雪    币: 250
活跃值: (1534)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
看看
2025-5-5 12:42
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
dddd
1天前
0
游客
登录 | 注册 方可回帖
返回