是时候整理下笔记了,加入了Android 客户组也有一段时间了,现在又要被调回到平台组去,趁着元旦想先整理下和Android相关的一些东西。
首先是Android的启动。这个是我进这个组了解安卓平台的第一个入门点。
由于是笔记转过来的,可能整理的不是很好。
Android起来首先是按照Linux的启动来的,在kernel的启动过程中,可以看到Linux启动的第一个用户进程是/sbin/init,这个代码在property_service.c中
1、创建相关文件夹并设置权限。Mount几个动态文件夹/proc,/sysfs等等
2、重定向输入输出到null,初始化权限域、内核打印信息,获取硬件相关信息等等
3、难点在这
/*
具体解析过程见system\core\init\Init_parser.c。
解析所得服务添加到service_list中,动作添加到action_list中。*/
init_parse_config_file(“/init.rc”);//加载解析/init.rc,要注意service是在class_start才会启动
主要看 parse_config(fn, data);基本的实现方式就是典型的链表加递归方式来解析整个文件。可以看到主要是一行一行地进行,然后首先会找到SECTION,所谓的section,在init.rc中,可以看到service是一种,action是一种。(这个可以去结合init.rc的语法学习)
这里得先看
重点在于对头文件的巧妙使用,kerywords.h之中定义了在init.rc中会使用到的命令用到的函数。从下图可以看到会有很多不同的flags,使用上面的宏,就可以提取出这些函数的相关信息。
对该头文件还有第二次引用,在这次引用中,将会头文件定义的函数加到这个keyword_info数组里。这个关键字是给这些字段注册相应的执行函数。
对于一个新的行,想得到他的keyword,在调用parse_line函数,这个函数对应不一样的section,是会指向不同函数的。
看parse_new_section就是说在一行一行下来,等到到了一个新的section时,就要重新去定义parse_line。
主要是三种section的关键词:on,service,import
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
parse_service中主要是获取service的name,然后加到service_list,其实这个只是一个架子,没实质内容。后面state->parse_line = parse_line_service;定义了这个函数指针的内容,可以看到就是将service下面的内容对应的函数加到cmd_list中。(只有加到这个链表之中的函数,后面才会调用)
同样的道理,可以看到对action的处理也是差不多的,唯一不同就是action下只能加command,而service可以加command和operation
重新回到init.c中,可以看到接下来就是将各种trigeer对应的函数加进来。但是在此都没调用。
最后是进入到了一个for循环中,在这个循环中,
首先,是
**execute_one_command();//到这里才是运行前面加在列表中的命令?class_start启动service
restart_processes();//重启那些加了重启的service**
然后,会将三个fd加到POLL的文件描述符集之中。调用POLL来轮询这几个fd。要知道在前面很多地方没说的,是会创建这三个相应的socket,在一些服务死了之后,通过这些socket进行通信,这个时候,POLL就会有反映了,就能执行相应的动作,例如重启service。
大致流程是这样。
Service的启动是这样的,首先在设置service的时候,会将其加入到一个类中,后面class_start会将他们起来,如果没加的话,说明设置为默认属性。
前面讲了一大堆,只是简单的讲了一开始起来系统的一些初始化工作,property是这么用起来的以及对init.rc是怎么去解析的。但是要知道,这个时候其实还算是在Linux的部分,因为还没进入虚拟机。
对于这个部分就这样粗略的过了。接下来是进入zygote
在init.rc中可以看到
注册了zygote这个service,并传入参数–start-system-server
在init.rc中class_star会使相关service启动。
启动zygote的程序是/system/bin/app_process,(app_main.cpp)可以看到,代码中根据传入的参数进行配置,
然后替换程序名字。(所以我们看到的名字才叫zygote,人家本来叫app_process)
启动zygote
很简单,但是这里的实际工作交给了runtime.star来实现,进入看看。(AndroidRuntime.cpp)
只讲我认为最主要的地方。
1、启动虚拟机
2、注册JNI函数
详细看startReg的话,可以看到
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
在这里,可以进入看到他只是去执行在gRegJNI这个数组之中的函数指针的函数。
那么这个函数指针是很多很多JNI函数。再细看就会发现这种注册方法跟在framework模板中的注册方法是一样的。
其实在app_main函数中会调用 AndroidRuntime::start去声明要调com.android.internal.os.ZygoteInit这个类。也就是说,最后zygote的实现是在java中实现的。也就是上面的这个类。
3、从C代码回调JAVA代码来真正完成zygote的工作
类在ZygoteInit.java中
首先,是注册zygote使用的socket
registerZygoteSocket();//注册zygote用的socket
第二,预加载类和资源
preload();//预加载类和资源,这里也就是为什么apk越多开机越慢的主要原因之一了
第三
gc(); // Do an initial gc to clean up after startup强行执行一次垃圾回收
第四 很重要,启动system_server
startSystemServer();//启动systemsever
如下图,可以看到在这个里面,就是使用了Linux的fork-exec机制
在java中,要先配置要fork和exec的参数,具体看代码。
第五,重要,zygote将使用select的机制,来等待上面的socket产生反应,也就是说,zygote进入休眠,但是在需要他来产生进程的时候,他就会醒来。
最后是清除一些上面设置的东西
至此zygote的部分就简单讲完了,这里就已经进入了Java虚拟机的部分了。接下来要讲另一个很重要的进程,由zygote生出来的system_server
下面讲下system_server的启动流程:
ZygoteInit.java的第四步中要去创建system_server
如下:
进如该函数:
1、传入要参数
2、在zygote的socket通信中,客户端成为ZygoteConnection。
3、调用forkSystemServer启动system_server,这个会调到dalvik_system_Zygote.cpp中的Dalvik_dalvik_system_Zygote_forkSystemServer函数。
4、子进程处理 handleSystemServerProcess。
下面详细讲下3和4 。
3:Dalvik_dalvik_system_Zygote_forkSystemServer
在此会调用
这个函数主要实现两个部分的功能:
(1)设置信号处理函数,
信号处理函数主要是让system_server和zygote同生死。
(2)使用fork复制了zygote
并且出来后会判断system_server是否退出,是的话,则让zygote也自杀。
4:handleSystemServerProcess
(1)首先会关闭从zygote继承的socket,因为待会zygote的socket主要是用来接受请求,fork进程的,system_server把他们关掉
(2)然后实质性的工作:
看下这个函数
nativezygoteInit是为了使zygote能使用binder
下面那个applicationInit比较重要:调用了****invokeStaticMain(args.startClass, args.startArgs);这个函数,这个函数会调用一个类里的main函数。(而且是以抛出异常的方式来调用main的,为的是节省栈资源?)
然后就启动了
“com.android.server.SystemServer”,//类的main
SystemServer的main主要做了3个工作:
(1)System.loadLibrary(“android_servers”);加载这个库
(2)init1(args) 这个是native函数,为
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
system_init();
}
而system_init()创建了一些系统服务,加入binder通信系统,并且在回调init2。
(3)Init2会启动Android主要的service项目。(ServiceManager.addService函数)init2很多service是Android很重要的基础服务。
Android 从 Linux 系统启动有 4 个步骤;
(1) init 进程启动
(2) Native 服务启动
(3) System Server,Android 服务启动
(4) Home 启动
总体启动框架图如:
第一步:initial 进程(system\core\init)
init 进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等) 之后, 就通过启动一个用户级程序init 的方式,完成引导进程。init 始终是第一个进程.
Init.rc
Init.marvell.rc
Init 进程一起来就根据 init.rc 和 init.xxx.rc 脚本文件建立了几个基本的服务:
servicemanamger
zygote
。 。 。
最后 Init 并不退出,而是担当起 property service 的功能。
1.1 脚本文件
init@System/Core/Init
Init.c: parse_config_file(Init.rc)
@parse_config_file(Init.marvel.rc)
解析脚本文件:Init.rc 和 Init.xxxx.rc(硬件平台相关)
Init.rc 是 Android 自己规定的初始化脚本(Android Init Language, System/Core/Init/readme.txt)
该脚本包含四个类型的声明:
Actions
Commands
Services
Options.
1.2 服务启动机制
我们来看看 Init 是这样解析.rc 文件开启服务的。
(1)打开.rc 文件,解析文件内容@ system\core\init\init.c
将 service 信息放置到 service_list 中。@ system\core\init parser.c
(2)restart_service()@ system\core\init\init.c
service_start
execve(…).建立 service 进程。
第二步 Zygote
Servicemanager 和 zygote 进程就奠定了 Android 的基础。Zygote 这个进程起来才会建立起真正的 Android 运行空间, 初始化建立的 Servic e 都是 Navtive service.在.rc 脚本文件中 zygot e的描述:
service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
所以 Zygote 从 main(…)@frameworks\base\cmds\app_main.cpp 开始。
(1) main(…)@frameworks\base\cmds\app_main.cpp
建立 Java Runtime
runtime.start(“com.android.internal.os.ZygoteInit”, startSystemServer);
(2) [email protected]
建立虚拟机
运行:com.android.internal.os.ZygoteInit:main 函数。
(3)main()@com.android.internal.os.ZygoteInit//正真的 Zygote。
registerZygoteSocket();//登记 Listen 端口
startSystemServer();
进入 Zygote 服务框架。
经过这几个步骤,Zygote 就建立好了,利用 Socket 通讯,接收 ActivityManangerService 的
请求,Fork 应用程序。
第三步 System Server
[email protected] 在 Zygote 上 fork 了 一 个 进 程 :
com.android.server.SystemServer.于是 SystemServer@(SystemServer.java)就建立了。Android的所有服务循环框架都是建立 SystemServer@(SystemServer.java )上。在 SystemServer.java看不到循环结构, 只是可以看到建立了 init 2 的实现函数, 建立了一大堆服务, 并 AddService到 service Manager。
main() @ com/android/server/SystemServer
{
init1();
}
Init1()是在 Native 空间实现的 (com_andoird_server_systemServer.cpp ) 。 我们一看这个函数就知道了,init1->system_init() @System_init.cpp
在 system_init()我们看到了循环闭合管理框架。
{
Call “com/android/server/SystemServer”, “init2”
…..
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
init2()@SystemServer.java 中建立了 Android 中所有要用到的服务。
这个 init2()建立了一个线程,来 New Service 和 AddService 来建立服务
第四步 Home 启动
在 [email protected] 后半段,我们可以看到系统在启动完所有的 Android 服务后,做了这样一些动作:
(1) 使用 xxx.systemReady()通知各个服务,系统已经就绪。
(2) 特别对于 ActivityManagerService.systemReady(回调)
Widget.wallpaper,imm(输入法)等 ready 通知。
Home 就 是 在 ActivityManagerService.systemReady() 通 知 的 过 程 中 建 立 的 。 下 面 是
ActivityManagerService.systemReady()的伪代码:
systemReady()@ActivityManagerService.java
resumeTopActivityLocked()
startHomeActivityLocked();//如果是第一个则启动 HomeActivity。
startActivityLocked(。 。 。 )CATEGORY_HOME