从源码来看android启动流程

前面讲了一个android重启问题,对android的启动流程比较感兴趣,特意梳理一下android的启动流程。

回顾

梳理启动流程之前,我们回忆一下android启动流程的大概。
在这里插入图片描述

一、bootloader

1、什么是bootloader?

BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。

2、这个阶段会做什么?

(1)硬件初始化:关闭看门狗,屏蔽中断,初始化内存,设置栈,设置时钟,从flash引导内核到内存等
(2)通过bootargs向内核传递配置信息。如波特率
通常我司的还会做一些定制的内容,如初始化功放、点屏、显示开机logo等等。

二、kernel

1、内核引导阶段

通常使用汇编语言编写,主要检查内核与当前硬件是否匹配。这部分也与硬件体系结构相关。代码主要位于 kernel /arch/arm/kernel/head.S

bl  switch_to_vhe
add sp, sp, #16
mov x29, #0
mov x30, #0
b   start_kernel

2、内核启动阶段

引导阶段结束前,将调用start_kernel()进入内核启动阶段。内核启动阶段相关的代码主要位于android/kernel-5.10/init/main.c
启动init进程,再通过init进程,来读取init.rc中的相关配置,从而来启动其他相关进程以及其他操作。

 asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
	....
	trap_init();//初始化内核中断和异常处理机制
	mm_init();//初始化内存
	.....
	thread_stack_cache_init();
	cred_init();
	fork_init();
	proc_caches_init();
	uts_ns_init();
	buffer_init();
	key_init();
	security_init();
	dbg_late_init();
	vfs_caches_init();
	pagecache_init();
	signals_init();
	seq_file_init();
	proc_root_init();
	nsfs_init();
	cpuset_init();
	cgroup_init();
	taskstats_init_early();
	delayacct_init();

	poking_init();
	check_bugs();

	acpi_subsystem_init();
	arch_post_acpi_subsys_init();
	sfi_init_late();
	kcsan_init();

	/* Do the rest non-__init'ed, we're now alive */
	arch_call_rest_init();//启动init

	prevent_tail_call_optimization();
}

三、init阶段:

static int __ref kernel_init(void *unused)
{
    ...
 
    if (!try_to_run_init_process("/sbin/init") ||
        !try_to_run_init_process("/etc/init") ||
        !try_to_run_init_process("/bin/init") ||
        !try_to_run_init_process("/bin/sh"))
        return 0;
 
    panic("No working init found.  Try passing init= option to kernel. "
          "See Linux Documentation/admin-guide/init.rst for guidance.");
}

如何知道执行的那个init文件呢?

kernel_init启动后,完成一些init的初始化操作,然后去系统根目录下依次找ramdisk_execute_command和execute_command设置的应用程序,如果这两个目录都找不到,就依次去根目录下找/sbin/init,/etc/init,/bin/init,/bin/sh这四个应用程序进行启动,只要这些应用程序有一个启动了,其他就不启动了。
在这里插入图片描述

int main(int argc, char** 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);
}

1、第一阶段:


int FirstStageMain(int argc, char** argv) {
    ............
 
    //创建文件系统目录并挂在相关文件系统
    // 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.
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
    ......
    //初始化日志输出系统
    InitKernelLogging(argv);
    .....
 
    //执行命令/system/bin/init,回到main函数,初始化selinux和加载selinux规则
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));
 
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
 
    return 1;
}
 
int SetupSelinux(char** argv) {
    ......
    //加载权限策略
    LoadSelinuxPolicy(policy);
    .....
    SelinuxSetEnforcement();
    ....
    //准备进入第二阶段
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
 
    // execv() only returns if an error happened, in which case we
    // panic and never return from this function.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
 
    return 1;
}

第二阶段

int SecondStageMain(int argc, char** argv) {
    ....
    //初始化属性系统
    PropertyInit();
 
    //进行selinux第二阶段并恢复一些文件安全上下文
    SelabelInitialize();
    SelinuxRestoreContext();
 
    //开启属性服务
    StartPropertyService(&property_fd);
     
    ........
    //匹配命令和函数之间的关系(ls、chmod.....)
    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);
     
    ......
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //加载解析脚本
    LoadBootScripts(am, sm);
    ....
    //按照early-init --> init -->late-init的顺序把相关action加入触发器队列,然后在循环中,执行所有触发器队列中Action带command的执行函数
    am.QueueEventTrigger("early-init");
    ....
 
    // Restore prio before main loop
    setpriority(PRIO_PROCESS, 0, 0);
    while (true) {
        ....
        //1、遍历并启动每个系统服务。
        //2、监测并处理子进程状态,如果是系统服务,重新拉起
        ....
    }
 
    return 0;
}

3、第三阶段:

第三阶段主要是解析rc文件,启动服务。Zygote就在此启动。我们需要先简单了解一下rc文件的语法;
在这里插入图片描述
总结一下:init阶段
在这里插入图片描述

四、Zygote阶段:

Init进程启动后,最重要的一个进程就是Zygote进程,Zygote是所有应用的鼻祖。SystemServer和其它所有虚拟机进程都是由Zygote fork而来 。Zygote进程由app_process启动,Zygote是一个C/S模型,Zygote进程作为服务端,其他进程作为客户端向它发出“孵化-fork”请求,而Zygote接收到这个请求后就“孵化-fork”出一个新的进程。


service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    onrestart restart vendor.tv-input-1-0
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

第一个zygote进程通过应用程序/system/bin/app_process来启动它

参数1:-Xzygote 该参数将作为虚拟机启动时所需的参数

参数2:/system/bin 代表虚拟机程序所在目录

参数3:–zygote 指明以ZygoteInit.java类中的main函数作为虚拟机执行入口

int main(int argc, char* const argv[])
{
    .....
    //根据参数启动zygote、start-system-server
    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.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
 
    .....
    if (startSystemServer) {
        args.add(String8("start-system-server"));
    }
    .....
    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.");
    }
}
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    .........
    //启动虚拟机
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);
 
    /*
     * Register android functions.
     */
     //注册jni
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ....
    //通过JNI方式调用ZygoteInit.main(),正在进入java世界
    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);
        }
    }
    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");
}
public static void main(String[] argv) {
 
    Runnable caller;
    try {
        .......
        //预加载资源,加快启动速度
        preload(bootTimingsTraceLog);
 
        ....
        //建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
        zygoteServer = new ZygoteServer(isPrimaryZygote);
 
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
 
            // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
            // child (system_server) process.
            if (r != null) {
                r.run();
                return;
            }
        }
 
        Log.i(TAG, "Accepting command socket connections");
 
        // The select loop returns early in the child process after a fork and
        // loops forever in the zygote.
 
        //zygote任务完成,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with fatal exception", ex);
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }
 
    // We're in the child process and have exited the select loop. Proceed to execute the
    // command.
    if (caller != null) {
        caller.run();
    }
}

zygote总结:

1)zygote进程的入口app_main.cpp;

2)调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;

3)通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;

4)registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;

5)preload()预加载通用类、drawable和color资源等,用于提高app启动效率;

6)通过startSystemServer来fork system_server进程,也是上层framework的运行载体。

7)zygote任务完成,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

8)启动SystemServer进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是李校长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值