原文地址: 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进程分析(补充)相关推荐

  1. android6.0源码分析之Zygote进程分析

    在android6.0源码分析之Runtime的初始化一文中,对Zygote进程的初期的Runtime初始化过程进行了分析,在Runtime启动结束后,会对Zygote进程进行初始化,其它Java进程 ...

  2. android6.0源码分析之AMS服务源码分析

    activitymanagerservice服务源码分析 1.ActivityManagerService概述 ActivityManagerService(以下简称AMS)作为Android中最核心 ...

  3. android6.0源码分析之Runtime的初始化

    Android运行时作为android架构的一部分,起着非常重要的作用,它和核心库(Core Libraries)组成了Android运行时库层.本文将依据android源码对AndroidRunti ...

  4. android6.0源码分析之Camera2 HAL分析

    1.Camera HAL的初始化 Camera HAL的初始加载是在Native的CameraService初始化流程中的,而CameraService初始化是在Main_mediaServer.cp ...

  5. android6.0源码分析之Camera API2.0下的Preview(预览)流程分析

    1.Camera2 preview的应用层流程分析 preview流程都是从startPreview开始的,所以来看startPreview方法的代码: <code class="hl ...

  6. android6.0源码分析之Camera API2.0下的初始化流程分析

    1.Camera2初始化的应用层流程分析 Camera2的初始化流程与Camera1.0有所区别,本文将就Camera2的内置应用来分析Camera2.0的初始化过程.Camera2.0首先启动的是C ...

  7. Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...

    Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮 前言 之前写过屏蔽系统导航栏功能的文章,具体可看Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP) ...

  8. Android6.0 源码修改之Settings音量调节界面增加通话音量调节

    Android6.0 源码修改之Settings音量调节界面增加通话音量调节 前言 今天客户提了个需求,因为我们的设备在正常情况下无法调节通话音量,只有在打电话过程中,按物理音量加减键才能出现调节通话 ...

  9. Android6.0源码解读之ViewGroup点击事件分发机制

    本篇博文是Android点击事件分发机制系列博文的第三篇,主要是从解读ViewGroup类的源码入手,根据源码理清ViewGroup点击事件分发原理,明白ViewGroup和View点击事件分发的关系 ...

最新文章

  1. Rails测试《一》fixtures简介
  2. How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
  3. 推荐五星级C语言学习网站
  4. 【bzoj3575】 Hnoi2014—道路堵塞
  5. 行政编码json_基于FME国内县级及以上网络公开行政区划边界的获取
  6. ASP.NET2.0数据操作之创建业务逻辑层
  7. REVERSE-PRACTICE-BUUCTF-6
  8. java 数据类型分为_JAVA中分为基本数据类型及引用数据类型
  9. Java设计模式学习总结(14)——结构型模式之代理模式
  10. 道路上下行是什么意思_了解道路禁止符号 春节压岁钱少填罚款
  11. html2canvas在手机不行,html2canvas - 在iOS设备上崩溃
  12. Sublime Text关闭自动更新
  13. 标准粒子群优化算法 PSO
  14. tan和cot的梗_cot和tan的关系
  15. 程序员值得提升的沟通小技巧!
  16. WTL自绘界面库(CQsStatic)
  17. python中re.sub函数使用
  18. 舒适区下的焦虑感和破局
  19. SOAR+HIDS,增强主机安全防护
  20. XingGAN for Person Image Generation(人体姿势生成笔记)

热门文章

  1. JQuery图片切换 Win8 Metro风格Banner
  2. 零基础入门NLP之搭建中文分词工具
  3. SNAT和DNAT的区别
  4. Python学习笔记:常用第三方模块(1)
  5. Maple 公式推导
  6. 【远程操控】Pycharm远程连接服务器之本地显示独立的plot窗口
  7. 关于Matconvnet中Conv-ReLU-Pool-NormBatch的总结与思考
  8. PIC单片机入门_同步/异步通信技术基础
  9. C++ builder 的文件读写操作总结
  10. javascript面象对象编程的三种方法