Android 启动流程分析(init、zygote进程)

594 阅读4分钟

本篇分析针对系统android-11.0.0_r28版本 先来张图:

android系统启动流程图.drawio.png

init流程

android内核启动首先会调用init的main.c类

android-kernel/common/init/main.c
//内核空间init方法 1409行
static int __ref kernel_init(void *unused) {
//等待kthread全部设置完毕
wait_for_completion(&kthreadd_done);
//需要在释放内存之前完成所有async _init代码
async_synchronize_full();
//内核映射现在已经完成—更新用户空间页表 完成PTI
pti_finalize();
//**初始化方法,这是我们主要关心的方法,会调用系统init
!try_to_run_init_process("/bin/init") ||
}

然后调用到system/core/init/main.cpp

//反复执行多次
int main(int argc, char** argv) {
        if (!strcmp(argv[1], "selinux_setup")) {
            //2.挂载linux安全子系统,安全策略
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            //3.初始化属性
            return SecondStageMain(argc, argv);
        }
    }
    //1.第一阶段方法
    return FirstStageMain(argc, argv);
}

//第一阶段
int FirstStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        //安全处理 重启信号
        InstallRebootSignalHandlers();
    }
    //在initramdisk中完成我们需要的基本文件系统设置
    //其余在rc文件中完成
    //主要是挂载文件,对文件系统初始化
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    //mkdir创建文件夹
    CHECKCALL(mkdir("/dev/pts", 0755));
    //日志初始化
    InitKernelLogging(argv);
    //最后定义目录和selinux_setup,走到第二阶段,安全子系统
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    xecv(path, const_cast<char**>(args));
    
    
//第二阶段
int SetupSelinux(char** argv) {
    //设置SELinux,加载SELinux策略
    SelinuxSetupKernelLogging();
    SelinuxInitialize();
    //第二阶段主要是做安全策略相关,然后调用了第三阶段的方法
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
    
}

//第三阶段(可以叫第二主阶段)
int SecondStageMain(int argc, char** argv) {
    //输入输出打印 logging
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    //******初始化属性域
    PropertyInit();
    //查看是否需要加载调试道具以允许adb root,当设备被解锁。
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    //挂载第二阶段初始化期间所需的额外文件系统
    MountExtraFilesystems();
    //处理子进程终止信号
    InstallSignalFdHandler(&epoll);
    InstallInitNotifier(&epoll);
    StartPropertyService(&property_fd);
   //****负载启动脚本  解析init.rc文件
    LoadBootScripts(am, sm);
     //死循环等待
    while (true) {
    //等待触发
    auto pending_functions = epoll.Wait(epoll_timeout);
    }
}

//看下LoadBootScripts方法中做了什么  parse很多init文件
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
            ........
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}
//ParseConfig 最终都走入了ParseConfigFile方法
bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {
        return ParseConfigDir(path);//最终走入ParseConfigFile
    }
    return ParseConfigFile(path);
}

//根据传入文件的各种state解析init文件
void Parser::ParseData(const std::string& filename, std::string* data) {
    for (;;) {
        switch (next_token(&state)) {
            case T_EOF:
                    section_parser->EndFile();
                return;
            case T_NEWLINE: 
 }
//

在第二个主阶段最后,执行了很多init文件和init.rc文件,什么作用。

进入system/core/rootdir/init.rc看一下

  # Now we can start zygote for devices with file based encryption
  //现在我们可以开始zygote设备基于文件加密触发zygote-start
  trigger zygote-start

可以看到zygote的启动实在init的第二个主阶段,执行了init.rc完成的。

init.rc 1.执行zygote 2.执行重启。

在看下init(pid=0)中我们做了什么事情

  1. 挂载文件
  2. 设置seliunx --安全子模块、安全策略
  3. 开启属性服务,注册到epoll中
  4. 解析init.rc文件
  5. 循环处理脚本 ----这一步,对zygote进行启动
  6. 最后while(true)等待

Zygote流程

image.png

可以看到zygote有好多文件,32位的加载zygote32,64位系统加载zygote64,32-64就是先尝试加载32,然后加载64,反之亦然。

目录system/core/rootdir/init.zygote64_32.rc 以init.zygote64为例

//可以看到加载了手机中 /system/bin/app_process64这个目录的文件,并传入参数
service zygote /system/bin/app_process64 
-Xzygote /system/bin --zygote --start-system-server

搜索一下,app_process可以看到 adnroid.bp文件 frameworks/base/cmds/app_process/Android.bp

执行的是:srcs: ["app_main.cpp"]

native层

//进入app_main.cpp,直接找main函数 
//直接执行了  AppRuntime : public AndroidRuntime
//开启了android运行时环境
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//264行的两个判断,可以看到rc文件中的两个参数
//--zygote --start-system-server
//到这里zygote、startSystemServer都被置为true
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
            
//0.执行到
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
//frameworks/base/core/jni/AndroidRuntime.cpp
//1.先启动虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
//2.注册jni函数
if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }    
    //点击startReg方法,可以看到执行了
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0)
    //可以看到for循环取数组中的函数
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0)
        //gRegJNI 看看REG_JNI数组中的几个函数,是我们非常熟悉的。
         REG_JNI(register_android_os_Binder),
         REG_JNI(register_android_os_Parcel),
//3.最后调用ZygoteInit,在0.的时候我们把类名传进来的
 //startClass == com.android.internal.os.ZygoteInit
 env->CallStaticVoidMethod(startClass, startMeth, strArray);
 //会调用到ZygoteInit中的方法

java层

  main(){
  // ZygotePreload 预加载,加快进程的启动
  preload(bootTimingsTraceLog);
  //Server socket class for zygote processes.
  zygoteServer = new ZygoteServer(isPrimaryZygote); // socket
  Runnable r = forkSystemServer // 启动 SystemServer 进程
  //在runSelectLoop开启死循环,接收AMS传过来的消息
  caller = zygoteServer.runSelectLoop(abiList);
  }

Zygote总结:

native:

  1. 初始化运行环境,创建jvm android虚拟机
  2. 注册jni函数
  3. 调用 zygote.init类 main方法

java:

  1. 预加载,加快进程启动
  2. 启动zygote socket
  3. 创建systemserver
  4. 循环等待