• linux内核初始化成功后是如何过渡到android初始化的


    Android用的linux内核,以完成OS该有的功能,例如,文件系统,网络,内存管理,进程调度,驱动等 ,向下管理硬件资源向上提供系统调用。另一些Android特有驱动也放在内核之中。
    linux内核启动完成后,便进行Android的初始化工作。

    内核端

    内核是在main.c中进行初始化,从kernel_init开始

    static int __init kernel_init(void * unused)
    {
    	lock_kernel();
    	/*
    	 * init can run on any cpu.
    	 */
    	set_cpus_allowed_ptr(current, CPU_MASK_ALL_PTR);
    	/*
    	 * Tell the world that we're going to be the grim
    	 * reaper of innocent orphaned children.
    	 *
    	 * We don't want people to have to make incorrect
    	 * assumptions about where in the task array this
    	 * can be found.
    	 */
    	init_pid_ns.child_reaper = current;
    
    	cad_pid = task_pid(current);
    
    	smp_prepare_cpus(setup_max_cpus);
    
    	do_pre_smp_initcalls();
    	start_boot_trace();
    
    	smp_init();
    	sched_init_smp();
    
    	cpuset_init_smp();
    
    	do_basic_setup();
    
    	/*
    	 * check if there is an early userspace init.  If yes, let it do all
    	 * the work
    	 */
    
    	if (!ramdisk_execute_command)
    		ramdisk_execute_command = "/init";
    
    	if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
    		ramdisk_execute_command = NULL;
    		prepare_namespace();
    	}
    
    	/*
    	 * Ok, we have completed the initial bootup, and
    	 * we're essentially up and running. Get rid of the
    	 * initmem segments and start the user-mode stuff..
    	 */
    
    	init_post();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在main.c 函数init_post()开始执行Android相关代码

    	if (ramdisk_execute_command) {
    		run_init_process(ramdisk_execute_command);
    		printk(KERN_WARNING "Failed to execute %s\n",
    				ramdisk_execute_command);
    	}
    
    	/*
    	 * We try each of these until one succeeds.
    	 *
    	 * The Bourne shell can be used instead of init if we are
    	 * trying to recover a really broken machine.
    	 */
    	if (execute_command) {
    		run_init_process(execute_command);
    		printk(KERN_WARNING "Failed to execute %s.  Attempting "
    					"defaults...\n", execute_command);
    	}
    	run_init_process("/sbin/init");
    	run_init_process("/etc/init");
    	run_init_process("/bin/init");
    	run_init_process("/bin/sh");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    run_init_process便是加载执行文件。可以看到有六处出现了这个函数,但是执行的是第一个,
    也就是run_init_process(ramdisk_execute_command), 变量ramdisk_execute_command在kernel_init执行时被赋值为’/init’, 也就是说,将会执行根文件目录下的init进程,而这个进程正是Android的初始化进程.

    Android端

    在根目录下可以看到init是个软链接,真正的init文件在/system/bin下面
    在这里插入图片描述
    进入目录,真身就在里面

    在这里插入图片描述
    加载执行后,就是大家耳熟能详的init进程了,开始进入Android的世界。

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    init可执行文件的命名

    在源码/system/core/init目录下查看mk和bp文件,在文件Android.mk中

    LOCAL_MODULE := init_first_stage
    LOCAL_MODULE_STEM := init
    
    • 1
    • 2

    在文件Android.bp中

    cc_binary {
        name: "init_second_stage",
        recovery_available: true,
        stem: "init",
        defaults: ["init_defaults"],
        static_libs: ["libinit"],
        required: [
            "e2fsdroid",
            "init.rc",
            "mke2fs",
            "sload_f2fs",
            "make_f2fs",
            "ueventd.rc",
        ],
        srcs: ["main.cpp"],
        symlinks: ["ueventd"],
        target: {
            recovery: {
                cflags: ["-DRECOVERY"],
                exclude_shared_libs: [
                    "libbinder",
                    "libutils",
                ],
            },
        },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在Android 11源码中,mk文件和bp文件还是共存的,但mk在编译时会被转换成bp文件。在初始化的过程中,与Android密切相关的又分为两个阶段,但无论在第一阶段,还是第二阶段,其stem都是init。

  • 相关阅读:
    数据结构与算法基础-(3)
    IDEA日志操作
    Vue、JS——定时器倒计时封装
    SpringBoot SpringBoot 开发实用篇 5 整合第三方技术 5.23 SpringBoot 整合 RabbitMQ(direct 模式)
    基础会计学作业
    Windows10 电脑上配置 Docker 环境
    10个编程好习惯:优秀程序员的经验分享
    【C语言】——通讯录(静态-动态增长-文件储存)
    前端版本控制工具,常见的Git 和SVN
    Palantir大数据技术在乌克兰战场的应用
  • 原文地址:https://blog.csdn.net/chopinyychopinyy/article/details/137916432