国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

筆記:Android 9系統(tǒng)啟動(dòng)流程

這篇具有很好參考價(jià)值的文章主要介紹了筆記:Android 9系統(tǒng)啟動(dòng)流程。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

啟動(dòng)流程

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

1.按下電源,系統(tǒng)啟動(dòng)

當(dāng)電源鍵按下時(shí),引導(dǎo)芯片代碼(匯編指令)會(huì)從預(yù)定的地方(固化在ROM)開始執(zhí)行,將引導(dǎo)程序 BootLoader 加載到 RAM中,然后執(zhí)行

2.引導(dǎo)程序 BootLoader

BootLoader 是在 Android 操作系統(tǒng)開始前的一個(gè)小程序,主要作用是把系統(tǒng)OS拉起來并運(yùn)行
位置:\bootable\bootloader

3.Linux內(nèi)核啟動(dòng)

當(dāng) Linux系統(tǒng)被 BootLoader 程序拉起,內(nèi)核啟動(dòng)時(shí),會(huì)設(shè)置緩存,被保護(hù)存儲(chǔ)器,計(jì)劃列表,加載驅(qū)動(dòng)等工作,在內(nèi)核完成系統(tǒng)設(shè)置后,會(huì)啟動(dòng)進(jìn)程,主要涉及3個(gè)特殊的進(jìn)程,idle進(jìn)程(PID = 0), init進(jìn)程(PID = 1)和kthreadd進(jìn)程(PID = 2),這三個(gè)進(jìn)程是內(nèi)核的基礎(chǔ)

  • idle進(jìn)程:是 init 進(jìn)程和 kthreadd 進(jìn)程的父進(jìn)程,是Linux系統(tǒng)第一個(gè)進(jìn)程。
  • init進(jìn)程:是Android系統(tǒng)應(yīng)用程序的始祖,app都是直接或間接以它為父進(jìn)程,是Linux系統(tǒng)第一個(gè)用戶進(jìn)程
  • kthreadd進(jìn)程:是Linux系統(tǒng)內(nèi)核管家,所有的內(nèi)核線程都是直接或間接以它為父進(jìn)程

idle進(jìn)程的啟動(dòng)是用匯編語言寫的,對(duì)應(yīng)文件是/kernel/fusion/4.9/arch/arm64/kernel/head.S注意:不同版本的android文件夾名稱不同
具體的也看不懂,根據(jù)大佬說的會(huì)跳轉(zhuǎn)到 /kernel/fusion/4.9/include/linux/start_kernel.h
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
這個(gè)頭文件對(duì)應(yīng)的實(shí)現(xiàn)在 /kernel/fusion/4.9/init/main.c

asmlinkage __visible void __init start_kernel(void)
{
	......
	ftrace_init();

	/* Do the rest non-__init'ed, we're now alive */
	rest_init();
}

rest_init 函數(shù)中開啟了 init 進(jìn)程和 kthreadd 進(jìn)程

static noinline void __ref rest_init(void)
{
	int pid;
#if (MP_CACHE_DROP==1)
	int pid_kthre_drop_cache;
	struct sched_param para;
	struct task_struct *p;
	int srch_retval;
#endif

#ifdef CONFIG_MP_PLATFORM_PHY_ADDRESS_MORE_THAN_2G_SET_MOVABLE_DEBUG
	testAddrTranslation();
#endif        
	//啟動(dòng)RCU機(jī)制,這個(gè)與后面的rcu_read_lock和rcu_read_unlock是配套的,用于多核同步
	rcu_scheduler_starting();
	/*
	 * We need to spawn init first so that it obtains pid 1, however
	 * the init task will end up wanting to create kthreads, which, if
	 * we schedule it before we create kthreadd, will OOPS.
	 */
	 //用kernel_thread方式創(chuàng)建init進(jìn)程,將 kernel_init函數(shù)指針傳遞過去創(chuàng)建 init 進(jìn)程
	kernel_thread(kernel_init, NULL, CLONE_FS);
	// 設(shè)定NUMA系統(tǒng)的默認(rèn)內(nèi)存訪問策略
	numa_default_policy();
	//同上,用kernel_thread方式創(chuàng)建kthreadd進(jìn)程
	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

#if (MP_CACHE_DROP==1)
	pid_kthre_drop_cache=kernel_thread(kthre_drop_cache, NULL, CLONE_FS | CLONE_FILES);
	rcu_read_lock();
	srch_retval = -ESRCH;
	p = pid_kthre_drop_cache ? find_task_by_vpid(pid_kthre_drop_cache) : current;
	if (p != NULL)
	{
		srch_retval = (p->policy == SCHED_FIFO || p->policy == SCHED_RR)?1:0;
		para.sched_priority=srch_retval;
		//use default and set min
		srch_retval = sched_setscheduler(p, p->policy, &para);
	}
	rcu_read_unlock();
#endif
	//打開RCU讀取鎖,在此期間無法進(jìn)行進(jìn)程切換
	rcu_read_lock();
	// 獲取kthreadd的進(jìn)程描述符,期間需要檢索進(jìn)程pid的使用鏈表,所以要加鎖
	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
	//關(guān)閉RCU讀取鎖
	rcu_read_unlock();
	// 之前kernel_init函數(shù)調(diào)用了wait_for_completion(&kthreadd_done),這里調(diào)用complete就是通知kernel_init進(jìn)程kthreadd進(jìn)程已創(chuàng)建完成,可以繼續(xù)執(zhí)行
	complete(&kthreadd_done);

	/*
	 * The boot idle thread must execute schedule()
	 * at least once to get things moving:
	 */
	 //current表示當(dāng)前進(jìn)程,當(dāng)前0號(hào)進(jìn)程init_task設(shè)置為idle進(jìn)程
	init_idle_bootup_task(current);
	//0號(hào)進(jìn)程主動(dòng)請求調(diào)度,讓出cpu,1號(hào)進(jìn)程kernel_init將會(huì)運(yùn)行,并且禁止搶占
	schedule_preempt_disabled();
	/* Call into cpu_idle with preempt disabled */
	// 這個(gè)函數(shù)會(huì)調(diào)用cpu_idle_loop()使得idle進(jìn)程進(jìn)入自己的事件處理循環(huán)
	cpu_startup_entry(CPUHP_ONLINE);
}

4.init 進(jìn)程啟動(dòng)

init 進(jìn)程是 Android 系統(tǒng)中用戶第一個(gè)進(jìn)程,進(jìn)程號(hào)為1,它被賦予了很多極其重要的工作職責(zé),比如創(chuàng)建 Zygote(孵化器)和屬性服務(wù)等,init是由多個(gè)源文件共同組成的,這些文件位置:system/core/init 中,可用ps命令查看到:
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
上面說到在rest_init 函數(shù)中通過 kernel_thread(kernel_init, NULL, CLONE_FS); 方法來啟動(dòng)init進(jìn)程
kernel_thread方法位置:/kernel/fusion/4.9/kernel/fork.c
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
kernel_thread 的第一個(gè)參數(shù)是一個(gè)函數(shù)指針,會(huì)在創(chuàng)建進(jìn)程后執(zhí)行,第三個(gè)參數(shù)是創(chuàng)建進(jìn)程的方式

參數(shù)名 表示
CLONE_PARENT 創(chuàng)建的子進(jìn)程的父進(jìn)程是調(diào)用者的父進(jìn)程,新進(jìn)程與創(chuàng)建它的進(jìn)程成了“兄弟”而不是“父子”
CLONE_FS 子進(jìn)程與父進(jìn)程共享相同的文件系統(tǒng),包括root、當(dāng)前目錄、umask
CLONE_FILES 子進(jìn)程與父進(jìn)程共享相同的文件描述符(file descriptor)表
CLONE_NEWNS 在新的namespace啟動(dòng)子進(jìn)程,namespace描述了進(jìn)程的文件hierarchy
CLONE_SIGHAND 子進(jìn)程與父進(jìn)程共享相同的信號(hào)處理(signal handler)表
CLONE_PTRACE 若父進(jìn)程被trace,子進(jìn)程也被trace
CLONE_UNTRACED 若父進(jìn)程被trace,子進(jìn)程不被trace
CLONE_VFORK 父進(jìn)程被掛起,直至子進(jìn)程釋放虛擬內(nèi)存資源
CLONE_VM 子進(jìn)程與父進(jìn)程運(yùn)行于相同的內(nèi)存空間
CLONE_PID 子進(jìn)程在創(chuàng)建時(shí)PID與父進(jìn)程一致
CLONE_THREAD Linux 2.4中增加以支持POSIX線程標(biāo)準(zhǔn),子進(jìn)程與父進(jìn)程共享相同的線程群

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
_do_fork 函數(shù)用于創(chuàng)建進(jìn)程,它首先調(diào)用 copy_process() 創(chuàng)建新進(jìn)程,然后調(diào)用 wake_up_new_task() 將進(jìn)程放入運(yùn)行隊(duì)列中并啟動(dòng)新進(jìn)程,在創(chuàng)建完成后會(huì)回調(diào) /kernel/fusion/4.9/init/main.c 文件中的kernel_init 方法

static int __ref kernel_init(void *unused)
{
......
	if (ramdisk_execute_command) {	// ramdisk_execute_command 的值為"/init"
		ret = run_init_process(ramdisk_execute_command);
		if (!ret)
			return 0;
		pr_err("Failed to execute %s (error %d)\n",
		       ramdisk_execute_command, ret);
	}
	/*
	 * 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) {
		ret = run_init_process(execute_command);
		if (!ret)
			return 0;
		panic("Requested init %s failed (error %d).",
		      execute_command, ret);
	}
	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/init.txt for guidance.");
}

這個(gè)方法會(huì)去找根目錄下的 init(ramdisk_execute_command) 可執(zhí)行文件,并運(yùn)行它,如果在根目錄找不到就會(huì)去找 /sbin/init、/etc/init、/bin/init、/bin/sh 目錄下的可執(zhí)行文件,只要這些應(yīng)用程序有一個(gè)啟動(dòng)了,其他就不啟動(dòng)了
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
而這個(gè) init 可執(zhí)行文件是 system/core/init/init.cpp 編譯后生成的

int main(int argc, char** argv) {
	//注釋一:進(jìn)行ueventd/watchdogd跳轉(zhuǎn)及環(huán)境變量設(shè)置
	//basename是C庫中的一個(gè)函數(shù),得到特定的路徑中的最后一個(gè)'/'后面的內(nèi)容,比如/sdcard/miui_recovery/backup,得到的結(jié)果是backup
    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) {//將各種信號(hào)量,如SIGABRT,SIGBUS等的行為設(shè)置為SA_RESTART,一旦監(jiān)聽到這些信號(hào)即執(zhí)行重啟系統(tǒng)
        InstallRebootSignalHandlers();
    }
	//之前準(zhǔn)備工作時(shí)將INIT_SECOND_STAGE設(shè)置為true,已經(jīng)不為nullptr,所以is_first_stage為false
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    if (is_first_stage) {	//如果是第一次執(zhí)行
        boot_clock::time_point start_time = boot_clock::now();

		// 清理 umask
        // Clear the umask.
        umask(0);
        clearenv();
        setenv("PATH", _PATH_DEFPATH, 1);
        // 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.
        // 注釋二:創(chuàng)建和掛載啟動(dòng)所需要的文件目錄
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        ......

        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
        // talk to the outside world...
        // 注釋三:初始化Kernel 的 Log,外界可獲取 Kernel 的打印日志
        InitKernelLogging(argv);
        LOG(INFO) << "init first stage started!";
        if (!DoFirstStageMount()) {	//掛載分區(qū)設(shè)備
            LOG(FATAL) << "Failed to mount required partitions early ...";
        }
		....
		// 注釋四:初始化selinux策略
		SelinuxSetupKernelLogging();
        SelinuxInitialize();

		// 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) { //restorecon命令用來恢復(fù)SELinux文件屬性即恢復(fù)文件的安全上下文
            PLOG(FATAL) << "restorecon failed of /init failed";
        }
        setenv("INIT_SECOND_STAGE", "true", 1);	//設(shè)置環(huán)境變量

        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 };
        execv(path, args);	//重新執(zhí)行main方法

        // execv() only returns if an error happened, in which case we
        // panic and never fall through this conditional.
        PLOG(FATAL) << "execv(\"" << path << "\") failed";
    }
/***************** 第二部分 ******************/
    // At this point we're in the second stage of init.
    InitKernelLogging(argv);	//初始化 kernel 日志
    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);		//初始化進(jìn)程會(huì)話密鑰 位置:/system/core/libkeyutils/Keyutils.cpp

    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); //創(chuàng)建 /dev/.booting 文件,就是個(gè)標(biāo)記,表示booting進(jìn)行中
	// 注釋五:
    property_init();	//初始化屬性系統(tǒng),并從指定文件讀取屬性

    // 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();		//處理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");	//清空這些環(huán)境變量,因?yàn)橹岸家呀?jīng)存入到系統(tǒng)屬性中去了
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");

    // Now set up SELinux for second stage.
    SelinuxSetupKernelLogging();	
    SelabelInitialize();		// SElinux第二階段
    SelinuxRestoreContext();	// 恢復(fù)安全上下文

    epoll_fd = epoll_create1(EPOLL_CLOEXEC);	//注釋六:創(chuàng)建 epoll 句柄
    if (epoll_fd == -1) {
        PLOG(FATAL) << "epoll_create1 failed";
    }

    sigchld_handler_init();		//類似java中的Handelr,如果子進(jìn)程(比如 Zygote 進(jìn)程)異常退出,init進(jìn)程會(huì)調(diào)用到該函數(shù)中設(shè)定的信號(hào)處理函數(shù)來進(jìn)行處理

    if (!IsRebootCapable()) {
        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
        // In that case, receiving SIGTERM will cause the system to shut down.
        InstallSigtermHandler();
    }

    property_load_boot_defaults();	//從文件中加載一些屬性,讀取usb配置
    export_oem_lock_status();		//設(shè)置ro.boot.flash.locked 屬性
    start_property_service();		//注釋七:啟動(dòng)屬性服務(wù)
    set_usb_controller();			//設(shè)置sys.usb.controller 屬性

    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map); //靜態(tài)方法,將function_map放到Action中作為成員變量

    subcontexts = InitializeSubcontexts();

    ActionManager& am = ActionManager::GetInstance();	//得到ActionManager對(duì)象
    ServiceList& sm = ServiceList::GetInstance();

	//注釋八:解析init.rc 文件
    LoadBootScripts(am, sm);	//解析 init.rc 配置文件
    // 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"); //注釋九:額外配置一些事件和Action

    // 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(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    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(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");

    // 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) {//注釋十:監(jiān)聽新的事件
        // 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 || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            if (!shutting_down) {
                auto next_process_restart_time = RestartProcesses();

                // If there's a process that needs restarting, wake up in time for that.
                if (next_process_restart_time) {
                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
                                           *next_process_restart_time - boot_clock::now())
                                           .count();
                    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;
}

init 的 main 函數(shù)做了很多的事情,

注釋一:ueventd_main 創(chuàng)建設(shè)備節(jié)點(diǎn)文件,watchdogd_main

ueventd_main
Android 根文件系統(tǒng)的映像上不存在 /dev 目錄,該目錄是init進(jìn)程啟動(dòng)后動(dòng)態(tài)創(chuàng)建的,而init進(jìn)程將創(chuàng)建設(shè)備節(jié)點(diǎn)文件的任務(wù)交給了 ueventd 子進(jìn)程
位置:\system\core\init\ueventd.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
ueventd 通過兩種方式創(chuàng)建設(shè)備節(jié)點(diǎn)文件
1.冷插拔(Cold Plug)即以預(yù)先定義的設(shè)備信息統(tǒng)一創(chuàng)建設(shè)備節(jié)點(diǎn)文件,這一類設(shè)備節(jié)點(diǎn)文件也被稱為靜態(tài)節(jié)點(diǎn)文件
2.熱插拔(Hot Plug)即在系統(tǒng)運(yùn)行中,當(dāng)有設(shè)備插入U(xiǎn)SB端口時(shí),ueventd就會(huì)監(jiān)聽到這一時(shí)間,為插入的設(shè)備動(dòng)態(tài)創(chuàng)建設(shè)備節(jié)點(diǎn)文件,這一類設(shè)備節(jié)點(diǎn)文件也被稱為動(dòng)態(tài)節(jié)點(diǎn)文件
watchdogd_main
看門狗本身是一個(gè)定時(shí)電路,內(nèi)部會(huì)不斷進(jìn)行計(jì)時(shí)操作,有兩個(gè)引腳與系統(tǒng)相連,正常運(yùn)行時(shí)每隔一段時(shí)間計(jì)算機(jī)系統(tǒng)會(huì)通過一個(gè)引腳向看門狗發(fā)送信號(hào),看門狗接收到信號(hào)后會(huì)將計(jì)時(shí)器清零并重新開始計(jì)時(shí),若系統(tǒng)卡死,看門狗計(jì)時(shí)結(jié)束,就會(huì)通過另一個(gè)引腳向系統(tǒng)發(fā)動(dòng)復(fù)位信號(hào),讓系統(tǒng)重啟
位置:\system\core\init\watchdogd.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋二:第一部分 掛載文件系統(tǒng)并創(chuàng)建目錄

因?yàn)槭堑谝淮螆?zhí)行main函數(shù) is_first_stage 獲得為null
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

mount是用來掛載文件系統(tǒng)的,非常熟悉了,用于掛載前面創(chuàng)建的節(jié)點(diǎn)文件,mknod用于創(chuàng)建Linux中的設(shè)備文件

init 初始化過程中,Android分別掛載了 tmpfs,devpts,proc,sysfs,selinuxfs 這5類文件系統(tǒng)
????????tmpfs:虛擬內(nèi)存文件系統(tǒng),會(huì)將所有的文件存儲(chǔ)在虛擬內(nèi)存中,既可以使用RAM,也可以使用交換分區(qū),會(huì)根據(jù)實(shí)際需要改變大小,因?yàn)槭邱v留在RAM中,所以讀取的速度非常快

????????devpts:devpts文件系統(tǒng)為偽終端提供了一個(gè)標(biāo)準(zhǔn)的接口,標(biāo)準(zhǔn)節(jié)點(diǎn)是/dev/pts。只要pty的主復(fù)合設(shè)備/dev/ptmx被打開,就會(huì)在/dev/pts下動(dòng)態(tài)的創(chuàng)建一個(gè)新的pty設(shè)備文件

????????proc:虛擬文件系統(tǒng),它可以看作是內(nèi)核內(nèi)部數(shù)據(jù)結(jié)構(gòu)的接口,通過它我們可以獲得系統(tǒng)的信息,同時(shí)也能夠在運(yùn)行時(shí)修改特定的內(nèi)核參數(shù)

????????sysfs:不占有任何磁盤空間的虛擬文件系統(tǒng)。它通常被掛接在/sys目錄下。sysfs文件系統(tǒng)是Linux2.6內(nèi)核引入的,它把連接在系統(tǒng)上的設(shè)備和總線組織成為一個(gè)分級(jí)的文件,使得它們可以在用戶空間存取

????????selinuxfs:通常掛載在/sys/fs/selinux目錄下,用來存放SELinux安全策略文件

注釋三:初始化日志輸出,掛載分區(qū)設(shè)備

InitKernelLogging
位置:/system/core/init/log.cpp
Linux 萬物皆文件,/sys/fs/selinux/null 相當(dāng)于一個(gè) null 對(duì)象
首先是將標(biāo)準(zhǔn)輸入輸出( 0、1、2)定向到 /sys/fs/selinux/null(null設(shè)備上)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
文件描述符 (file descriptor) 是內(nèi)核為了高效管理已被打開的文件所創(chuàng)建的索引,其是一個(gè)非負(fù)整數(shù)(通常是小整數(shù)),用于指代被打開的文件,所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都通過文件描述符。
Linux 進(jìn)程默認(rèn)情況下會(huì)有3個(gè)缺省打開的文件描述符,分別是標(biāo)準(zhǔn)輸入 0, 標(biāo)準(zhǔn)輸出 1, 標(biāo)準(zhǔn)錯(cuò)誤 2

InitLogging
位置:/system/core/base/logging.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
DoFirstStageMount
位置:system/core/init/init_first_stage.cpp
主要作用是初始化特定設(shè)備并掛載
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋四:啟用SELinux安全策略

位置:\system\core\init\selinux.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋五:第二部分 屬性服務(wù) property_init() 函數(shù) 和 start_property_service() 函數(shù)

啟用SELinux安全策略后,會(huì)重新執(zhí)行main函數(shù),由于設(shè)置了INIT_SECOND_SRAGE 屬性,所以第一部分執(zhí)行的代碼不會(huì)再執(zhí)行
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
位置:/system/core/init/property_service.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
直接交給 __system_property_area_init 處理,位置 /bionic/libc/bionic/system_property_api.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
最終調(diào)用了system_properties中的AreaInit 方法 位置:/bionic/libc/system_properties/system_properties.cpp
主要完成的工作,清除緩存,主要清除幾個(gè)鏈表以及在內(nèi)存中的映射,新建property_fliename 目錄(/dev/_properties)然后調(diào)用Initialize加載心痛屬性的類別信息,最后將加載的鏈表寫入文件并映射到內(nèi)存
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
process_kernel_dt() 位置:/system/core/init/init.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
process_kernel_cmdline位置:/system/core/init/init.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋六:新建epoll并初始化子進(jìn)程終止信號(hào)處理函數(shù)

epoll_create1 位置:

sigchld_handler_init() 位置:/system/core/init/signal_handler.cpp
這個(gè)函數(shù)的主要作用是注冊 SIGCHLD 信號(hào)的處理函數(shù),init是一個(gè)守護(hù)進(jìn)程,為了防止init的子進(jìn)程成為僵尸進(jìn)程,需要init在子進(jìn)程結(jié)束時(shí)獲取子進(jìn)程的結(jié)束碼,通過結(jié)束碼將程序表中的進(jìn)程移除,防止僵尸進(jìn)程占用程序表的空間(程序表空間達(dá)到上限時(shí),系統(tǒng)不能再啟動(dòng)新的進(jìn)程)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋七:start_property_service() 開啟屬性服務(wù)

start_property_service 位置:\system\core\init\property_service.cpp
之前都是通過property_set 可以輕松設(shè)置系統(tǒng)屬性,但不是所有的進(jìn)程都有權(quán)限可以隨意修改系統(tǒng)屬性,Android 將屬性的設(shè)置統(tǒng)一交給init進(jìn)程管理,其他進(jìn)程不能直接修改屬性,只能通過init進(jìn)程來修改
start_property_service() 位置:/system/core/init/property_service.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋八:解析init.rc文件

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
位置:/system/core/init/parser.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
這里涉及到on service import 對(duì)應(yīng)的三個(gè)解析器:ActionParser、ServiceParser、ImportParser,它們是之前加入到section_parsers_這個(gè)map中
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
它們都是SectionParser的子類,SectionParser中有三個(gè)虛函數(shù)和一個(gè)純虛函數(shù),只要包含純虛函數(shù)的類就是抽象類,不能new,只能通過子類實(shí)現(xiàn)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

ActionParser

位置:\system\core\init\action_parser.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
ParseSection 函數(shù)的作用就是構(gòu)造了一個(gè)Action對(duì)象,將trigger條件記錄到Action這個(gè)對(duì)象中,如果是event trigger 就賦值給event_trigger_,如果是property trigger就放到property_trigger_這個(gè)map中
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,androidParseLineSection是直接調(diào)用Action對(duì)象的AddCommand函數(shù),AddCommand看名字就大概知道是添加命令,其調(diào)用FindFunction查找命令對(duì)應(yīng)的執(zhí)行函數(shù),最后將這些信息包裝成Command對(duì)象存放到commands_數(shù)組中
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
FindFunction是通過命令查找對(duì)應(yīng)的執(zhí)行函數(shù),比如.rc文件中定義chmod,那得在一個(gè)map中找到 chmod 具體去執(zhí)行哪個(gè)函數(shù),find相當(dāng)于Java中的get,但是返回的是entry,可以通過entry ->first和entry ->second獲取key-value。找到的value是一個(gè)結(jié)構(gòu)體,里面有三個(gè)值,第一個(gè)是參數(shù)最小數(shù)目,第二個(gè)是參數(shù)最大數(shù)目,第三個(gè)就是執(zhí)行函數(shù),之后作了參數(shù)的數(shù)目檢查,也就是說命令后的參數(shù)要在最小值和最大值之間。
這個(gè)BuiltinFunctionMap也比較簡單,例如 {"chown", {2, 3, {true, do_chown}}},表示
最小的參數(shù)為2,最大的參數(shù)為3,調(diào)用的方法為 do_chown(),ture表示 是否需要在vendor_init域的子進(jìn)程中運(yùn)行,SELinux相關(guān)

EndSection 直接是調(diào)用ActionManager::GetInstance().AddAction,將數(shù)據(jù)存放到 actions_ 數(shù)組中,EndFile是一個(gè)空實(shí)現(xiàn)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

ServiceParser

位置:\system\core\init\service.cpp
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
一樣是看ParseSection 、ParseLineSection方法
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
OptionParserMap也比較簡單,例如 {"oneshot", {0, 0, &Service::ParseOneshot}},表示
最小的參數(shù)為0,最大的參數(shù)為0,調(diào)用的方法為 Service 類中的 ParseOneshot() 方法

EndSection,直接調(diào)用ServiceManager的AddService函數(shù),將數(shù)據(jù)存放到 services_ 數(shù)組中,EndFile依然是一個(gè)空實(shí)現(xiàn)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

ImportParser

位置:\system\core\init\import_parser.cpp
主要導(dǎo)入一些其他的rc文件進(jìn)來,只實(shí)現(xiàn)了 ParseSection 和 EndFile ,因?yàn)樗恼Z法比較單一
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
至此,解析init.rc語法的過程走完了,主要就是三個(gè)核心解析器:ActionParser、ServiceParser、ImportParser。而這幾個(gè)解析器主要是實(shí)現(xiàn)ParseSection、ParseLineSection、EndSection、EndFile四個(gè)函數(shù)

注釋九:其他事件和一些Action

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋十:監(jiān)聽新的事件

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
到這里 init 進(jìn)程已經(jīng)啟動(dòng)完成

5.Zygote(孵化器)進(jìn)程啟動(dòng)

上面講到在init進(jìn)程中有解析.rc文件,在這個(gè)rc文件中配置了一個(gè)重要的服務(wù)service–zygote,這是app程序的鼻祖
zygote進(jìn)程主要負(fù)責(zé)創(chuàng)建Java虛擬機(jī),加載系統(tǒng)資源,啟動(dòng)SystemServer進(jìn)程,以及在后續(xù)運(yùn)行過程中啟動(dòng)普通的應(yīng)用程序。
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
不同機(jī)器 zygote.rc 的文件個(gè)數(shù)可能有不同,這里有四種

  • init.zygote32.rc :進(jìn)程對(duì)應(yīng)的執(zhí)行程序是 app_process (純 32bit 模式)
  • init.zygote32_64.rc :啟動(dòng)兩個(gè) zygote 進(jìn)程 (名為 zygote 和 zygote_secondary),對(duì)應(yīng)的執(zhí)行程序分別是 app_process32 (主模式)、app_process64
  • init.zygote64.rc:進(jìn)程對(duì)應(yīng)的執(zhí)行程序是 app_process64 (純 64bit 模式)
  • init.zygote64_32.rc:啟動(dòng)兩個(gè) zygote 進(jìn)程 (名為 zygote 和 zygote_secondary),對(duì)應(yīng)的執(zhí)行程序分別是 app_process64 (主模式)、app_process32

上節(jié)注釋九的位置,再 init 最后會(huì)加入 late-init 的 trigger,當(dāng)late-init 觸發(fā)時(shí),會(huì)觸發(fā)zygote-start的操作,staty zygote就會(huì)創(chuàng)建zygote進(jìn)程并運(yùn)行
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
上一節(jié)在解析init.rc文件時(shí)會(huì)創(chuàng)建解析器解析init.rc里面的命令,而start命令是由ActionParser 解析器解析
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
可知 start 命令對(duì)應(yīng)的執(zhí)行函數(shù)為 do_start,do_start函數(shù)首先通過 FindService 去service 數(shù)組中遍歷,根據(jù)信息匹配出對(duì)應(yīng)的service,然后調(diào)用這個(gè) service 的 Start 方法
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
zygote 服務(wù)對(duì)應(yīng)的二進(jìn)制文件是 /system/bin/app_processXXX,對(duì)應(yīng)的源文件在:/frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
	// 將參數(shù)argv放到argv_String 字符串中
	// 上圖可知,傳入的參數(shù)是 -Xzygote /system/bin --zygote --start-system-server
    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.string());
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //構(gòu)建 AppRuntime 對(duì)象,并將參數(shù)傳入
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    const char* spaced_commands[] = { "-cp", "-classpath" }; //這兩個(gè)參數(shù)是Java程序需要依賴的Jar包,相當(dāng)于import
    // 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) {	//將spaced_commands中的參數(shù)額外加入VM
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          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) {//參數(shù)是否是spaced_commands中的參數(shù)
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {	//如果參數(shù)第一個(gè)字符是”-“,直接跳出循環(huán),之前傳入的第一個(gè)參數(shù)是 -Xzygote,所以執(zhí)行到這里就跳出了,i=0
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        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;

    ++i;  // Skip unused "parent dir" argument.
    //跳過一個(gè)參數(shù),之前跳過了 -Xzygote,這里跳過 /system/bin
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {	// 表示zygote啟動(dòng)模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;	//這個(gè)值根據(jù)平臺(tái)可能是zygote或者zygote64
        } else if (strcmp(arg, "--start-system-server") == 0) {//需要啟動(dòng)SystemServer
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {//表示application啟動(dòng)模式,普通的應(yīng)用程序
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {//進(jìn)程別名
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {//application啟動(dòng)的class
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {	//className不為空,說明是application啟動(dòng)模式
        // 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);//將className和參數(shù)設(shè)置給runtime

        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.string(), restOfArgs.string());
        }
    } else {	//zygote啟動(dòng)模式
        // We're in zygote mode.
        maybeCreateDalvikCache();//創(chuàng)建Dalvik的緩存目錄

        if (startSystemServer) {//加入 start-system-server參數(shù)
            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);
        args.add(abiFlag); // 加入--abi-list=參數(shù)

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));//將剩下的參數(shù)加入args
        }
    }

    if (!niceName.isEmpty()) {//設(shè)置進(jìn)程的別名
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) {	//zygote啟動(dòng)模式,加載 ZygoteInit 類
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {	//application 啟動(dòng)模式,加載 RuntimeInit 類
        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.");
    }
}

app_main.cpp 的 main 函數(shù)主要做的事就是參數(shù)解析,這個(gè)函數(shù)有兩種啟動(dòng)模式

  • 一種是zygote模式:初始化zygote進(jìn)程,傳遞的參數(shù):–start-system-server 和 --socket-name=zygote,前者表示啟動(dòng)SystemServer,后者指定socket的名稱
  • 一種是application模式:啟動(dòng)普通應(yīng)用程序,傳遞的參數(shù)有class名字以及class帶的參數(shù)

兩種模式最終都是調(diào)用AppRuntime對(duì)象的start函數(shù),加載 ZygoteInit 或 RuntimeInit 兩個(gè)Java類,并將之前整理的參數(shù)傳入進(jìn)去

上面main函數(shù)最后得知,如果 zygote 為 true,說明當(dāng)前在運(yùn)行Zygote進(jìn)程中,就會(huì)調(diào)用 AppRuntime 的 start 函數(shù)
位置:\frameworks\base\core\jni\AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    。。。。。。。
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL); //注釋一:初始化jni
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) { //注釋二:啟動(dòng)JAVA虛擬機(jī)
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
     //注釋三:為Java虛擬機(jī)注冊JNI方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
	
	 /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass; //注釋四:調(diào)用ZygoteInit.java 的 main 函數(shù)	
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
  	// 獲得傳遞的 className 參數(shù),如果為 zygote 則傳遞的參數(shù)為:com.android.internal.os.ZygoteInit
  	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);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    // slashClassName 函數(shù)將className中的 “.” 替換成 “/”
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    // 找到 com.android.internal.os.ZygoteInit.java 這個(gè)類
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
    	// 找到 ZygoteInit.java 類中的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反射調(diào)用 zygoteInit.java 的 main 方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

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

    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)//退出當(dāng)前線程
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)//創(chuàng)建一個(gè)線程,該線程會(huì)等待所有子線程結(jié)束后關(guān)閉虛擬機(jī)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

總體流程是:1.初始化jni,2.startVm函數(shù)創(chuàng)建java虛擬機(jī),3.startReg 函數(shù)為虛擬機(jī)注冊JNI方法,4. 根據(jù)傳遞進(jìn)來的參數(shù)找到對(duì)應(yīng)的java類,5. 通過JNI調(diào)用對(duì)應(yīng)類的main方法。通過JNI的方法zygote就從Native層進(jìn)入了Java框架層了,此前沒有任何代碼進(jìn)入Java框架層

注釋一:初始化JNI

位置:\libnativehelper\JniInvocation.cpp

bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
  char buffer[PROP_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  library = GetLibrary(library, buffer);
  // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
  // This is due to the fact that it is possible that some threads might have yet to finish
  // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
  // unloaded.
  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
  
  handle_ = dlopen(library, kDlopenFlags);
  if (handle_ == NULL) {
    if (strcmp(library, kLibraryFallback) == 0) {
      // Nothing else to try.
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
    // Note that this is enough to get something like the zygote
    // running, we can't property_set here to fix this for the future
    // because we are root and not the system user. See
    // RuntimeInit.commonInit for where we fix up the property to
    // avoid future fallbacks. http://b/11463182
    ALOGW("Falling back from %s to %s after dlopen error: %s",
          library, kLibraryFallback, dlerror());
    library = kLibraryFallback;
    //dlopen的功能是以指定的模式打開指定的動(dòng)態(tài)鏈接庫文件,并返回一個(gè)句柄
    //RTLD_NOW 表示需要在dlopen返回前,解析出所有未定義的符號(hào),如果解析不出返回NULL
    //RTLD_NODELETE 表示在dlclose()期間不卸載庫,并在之后使用dlopen重新加載庫的時(shí)不初始化庫中的靜態(tài)變量
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
  }
  // FindSymbol 函數(shù)內(nèi)部實(shí)際調(diào)用的是dlsym
  // dlsym作用是根據(jù)動(dòng)態(tài)鏈接庫 操作句柄(handle)與符號(hào)(symbol),返回對(duì)應(yīng)的地址
  // 這里實(shí)際就是從lobart.so庫中將 JNI_GetDefaultJavaVMInitArgs 等對(duì)應(yīng)的地址存放到 &JNI_GetDefaultJavaVMInitArgs_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}
注釋二:創(chuàng)建虛擬機(jī) startVm

調(diào)用的函數(shù)是\libnativehelper\JniInvocation.cpp下的 AndroidRuntime::startVm 函數(shù),這個(gè)函數(shù)比較長,但做的事情單一,就是從系統(tǒng)屬性中讀取參數(shù),然后通過 addOption 設(shè)置到 AndroidRuntime 的 mOptions 數(shù)組中存儲(chǔ)起來,然后調(diào)用從 libart.so 中找到的 JNI_CreateJavaVM 函數(shù),并將之前讀到的參數(shù)傳入

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;
    。。。。。。

    /* route exit() to our handler */
    addOption("exit", (void*) runtime_exit); //將各個(gè)參數(shù)放到mOption數(shù)組中

    。。。。。。

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray(); //將mOptions賦值給initArgs
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { //調(diào)用libart.so 的JNI_CreateJavaVM 函數(shù)去創(chuàng)建虛擬機(jī)
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

libart.so是ART虛擬機(jī)的核心庫,它包含了ART虛擬機(jī)所有的核心組件,如ClassLinker、DexFile、JNI、gc等

注釋三:為虛擬機(jī)注冊JNI方法 startReg
/*
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
     //設(shè)置Android創(chuàng)建線程的函數(shù)javaCreateThreadEtc,這個(gè)函數(shù)內(nèi)部是通過Linux的clone來創(chuàng)建線程的
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
     //創(chuàng)建一個(gè)200容量的局部引用作用域,這個(gè)局部引用其實(shí)就是局部變量
    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {//注冊JNI函數(shù)
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);//釋放局部引用作用域

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}
/*********************************************************/
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }
    return 0;
}

startReg 處理就是交給 RegJNIRec 的 mProc,RegJNIRec是個(gè)很簡單的結(jié)構(gòu)體,mProc是個(gè)函數(shù)指針

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    REG_JNI(register_android_util_MemoryIntArray),
    REG_JNI(register_android_util_PathParser),
    REG_JNI(register_android_util_StatsLog),
    REG_JNI(register_android_app_admin_SecurityLog),
    REG_JNI(register_android_content_AssetManager),
    REG_JNI(register_android_content_StringBlock),
    REG_JNI(register_android_content_XmlBlock),
    REG_JNI(register_android_content_res_ApkAssets),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_Hyphenator),
    REG_JNI(register_android_text_MeasuredParagraph),
    REG_JNI(register_android_text_StaticLayout),
    REG_JNI(register_android_view_InputDevice),
    REG_JNI(register_android_view_KeyCharacterMap),
    REG_JNI(register_android_os_Process),
    REG_JNI(register_android_os_SystemProperties),
    REG_JNI(register_android_os_Binder),
    REG_JNI(register_android_os_Parcel),
    REG_JNI(register_android_os_HidlSupport),
	。。。。。。
};
注釋四:反射調(diào)用ZygoteInit類的main函數(shù)

虛擬機(jī)創(chuàng)建完成后,就可以運(yùn)行java代碼了,主要是通過jni的函數(shù) CallStaticVoidMethod 反射調(diào)用 com.android.internal.os.ZygoteInit.java 的main函數(shù),至此 Zygote 進(jìn)程已經(jīng)啟動(dòng)

6.SystemServer進(jìn)程啟動(dòng)

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

上面已經(jīng)啟動(dòng)了Zygote進(jìn)程,并最終調(diào)用到了ZygoteInit.java 的main函數(shù),而SystemServer就是在這個(gè)main函數(shù)中啟動(dòng)的
位置:\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        final Runnable caller;
        try {
            // Report Zygote start time to tron unless it is a runtime restart
            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
                MetricsLogger.histogram(null, "boot_zygote_init",
                        (int) SystemClock.elapsedRealtime());
            }

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.enableDdms();
			
			// 注釋一:處理傳遞過來的參數(shù)
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) { //是否啟動(dòng)systemServer
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {  //ABI_LIST_ARG = "--abi-list=";
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {   //SOCKET_NAME_ARG = "--socket-name=";
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
			
			// 注釋二:創(chuàng)建一個(gè)Server端的Socket,socketName的值為“zygote”
            zygoteServer.registerServerSocketFromEnv(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                // 注釋三:預(yù)加載類和資源
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false, 0);

            Zygote.nativeSecurityInit();

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
            	// 注釋四:啟動(dòng)systemSercer進(jìn)程
                Runnable r = forkSystemServer(abiList, socketName, 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.
            //注釋五:等待 AMS 請求  進(jìn)入looper,等待AMS請求Zygote進(jìn)程來創(chuàng)建新的應(yīng)用程序進(jìn)程
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }
注釋一:處理傳遞過來的參數(shù)

\frameworks\base\cmds\app_process\app_main.cpp中有傳遞對(duì)應(yīng)的參數(shù)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋二:創(chuàng)建一個(gè)Server端的Socket

位置:\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
之后創(chuàng)建 SystemServer 進(jìn)程的時(shí)候,會(huì)將這個(gè)Socket傳遞進(jìn)去,SystemServer 就會(huì)在這個(gè)務(wù)器端 Socket 上等待 AMS 請求 Zygote 進(jìn)程來創(chuàng)建新的應(yīng)用程序進(jìn)程。

注釋三:預(yù)處理

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

注釋四:啟動(dòng)SystemSercer進(jìn)程
SystemSercer進(jìn)程創(chuàng)建
private static Runnable forkSystemServer(String abiList, String socketName,  ZygoteServer zygoteServer) {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_IPC_LOCK,
            OsConstants.CAP_KILL,
            OsConstants.CAP_NET_ADMIN,
            OsConstants.CAP_NET_BIND_SERVICE,
            OsConstants.CAP_NET_BROADCAST,
            OsConstants.CAP_NET_RAW,
            OsConstants.CAP_SYS_MODULE,
            OsConstants.CAP_SYS_NICE,
            OsConstants.CAP_SYS_PTRACE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG,
            OsConstants.CAP_WAKE_ALARM,
            OsConstants.CAP_BLOCK_SUSPEND
        );
        /* Containers run without some capabilities, so drop any caps that are not available. */
        StructCapUserHeader header = new StructCapUserHeader(
                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data;
        try {
            data = Os.capget(header);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
        // Mediatek Android Patch Begin
        /* Mediatek add 1014 to setgroups for dhcp*/
        /* Hardcoded command line to start the system server */
        String args[] = { // 創(chuàng)建args 數(shù)組,這個(gè)數(shù)組用來保存啟動(dòng) SystemServer 的啟動(dòng)參數(shù)
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1014,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
        };
        // Mediatek Android Patch End
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            boolean profileSystemServer = SystemProperties.getBoolean(
                    "dalvik.vm.profilesystemserver", false);
            if (profileSystemServer) {
                parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer( //創(chuàng)建一個(gè)子進(jìn)程,也就是 SystemServer 進(jìn)程
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {	//當(dāng)代碼邏輯運(yùn)行在子進(jìn)程中,既是 SystemServer 進(jìn)程
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket(); //子進(jìn)程關(guān)閉 Socket
            return handleSystemServerProcess(parsedArgs);//處理 SystemServer 進(jìn)程
        }

        return null;
    }

第一步:創(chuàng)建 SystemServer 的啟動(dòng)參數(shù)
從 args 數(shù)組,SystemServer 的啟動(dòng)參數(shù)可以看出 SystemServer 進(jìn)程用戶 id 和 用戶組 id 被設(shè)置成了1000,并擁有

setgroups=1001,1002,1003,1004,1005,1006,1007,1014,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010"

的權(quán)限,進(jìn)程的名稱為:–nice-name=system_server,啟動(dòng)的類名為com.android.server.SystemServer

第二步:forkSystemServer 創(chuàng)建出 SystemServer進(jìn)程

注意: 這里有個(gè)pid == 0 的判斷,android
的fork機(jī)制可以理解為分裂,分裂后有兩個(gè)代碼一模一樣的進(jìn)程,分裂后會(huì)同時(shí)執(zhí)行兩個(gè)進(jìn)程的代碼,如果是在父進(jìn)程中執(zhí)行
fork,則會(huì)返回分裂子進(jìn)程的的進(jìn)程號(hào)(pid),如果是在子進(jìn)程中 執(zhí)行 fork,返回值為0,所以 if (pid == 0)
里面的代碼只會(huì)在子進(jìn)程既 SystemServer 進(jìn)程中執(zhí)行

至此,就創(chuàng)建出了 SystemServer 進(jìn)程
由于SystemServer進(jìn)程 是 fork Zygote進(jìn)程的,所以也會(huì)得到 Zygote 進(jìn)程創(chuàng)建的 Socket ,但這個(gè) Socket 對(duì)于 SystemServer 沒有用處,所以關(guān)閉了這個(gè) Socket,之后調(diào)用 handleSystemServerProcess 來初始化 SystemServer 進(jìn)程
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
最終是得到了 SystemServer 的main方法反射

SystemSercer進(jìn)程啟動(dòng)流程

筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
位置:\frameworks\base\services\java\com\android\server\SystemServer.java

	/**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }

    public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));

        mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
        mRuntimeStartUptime = SystemClock.uptimeMillis();
    }

    private void run() {
        try {
            traceBeginAndSlog("InitBeforeStartServices");
            // If a device's clock is before 1970 (before 0), a lot of
            // APIs crash dealing with negative numbers, notably
            // java.io.File#setLastModified, so instead we fake it and
            // hope that time from cell towers or NTP fixes it shortly.
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { //獲得時(shí)間
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            //
            // Default the timezone property to GMT if not set.
            //
            String timezoneProperty =  SystemProperties.get("persist.sys.timezone"); //獲得時(shí)區(qū)
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                Slog.w(TAG, "Timezone not set; setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");
            }

            // If the system has "persist.sys.language" and friends set, replace them with
            // "persist.sys.locale". Note that the default locale at this point is calculated
            // using the "-Duser.locale" command line flag. That flag is usually populated by
            // AndroidRuntime using the same set of system properties, but only the system_server
            // and system apps are allowed to set them.
            //
            // NOTE: Most changes made here will need an equivalent change to
            // core/jni/AndroidRuntime.cpp
            if (!SystemProperties.get("persist.sys.language").isEmpty()) { 	//獲得語言
                final String languageTag = Locale.getDefault().toLanguageTag();

                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            // The system server should never make non-oneway calls
            Binder.setWarnOnBlocking(true);
            // The system server should always load safe labels
            PackageItemInfo.setForceSafeLabels(true);
            // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
            SQLiteCompatibilityWalFlags.init(null);

            // Here we go!
            Slog.i(TAG, "Entered the Android system server!");
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if (!mRuntimeRestart) {
                MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
            }

            // In case the runtime switched since last boot (such as when
            // the old runtime was removed in an OTA), set the system
            // property so that it is in sync. We can | xq oqi't do this in
            // libnativehelper's JniInvocation::Init code where we already
            // had to fallback to a different runtime because it is
            // running as root and we need to be the system user to set
            // the property. http://b/11463182
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            // Mmmmmm... more memory!
            VMRuntime.getRuntime().clearGrowthLimit();

            // The system server has to run all of the time, so it needs to be
            // as efficient as possible with its memory usage.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

            // Some devices rely on runtime fingerprint generation, so make sure
            // we've defined it before booting further.
            Build.ensureFingerprintProperty();

            // Within the system server, it is an error to access Environment paths without
            // explicitly specifying a user.
            Environment.setUserRequired(true);

            // Within the system server, any incoming Bundles should be defused
            // to avoid throwing BadParcelableException.
            BaseBundle.setShouldDefuse(true);

            // Within the system server, when parceling exceptions, include the stack trace
            Parcel.setStackTraceParceling(true);

            // Ensure binder calls into the system always run at foreground priority.
            BinderInternal.disableBackgroundScheduling(true);

            // Increase the number of binder threads in system_server
            BinderInternal.setMaxThreads(sMaxBinderThreads);

            // Prepare the main looper thread (this thread).
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            // Initialize native services.
            System.loadLibrary("android_servers"); //加載動(dòng)態(tài)庫 libandroid_servers.so

            // Check whether we failed to shut down last time we tried.
            // This call may not return.
            performPendingShutdown();

            // Initialize the system context.
            createSystemContext();

            // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext); //創(chuàng)建SystemServiceManaager對(duì)象,會(huì)對(duì)系統(tǒng)服務(wù)進(jìn)行創(chuàng)建,啟動(dòng)和生命周期管理
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices(); //啟動(dòng)引導(dǎo)服務(wù)
            startCoreServices();	  //啟動(dòng)核心服務(wù)
            startOtherServices();	  //啟動(dòng)其他服務(wù)
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }

        StrictMode.initVmDefaults(null);

        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
            final int MAX_UPTIME_MILLIS = 60 * 1000;
            if (uptimeMillis > MAX_UPTIME_MILLIS) {
                Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
                        "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
            }
        }

        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

startBootStrapServices():對(duì)應(yīng)系統(tǒng)引導(dǎo)服務(wù)。我們熟悉的ATM、AMS、PMS、PKMS服務(wù)就是在這啟動(dòng)的
startCoreServices():對(duì)應(yīng)核心服務(wù)。如電池服務(wù)就是在這啟動(dòng)
startOtherServices():對(duì)應(yīng)其他服務(wù)。在這個(gè)方法中,啟動(dòng)的服務(wù)大概有70+個(gè),WMS服務(wù)就是在這里啟動(dòng)的

引導(dǎo)服務(wù) 作用
Installer 系統(tǒng)安裝APK時(shí)的一個(gè)服務(wù),啟動(dòng)完成 Installer 服務(wù)之后才能啟動(dòng)其他的服務(wù)
ActivityManagerService 負(fù)責(zé)四大組件的啟動(dòng),切換,調(diào)度
PowerManagerService 系統(tǒng)中和 Power 相關(guān)的計(jì)算,然后決策系統(tǒng)應(yīng)該如何相應(yīng)
LightsService 管理背光顯示LED
DisplayManagerService 管理所有顯示設(shè)備
UserManagerService 多用戶模式管理
SensorService 為系統(tǒng)提供各種感應(yīng)器服務(wù)
PackageManagerService 用來對(duì)APK進(jìn)行安裝,解析,刪除,卸載等操作
核心服務(wù) 作用
DropBoxManagerService 用于生成和管理系運(yùn)行時(shí)的一些日志文件
BatteryService 管理電池相關(guān)服務(wù)
UsageStatsService 手機(jī)用戶使用每個(gè)app的頻率,時(shí)長
WebViewUpdateService WebView 更新服務(wù)
其他服務(wù) 作用
CameraService 攝像頭相關(guān)服務(wù)
AlarmManagerService 全局定時(shí)器管理服務(wù)
InputManagerService 管理輸入事件
WindowManagerService 窗口管理服務(wù)
VrManagerService VR模式夫管理服務(wù)
BluetoothService 藍(lán)牙管理服務(wù)
NotificationManagerService 通知管理服務(wù)
DeviceStorageMonitorService 存儲(chǔ)相關(guān)管理服務(wù)
LocationManagerService 定位相關(guān)管理服務(wù)
AudioService 音頻相關(guān)服務(wù)

startBootStrapServices() startCoreServices() startOtherServices()方法里都是調(diào)用類似的方法去開啟服務(wù)
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);以 PowerManagerService 為例,調(diào)用了SystemServiceManager 的 startService 方法開啟服務(wù)
位置: \frameworks\base\services\core\java\com\android\server\SystemServiceManager.java
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android

7.Launcher 啟動(dòng)

系統(tǒng)啟動(dòng)的最后一步是啟動(dòng)一個(gè)應(yīng)用程序用來顯示系統(tǒng)中已經(jīng)安裝的應(yīng)用程序,并作為這些安裝程序的啟動(dòng)入口,這個(gè)應(yīng)用程序就是Launcher

上面得知SystemServer 進(jìn)程啟動(dòng)中會(huì)啟動(dòng)很多其他的服務(wù),其中一個(gè)就是 ActivityManagerService,在 startOtherServices 中會(huì)調(diào)用 AMS 的 systemReady() 方法將 Lanuncher 啟動(dòng)起來
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
位置:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        traceLog.traceBegin("PhaseActivityManagerReady");
        。。。。。。

        synchronized (this) {
            。。。。。。
            startHomeActivityLocked(currentUserId, "systemReady");

            。。。。。。
        }
    }

在 AMS 中的 systemReady() 方法中執(zhí)行 startHomeActivityLocked()方法,傳入當(dāng)前用戶ID
筆記:Android 9系統(tǒng)啟動(dòng)流程,筆記,android
Launcher本身就是一個(gè)系統(tǒng)APP,用于顯示桌面等,LauncherApp啟動(dòng)之后會(huì)執(zhí)行其生命周期方法初始化桌面布局,至此,Launcher就啟動(dòng)完成了,用戶進(jìn)入到界面,整個(gè)Android系統(tǒng)也啟動(dòng)起來文章來源地址http://www.zghlxwxcb.cn/news/detail-623665.html

到了這里,關(guān)于筆記:Android 9系統(tǒng)啟動(dòng)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動(dòng)流程

    Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動(dòng)流程

    WindowManagerService是Android系統(tǒng)中重要的服務(wù),它是WindowManager的管理者,WindowManagerService無論對(duì)于應(yīng)用開發(fā)還是Framework開發(fā)都是重要的知識(shí)點(diǎn),究其原因是因?yàn)閃indowManagerService有很多職責(zé),每個(gè)職責(zé)都會(huì)涉及重要且復(fù)雜的系統(tǒng),這使得WindowManagerService就像一個(gè)十字路口的交通燈一樣

    2024年02月11日
    瀏覽(24)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段

    基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段

    Android13系統(tǒng)啟動(dòng)階段大致分為FirstStageMain階段和SecondStageMain,此章主要講FirstStageMain階段 (若分析有誤敬請指教) 本章講解的方向和你將收獲的知識(shí): 用戶空間進(jìn)程的調(diào)用流程 當(dāng)進(jìn)程掛掉后該如何處理 何時(shí)掛載上的基本文件系統(tǒng)和文件系統(tǒng)小知識(shí) FirstStageMain階段會(huì)掛載上什

    2024年02月10日
    瀏覽(38)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(四)之SecondStageMain階段

    基于Android13的系統(tǒng)啟動(dòng)流程分析(四)之SecondStageMain階段

    Android13系統(tǒng)啟動(dòng)階段大致分為FirstStageMain階段和SecondStageMain,此章主要講SecondStageMain階段 (若分析有誤敬請指教) 在基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段已經(jīng)講解過android系統(tǒng)啟動(dòng)的基本介紹了,這里不再單獨(dú)介紹了 我們先看是怎么進(jìn)入該階段的,仍然是

    2023年04月24日
    瀏覽(29)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(一)之SeLinux權(quán)限介紹

    基于Android13的系統(tǒng)啟動(dòng)流程分析(一)之SeLinux權(quán)限介紹

    學(xué)習(xí)Android系統(tǒng)啟動(dòng)流程之前先學(xué)習(xí)一下SeLinux權(quán)限系統(tǒng),步入正題 本章講解的方向和你將收獲的知識(shí): 什么是SeLinux系統(tǒng),SeLinux的簡介和介紹 SeLinux系統(tǒng)的主要作用和存在的意義,是基于哪個(gè)版本開始推行該方案的 如果遇到了SeLinux權(quán)限問題該如何解決,有幾種解決方案 SeLi

    2024年02月04日
    瀏覽(44)
  • Android 9 Audio系統(tǒng)筆記:AudioFlinger音頻流處理流程

    好久沒寫了,今天碰巧有個(gè)小伙伴問我關(guān)于音頻流這一塊的,久了還有點(diǎn)記不起來,我就順便寫一下,后面就不用又找一遍代碼了,所謂好記性不如爛筆頭。 所以,這里是關(guān)于如何從AudioTrack 寫入數(shù)據(jù)到audioflinger,以及audioflinger如何寫入到hal層的音頻流處理流程,主要寫一下

    2023年04月08日
    瀏覽(27)
  • Android Activity的啟動(dòng)流程(Android-10)

    Android Activity的啟動(dòng)流程(Android-10)

    在Android開發(fā)中,我們經(jīng)常會(huì)用到startActivity(Intent)方法,但是你知道startActivity(Intent)后Activity的啟動(dòng)流程嗎?今天就專門講一下最基礎(chǔ)的startActivity(Intent)看一下Activity的啟動(dòng)流程,同時(shí)由于Launcher的啟動(dòng)后續(xù)和這里基本類似,就記錄在一起。注意本章都是基于Android-10來講解的。

    2024年01月17日
    瀏覽(21)
  • android源碼學(xué)習(xí)- APP啟動(dòng)流程(android12源碼)

    android源碼學(xué)習(xí)- APP啟動(dòng)流程(android12源碼)

    百度一搜能找到很多講APP啟動(dòng)流程的,但是往往要么就是太老舊(還是基于android6去分析的),要么就是不全(往往只講了整個(gè)流程的一小部分)。所以我結(jié)合網(wǎng)上現(xiàn)有的文章,以及源碼的閱讀和調(diào)試,耗費(fèi)了3整天的時(shí)間,力求寫出一篇最完整,最詳細(xì),最通俗易懂的文章,

    2024年02月11日
    瀏覽(21)
  • Android啟動(dòng)流程優(yōu)化 中篇

    本文鏈接:https://blog.csdn.net/feather_wch/article/details/131587046 1、我們可以優(yōu)化部分 Application構(gòu)建到主界面onWindowFocusChanged 2、啟動(dòng)方式(官方) 冷啟動(dòng) 熱啟動(dòng) 溫啟動(dòng) 3、怎么樣算是卡頓? 卡頓:2-5-8原則 2秒以內(nèi):流程 2-5秒:可以接受 5-8秒:有些卡頓 8秒以上:非常卡頓,沒辦法接

    2024年02月12日
    瀏覽(37)
  • Android:啟動(dòng)流程

    Android:啟動(dòng)流程

    第一步:啟動(dòng)電源以及系統(tǒng)啟動(dòng) 當(dāng)電源按下,引導(dǎo)芯片代碼開始從預(yù)定義的地方(固化在ROM)開始執(zhí)行。加載引導(dǎo)程序到RAM,然后 執(zhí)行 第二步:引導(dǎo)程序 引導(dǎo)程序是在Android操作系統(tǒng)開始運(yùn)行前的一個(gè)小程序。引導(dǎo)程序是運(yùn)行的第一個(gè)程序,因此它是針 對(duì)特定的主板與芯片的

    2023年04月16日
    瀏覽(24)
  • Android Framework 之 啟動(dòng)流程

    Android 系統(tǒng)的啟動(dòng)流程 Android 系統(tǒng)的啟動(dòng)流程可以分為以下幾個(gè)主要步驟: 引導(dǎo)加載器(Bootloader)啟動(dòng) :當(dāng)你打開一個(gè) Android 設(shè)備時(shí),首先啟動(dòng)的是引導(dǎo)加載器。引導(dǎo)加載器負(fù)責(zé)啟動(dòng) Android 的核心操作系統(tǒng)。 Linux 內(nèi)核啟動(dòng) :引導(dǎo)加載器加載并啟動(dòng) Linux 內(nèi)核。Linux 內(nèi)核負(fù)責(zé)

    2024年02月14日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包