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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

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

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


此博文為《Android5.0源碼分析—— Zygote進程分析》的補充

我們已經知道Android?5.0已經默認了ART,今天本想回去查看一下這個部分,于是回到init進程中去尋找源碼,發現6.0的Zygote部分也小有變動,因此更新一下。

首先是init.c變成了init.cpp,這其實也就意味著在init中增加了類的概念。但是仔細查看init.h發現并沒有class關鍵字。只有很多的struct。如果對C++比較了解,就應該知道C++的struct和C中的struct其實已經是不一樣的概念了,在C++中struct除了公私與class對調外,其他的基本上沒有區別。在init.h中定義了以下結構體:

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版本的最大區別就是結構體內多了一個函數(5.0也有類似功能的函數但是被放在結構體外)!從函數的起名來看這個函數應該是負責通知Service的狀態變化。Android6.0作這樣的改變我認為僅僅是為了封裝。

另外一個就是init.main作了比較大的調整,但是同樣這些調整也只是讓整個程序的封裝性和可讀性更強罷了。實質的處理流程并沒有什么變化。調整后的main函數如下:(變動比較大的部分已經用金底紅字標出)

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)();//其實最根本的改變在這,為了封裝

??????? }

??? }

?

??? return 0;

}

總的來講,6.0其實就是將原先5.0的方式改成了注冊式的。使得結構性更強。

整理Zygote的啟動大致如下圖所示(帶點紅色的標示C++類,純綠的為java類):


可以看到,ART和Dalvik的啟動是在JniInvocation.init(NULL)中,init的參數可以指定使用哪個虛擬機,如果是NULL則默認ART。實際上可以認為是JniInvocation封裝掉了兩種虛擬機之間的差異(當然這僅僅是說的啟動)。

另一個收獲就是弄清楚了classname啟動,是指一些非Zygote 的java 程序的啟動路徑,如am(shell),這種進程和Zygote孵化出來的進程最大的區別就是沒有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;

??? }

再次總結Zygote孵化進程的過程如下圖所示。


總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。