安卓手机启动时发生的那些事儿——中篇

2020-11-07  本文已影响0人  邱穆

上篇文章我们谈到安卓手机启动时的前两部分,分别是BIOS和BootLoader阶段、Linux内核启动阶段,这篇文章,我们就来一起学习真正的进入安卓系统的启动流程。

一、概览

首先复习一下上篇所学,在安卓手机上,整个系统的启动可以分为三个过程,如下:

第一阶段主要由硬件和汇编语言完成,第二部分主要由C语言完成,第三部分主要由java完成。下面我们一起进入这第三部分的学习。

二、Linux内核启动安卓系统

上篇文章我们学到了运行Linux内核中的start_kernel(),然后start_kernel()函数最后通过调用kernel_thread()寻找init.rc文件,并启动init进程(pid = 1)。这一部分也就进行到了Native层,Linux 中的所有进程都是有init进程创建并运行的。Native层主要包括 init 进程以及其 fork 出来的用户空间的守护进程、 HAL 层、开机动画等。init进程是所有用户进程的鼻祖。其启动的主要内容如下:

init进程的入口函数主要代码如下:

/*位于安卓源码的system/core/init/init.cpp文件*/
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) {
        install_reboot_signal_handlers();
    }

    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();

        // 清理umask.
        umask(0);

        // 创建和挂载启动所需的文件目录
        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));
        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));
        InitKernelLogging(argv);
        ······
    }
    //对属性服务进行初始化
    property_init();
    ······
   //创建epoll句柄
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }
    //用于设置子进程信号处理函数,如果子进程(Zygote)异常退出,init会根据调用该函数中设定的信号处理函数来处理
    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);

    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        //解析init.rc文件
        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);
    }

    if (false) parser.DumpState();

    ActionManager& am = ActionManager::GetInstance();
    ······

    while (true) {
        int epoll_timeout_ms = -1;
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            //内部遍历执行每个action中携带的command对应的执行函数
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            //重启死去的进程
            restart_processes();
            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 (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;
}

init进程做的其中一件重要的事情就是解析init.rc文件,init.rc文件是由Android初始化语言(AIL)编写的脚本,主要用来启动各种服务,我们关注的Zygote进程就是由init.rc拆分后的init.zyygoteXX.rc定义的,以64位系统为例,就是init.zyygote64.rc文件。主要代码如下:

/*位于system/core/rootdir/init.zygote64.rc*/
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

这段service的主要作用就是通知init进程创建名为zygote的进程,程序路径位于/system/bin/app_process64,后面是要传递的参数。class main指的是Zygote的classname为main。
而在init.rc有如下配置代码:

on nonencrypted
    class_start main
    class_start late_start

其中class_start是一个COMMAND,对应的函数为do_class_start,而main就是Zygote的classname,因此class_start min是用来启动Zygote的,do_class_start函数在builtins.cpp定义,关键代码如下:

static int do_class_start(const std::vector<std::string>& args) {
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}

而ForEachServiceInClass函数会遍历Service链表,找到classname为main的Zygote,并执行StartIfNotDisabled函数,该函数代码如下:

bool Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}

可以看到,如果没有被对应的rc文件设置disable选项,则会调用Start()函数来启动该Service,因此我们来查看Start函数,主要代码如下:

bool Service::Start() {
    // Starting a service removes it from the disabled or reset state and
    // immediately takes it out of the restarting state if it was in there.
    flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));

    // 如果Service已经启动,则不启动
    if (flags_ & SVC_RUNNING) {
        return false;
    }

    bool needs_console = (flags_ & SVC_CONSOLE);
    if (needs_console) {
        if (console_.empty()) {
            console_ = default_console;
        }

        int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
        if (console_fd < 0) {
            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
            flags_ |= SVC_DISABLED;
            return false;
        }
        close(console_fd);
    }
     //判断需要启动的Service对应的执行文件是否存在
    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
        flags_ |= SVC_DISABLED;
        return false;
    }
······
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
    //当前代码在子进程进行
    if (pid == 0) {
        umask(077);
······
        //调用execve函数Service子进程就会被启动
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }
        _exit(127);
    }
······
    return true;
}

调用execve函数,Service子进程会被启动,并进入执行该Service的main函数,如果该Service是Zygote,则执行/system/bin/app_process64,对应app_main.cpp文件。其中的main函数代码如下:

int main(int argc, char* const argv[])
{
······
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        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.");
    }
}

可知这个函数调用了runtime的start函数启动Zygote,至此Zygote就启动了。
让我们总结下init进程的工作:

三、安卓系统启动

3.1 概述

在安卓系统中,DVM、和ART、应用程序进程以及运行系统的关键服务的SystemServer都是由Zygote进程来创建的,因此我们也称呼Zygote进程为受精卵进程或孵化器进程。下面我们就一起来学习Zygote进程启动过程。

3.2 启动Java框架,即进入FrameWork层

上一小节讲到,init启动Zygote是靠app_main.cpp的main函数中的runtime的start方法。我们就从这里继续分析学习。

int main(int argc, char* const argv[])
{
······
    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;
        } 
        ······
    }
······
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
······
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        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.");
    }
}

上面第一段代码主要是标识当前是什么进程,由于Zygote进程都是通过fork自身来创建子进程,所以有必要检查当前运行在哪个进程当中。
如果运行在Zygote进程,就会执行第三段代码,调用runtime的start函数。该函数的主要关键如下:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
······
    /* 启动java虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    //为java虚拟机注册JNI方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
······
    //从app_main的main函数知道className为com.android.internal.os.ZygoteInit
    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);
    }

    //将className的“.”替换为“/”
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        //找到Zygote的main方法
        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 {
            //通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

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

根据注释可以看到,这个函数的主要作用,就是启动Java虚拟机,并为其注册JNI方法,然后根据className找到ZygoteInit,顺利通过JNI调用其main函数。至于为什么要使用JNI,是因为ZygoteInit是由java语言编写的,当前的运行逻辑在Native中,需要进入FrameWork层,也就是java框架层。

3.3 FrameWork层发生的事情

Zygote成功进入Java框架层,换句话说就是Zygote开创了Java框架层。该main方法关键代码如下:

public static void main(String argv[]) {
        try {
            //创建一个Server端的socket,socketName为“zygote”
            zygoteServer.registerServerSocket(socketName);
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                //预加载类和资源
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }
······
            if (startSystemServer) {
                //启动SystemServer进程
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
            //等待AMS请求
            zygoteServer.runSelectLoop(abiList);
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

第一段代码创建了一个Server端的socket,socketName为“zygote”,这个socket用于等待AMS请求Zygote来创建新的应用程序进程,然后预加载类和资源,之后启动SystemServer进程,这样系统的服务也会由SystemServe进程启动起来,最后调用zygoteServer的runSelectLoop方法来等待AMS,可以总结ZygoteInit的main方法主要做了四件事:

具体的这四个函数的详细细节,本处不在探讨,待下次再进行学习。这里只说一下SystemServer进程的工作:

四、总结

这一次,我们学习了从kernel到framework层的工作,大致是梳理了安卓手机从按下电源键到启动安卓系统的过程,不过大家肯定还有疑问,这里并没有显示桌面,并没有启动软件,这些问题,我准备在下一篇文章再和大家一起学习。

上一篇下一篇

猜你喜欢

热点阅读