日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android6.0源码分析—— Zygote进程分析(补充)

發(fā)布時(shí)間:2025/3/15 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android6.0源码分析—— Zygote进程分析(补充) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文地址: http://blog.csdn.net/a34140974/article/details/50915307


此博文為《Android5.0源碼分析—— Zygote進(jìn)程分析》的補(bǔ)充

我們已經(jīng)知道Android?5.0已經(jīng)默認(rèn)了ART,今天本想回去查看一下這個(gè)部分,于是回到init進(jìn)程中去尋找源碼,發(fā)現(xiàn)6.0的Zygote部分也小有變動(dòng),因此更新一下。

首先是init.c變成了init.cpp,這其實(shí)也就意味著在init中增加了類的概念。但是仔細(xì)查看init.h發(fā)現(xiàn)并沒(méi)有class關(guān)鍵字。只有很多的struct。如果對(duì)C++比較了解,就應(yīng)該知道C++的struct和C中的struct其實(shí)已經(jīng)是不一樣的概念了,在C++中struct除了公私與class對(duì)調(diào)外,其他的基本上沒(méi)有區(qū)別。在init.h中定義了以下結(jié)構(gòu)體:

struct service {

????void NotifyStateChange(const char* new_state);

?

??????? /* list of all services */

??? struct listnode slist;

?

??? char *name;

??? const char *classname;

?

??? unsigned flags;

??? pid_t pid;

??? time_t time_started;??? /* time of last start */

??? time_t time_crashed;??? /* first crash within inspection window */

??? int nr_crashed;???????? /* number of times crashed within window */

?

??? uid_t uid;

??? gid_t gid;

??? gid_t supp_gids[NR_SVC_SUPP_GIDS];

? ??size_t nr_supp_gids;

?

??? const char* seclabel;

?

??? struct socketinfo *sockets;

??? struct svcenvinfo *envvars;

?

??? struct action onrestart;? /* Actions to execute on restart. */

?

??? std::vector<std::string>* writepid_files_;

?

??? /* keycodes for triggering this service via /dev/keychord */

??? int *keycodes;

??? int nkeycodes;

??? int keychord_id;

?

??? IoSchedClass ioprio_class;

??? int ioprio_pri;

?

??? int nargs;

????/* "MUST BE AT THE END OF THE STRUCT" */

??? char *args[1];

};

可以看到,與之前5.0版本的最大區(qū)別就是結(jié)構(gòu)體內(nèi)多了一個(gè)函數(shù)(5.0也有類似功能的函數(shù)但是被放在結(jié)構(gòu)體外)!從函數(shù)的起名來(lái)看這個(gè)函數(shù)應(yīng)該是負(fù)責(zé)通知Service的狀態(tài)變化。Android6.0作這樣的改變我認(rèn)為僅僅是為了封裝。

另外一個(gè)就是init.main作了比較大的調(diào)整,但是同樣這些調(diào)整也只是讓整個(gè)程序的封裝性和可讀性更強(qiáng)罷了。實(shí)質(zhì)的處理流程并沒(méi)有什么變化。調(diào)整后的main函數(shù)如下:(變動(dòng)比較大的部分已經(jīng)用金底紅字標(biāo)出)

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

??? }

?

????// Clear the umask.

??? umask(0);

?

??? add_environment("PATH", _PATH_DEFPATH);

?

??? bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);

?

????// 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.

??? if (is_first_stage) {

??????? mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");

??????? mkdir("/dev/pts", 0755);

??????? mkdir("/dev/socket", 0755);

??????? mount("devpts", "/dev/pts", "devpts", 0, NULL);

??????? mount("proc", "/proc", "proc", 0, NULL);

??????? mount("sysfs", "/sys", "sysfs", 0, NULL);

??? }

?

????// We must have some place other than / to create the device nodes for

??? // kmsg and null, otherwise we won't be able to remount / read-only

??? // later on. Now that tmpfs is mounted on /dev, we can actually talk

??? // to the outside world.

??? open_devnull_stdio();

??? klog_init();

??? klog_set_level(KLOG_NOTICE_LEVEL);

?

??? NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");

?

??? if (!is_first_stage) {

????????// Indicate that booting is in progress to background fw loaders, etc.

??????? close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

?

????????property_init();

?

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

??????? process_kernel_cmdline();

?

????????// Propogate the kernel variables to internal variables

??????? // used by init as well as the current required properties.

??????? export_kernel_boot_props();

??? }

?

????// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.

??? selinux_initialize(is_first_stage);

?

????// If we're in the kernel domain, re-exec init to transition to the init domain now

??? // that the SELinux policy has been loaded.

??? if (is_first_stage) {

??????? if (restorecon("/init") == -1) {

??????????? ERROR("restorecon failed: %s\n", strerror(errno));

??????????? security_failure();

??????? }

??????? char* path = argv[0];

??????? char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };

??????? if (execv(path, args) == -1) {

??????????? ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));

??????????? security_failure();

??????? }

??? }

?

????// These directories were necessarily created before initial policy load

??? // and therefore need their security context restored to the proper value.

??? // This must happen before /dev is populated by ueventd.

??? INFO("Running restorecon...\n");

??? restorecon("/dev");

??? restorecon("/dev/socket");

??? restorecon("/dev/__properties__");

??? restorecon_recursive("/sys");

?

????epoll_fd = epoll_create1(EPOLL_CLOEXEC);

??? if (epoll_fd == -1) {

??????? ERROR("epoll_create1 failed: %s\n", strerror(errno));

??????? exit(1);

??? }

?

??? signal_handler_init();

?

??? property_load_boot_defaults();

????start_property_service();

?

????init_parse_config_file("/init.rc");

?

??? action_for_each_trigger("early-init", action_add_queue_tail);

?

????// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...

??? queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");

????// ... so that we can start queuing up actions that require stuff from /dev.

??? queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

??? queue_builtin_action(keychord_init_action, "keychord_init");

??? queue_builtin_action(console_init_action, "console_init");

?

????// Trigger all the boot actions to get us started.

??? action_for_each_trigger("init", action_add_queue_tail);

?

????// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random

??? // wasn't ready immediately after wait_for_coldboot_done

??? queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

?

??? // Don't mount filesystems or start core system services in charger mode.

??? char bootmode[PROP_VALUE_MAX];

??? if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {

??????? action_for_each_trigger("charger", action_add_queue_tail);

??? } else {

??????? action_for_each_trigger("late-init", action_add_queue_tail);

??? }

?

????// Run all property triggers based on current state of the properties.

??? queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

?

??? while (true) {

??????? if (!waiting_for_exec) {

????????????execute_one_command();

????????????restart_processes();

??????? }

?

??????? int timeout = -1;

??????? if (process_needs_restart) {

??????????? timeout = (process_needs_restart - gettime()) * 1000;

??????????? if (timeout < 0)

??????????????? timeout = 0;

??????? }

?

??????? if (!action_queue_empty() || cur_action) {

??????????? timeout = 0;

??????? }

?

??????? bootchart_sample(&timeout);

?

??????? epoll_event ev;

????????int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));

??????? if (nr == -1) {

??????????? ERROR("epoll_wait failed: %s\n", strerror(errno));

??????? } else if (nr == 1) {

????????????((void (*)()) ev.data.ptr)();//其實(shí)最根本的改變?cè)谶@,為了封裝

??????? }

??? }

?

??? return 0;

}

總的來(lái)講,6.0其實(shí)就是將原先5.0的方式改成了注冊(cè)式的。使得結(jié)構(gòu)性更強(qiáng)。

整理Zygote的啟動(dòng)大致如下圖所示(帶點(diǎn)紅色的標(biāo)示C++類,純綠的為java類):


可以看到,ART和Dalvik的啟動(dòng)是在JniInvocation.init(NULL)中,init的參數(shù)可以指定使用哪個(gè)虛擬機(jī),如果是NULL則默認(rèn)ART。實(shí)際上可以認(rèn)為是JniInvocation封裝掉了兩種虛擬機(jī)之間的差異(當(dāng)然這僅僅是說(shuō)的啟動(dòng))。

另一個(gè)收獲就是弄清楚了classname啟動(dòng),是指一些非Zygote 的java 程序的啟動(dòng)路徑,如am(shell),這種進(jìn)程和Zygote孵化出來(lái)的進(jìn)程最大的區(qū)別就是沒(méi)有binder線程池。

//App_main.main()

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.");

??????? return 10;

??? }

再次總結(jié)Zygote孵化進(jìn)程的過(guò)程如下圖所示。


總結(jié)

以上是生活随笔為你收集整理的Android6.0源码分析—— Zygote进程分析(补充)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。