古语云:机会总是留给有准备的人。为了这场战役,我准备了如下几个利器。
战不得不战,打非得打。但也不能蛮打不是,蛮打多么没素质,没品位呢。得智取。于是乎,了解一下对方的实力吧。
敌手实力不容小视,单单一个Android系统启动流程就屯兵百万。
瞎话就不叙述了,进入正题,据探子回报:
底层linux kernel
Android源代码于底层linux搭边的在System\core…里。而存放各种待解析的文件则在System\core\rootdir里面。比如init.rc,uevent.rc,init.zygote32.rc等,以rc为文件后缀存放的,类似于编译原理的各种规定的语法格式,以便后面文件进行解析。
次底层的libraries以及Android Runtime的Dalvik 虚拟机
这里面包含了引用库。一般都存放在模块的子目录里。
主要包含C语言和JNI等编写的程序。
次顶层的Application Framework
是各种服务的管理者,activity manager,resource manager,view System等。主要存在于framwork\base\里。包含Java语言,c++语言,以及native的JNI。
顶层的Application
这个就不多说了,各种api,各种服务都给你准备好了,只等调用了。
本次关于启动的研究,没深入敌营到如此深的地步,止步于次底层。
本想从别的地方找找开打的地方,但是基于程序员的潜意识,总觉得init是个梦开始的地方。哈哈。那就从这研究吧。
int main(int argc, char **argv)
{
int fd_count = 0;
struct pollfd ufds[4];
char *tmpdev;
char* debuggable;
char tmp[32];
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
bool is_charger = false;
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);
/* 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.
*/
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
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);
/* indicate that booting is in progress to background fw loaders, etc */
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
...........
.............
INFO("reading config file\n");
init_parse_config_file("/init.rc");
action_for_each_trigger("early-init", action_add_queue_tail);
for(;;) {
int nr, i, timeout = -1;
execute_one_command();
restart_processes();
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action)
timeout = 0;
#if BOOTCHART
if (bootchart_count > 0) {
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
timeout = BOOTCHART_POLLING_MS;
if (bootchart_step() < 0 || --bootchart_count == 0) {
bootchart_finish();
bootchart_count = 0;
}
}
#endif
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents & POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
}
return 0;
}
单单一个main函数就又高又壮,看的头都大了。那就umask(0)为何是权限最大值,请查阅相关资料,这给个链接啊http://zhidao.baidu.com/link?url=EM6Z49OctQaxCVa38HloyfgpnIqVguMRWRW7T16dt3njaY1ykN4UlkFGHli-PJnTYfFmR51WjrtS9ImAr4f7Z
Pc_)。然后不能浪费上面给的权力啊,因此会执行各种目录的建立,挂载,关于init.rc的解析,解析后会产生响应的属性配置list表,进行属配置,配置后启动相应的service_list,这里会启动zygo后面就会属性启动,例如:来大麻烦。最后不断的检测和重启挂掉的服务。对于service的结构体的定义书《深入理解Android》有介绍,里面各种属性被赋值,各种服务所携带的属性值也就不同了,后面就会属性启动,例如:zygote的svc(为service的结构体)svc->classname为default属性。解决掉init的main函数之后,再去找找附带的喽喽兵看看。
来到init.rc的文件下,看看所谓的用规定语法格式进行指令书写的文件的是什么样。截图如下:
注意到了没,以on和service的关键字的前面没有缩进啊,说明这两个是要存在什么问题的,查看keyword.h的里面的宏定义,发现对应SECTION,同时还存在其它几种,opinion和command。这样解析的时候就会差别对待。
对于初始化起来的各项服务有很多,除了基本的内核通信之类的服务之外,哪个服务是给后期Android启动铺路的呢?这需要研究研究。在init.zygote32_64.rc的文件中,发现了这个。
里面有Android_power以及power state on。入口是这啊。且慢,最上面一行的又是啥东东?system\bin下面的app_process32 和后面的start system_server…..socket-name = zygote?
实际上,深入浅出Android书里已说明,zygote本身是一个native的应用程序,和驱动以及内核没有关系。从上面的指令中我们也看到system\bin\app_process32。也就是zygote的另一个名字。
接下来转入到zygote的初始化,转到路径framework\base\core\java\com\android\internal\os\zygoteinit.java.看到了如下的东东。
开始要进行Dalvik虚拟机框架启动的简要框架集成的初始化,随后对main函数的其他属性值进行检查赋值操作。图中圈大圈的部分。然后注册socket套接字,书写系统事件日志。为Dalvik虚拟机进行简要的框架环境注册之后,要进行预加载各种资源以及类,书中说要加载的类多大1200多个,时代在进步,目前已经有3000多个类要预先加载。使用gc进行建议性的回收,因为Java的回收我们是没有办法进行精准的控制。这样做的目的也是对之前预加载后进行空间上的资源释放。启动system server。runSelectLoop。关闭socket。会有疑惑,怎么关闭了socket了,难道zygote命要终结了?其实不是,在关闭之前,runselectloop被调用,里面是while(true){}。会不断响应其他请求。
对于system server启动,涉及好多服务类,以及对各个服务的守护,今天时间有限,改日了解记录。