Android系统进程Zygote启动过程的源代码分析(2)
Step 2.AndroidRuntime.start
这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
- /*
- *StarttheAndroidruntime.Thisinvolvesstartingthevirtualmachine
- *andcallingthe"staticvoidmain(String[]args)"methodintheclass
- *namedby"className".
- */
- voidAndroidRuntime::start(constchar*className,constboolstartSystemServer)
- {
- ......
- char*slashClassName=NULL;
- char*cp;
- JNIEnv*env;
- ......
- /*startthevirtualmachine*/
- if(startVm(&mJavaVM,&env)!=0)
- gotobail;
- /*
- *Registerandroidfunctions.
- */
- if(startReg(env)<0){
- LOGE("Unabletoregisterallandroidnatives\n");
- gotobail;
- }
- /*
- *Wewanttocallmain()withaStringarraywithargumentsinit.
- *Atpresentweonlyhaveoneargument,theclassname.Createan
- *arraytoholdit.
- */
- jclassstringClass;
- jobjectArraystrArray;
- jstringclassNameStr;
- jstringstartSystemServerStr;
- stringClass=env->FindClass("java/lang/String");
- assert(stringClass!=NULL);
- strArray=env->NewObjectArray(2,stringClass,NULL);
- assert(strArray!=NULL);
- classNameStr=env->NewStringUTF(className);
- assert(classNameStr!=NULL);
- env->SetObjectArrayElement(strArray,0,classNameStr);
- startSystemServerStr=env->NewStringUTF(startSystemServer?
- "true":"false");
- env->SetObjectArrayElement(strArray,1,startSystemServerStr);
- /*
- *StartVM.ThisthreadbecomesthemainthreadoftheVM,andwill
- *notreturnuntiltheVMexits.
- */
- jclassstartClass;
- jmethodIDstartMeth;
- slashClassName=strdup(className);
- for(cp=slashClassName;*cp!='\0';cp++)
- if(*cp=='.')
- *cp='/';
- startClass=env->FindClass(slashClassName);
- if(startClass==NULL){
- ......
- }else{
- startMeth=env->GetStaticMethodID(startClass,"main",
- "([Ljava/lang/String;)V");
- if(startMeth==NULL){
- ......
- }else{
- env->CallStaticVoidMethod(startClass,startMeth,strArray);
- ......
- }
- }
- ......
- }
这个函数的作用是启动Android系统运行时库,它主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数。
Step 3.ZygoteInit.main
这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:
- publicclassZygoteInit{
- ......
- publicstaticvoidmain(Stringargv[]){
- try{
- ......
- registerZygoteSocket();
- ......
- ......
- if(argv[1].equals("true")){
- startSystemServer();
- }elseif(!argv[1].equals("false")){
- ......
- }
- ......
- if(ZYGOTE_FORK_MODE){
- ......
- }else{
- runSelectLoopMode();
- }
- ......
- }catch(MethodAndArgsCallercaller){
- ......
- }catch(RuntimeExceptionex){
- ......
- }
- }
- ......
- }
它主要作了三件事情,一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯,二是调用startSystemServer函数来启动SystemServer组件,三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。
Step 4.ZygoteInit.registerZygoteSocket
这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:
- publicclassZygoteInit{
- ......
- /**
- *Registersaserversocketforzygotecommandconnections
- *
- *@throwsRuntimeExceptionwhenopenfails
- */
- privatestaticvoidregisterZygoteSocket(){
- if(sServerSocket==null){
- intfileDesc;
- try{
- Stringenv=System.getenv(ANDROID_SOCKET_ENV);
- fileDesc=Integer.parseInt(env);
- }catch(RuntimeExceptionex){
- ......
- }
- try{
- sServerSocket=newLocalServerSocket(
- createFileDescriptor(fileDesc));
- }catch(IOExceptionex){
- .......
- }
- }
- }
- ......
- }
这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:
- publicclassZygoteInit{
- ......
- privatestaticfinalStringANDROID_SOCKET_ENV="ANDROID_SOCKET_zygote";
- ......
- }
那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:
- voidservice_start(structservice*svc,constchar*dynamic_args)
- {
- ......
- pid_tpid;
- ......
- pid=fork();
- if(pid==0){
- structsocketinfo*si;
- ......
- for(si=svc->sockets;si;si=si->next){
- intsocket_type=(
- !strcmp(si->type,"stream")?SOCK_STREAM:
- (!strcmp(si->type,"dgram")?SOCK_DGRAM:SOCK_SEQPACKET));
- ints=create_socket(si->name,socket_type,
- si->perm,si->uid,si->gid);
- if(s>=0){
- publish_socket(si->name,s);
- }
- }
- ......
- }
- ......
- }
每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_socket函数写入到环境变量中去:
- staticvoidpublish_socket(constchar*name,intfd)
- {
- charkey[64]=ANDROID_SOCKET_ENV_PREFIX;
- charval[64];
- strlcpy(key+sizeof(ANDROID_SOCKET_ENV_PREFIX)-1,
- name,
- sizeof(key)-sizeof(ANDROID_SOCKET_ENV_PREFIX));
- snprintf(val,sizeof(val),"%d",fd);
- add_environment(key,val);
- /*makesurewedon'tclose-on-exec*/
- fcntl(fd,F_SETFD,0);
- }
这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:#defineANDROID_SOCKET_ENV_PREFIX"ANDROID_SOCKET_" 因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了,参考Android应用程序进程启动过程的源代码分析一文中的Step 4,ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的:
- publicclassProcess{
- ......
- privatestaticvoidopenZygoteSocketIfNeeded()
- throwsZygoteStartFailedEx{
- ......
- for(intretry=0
- ;(sZygoteSocket==null)&&(retry<(retryCount+1))
- ;retry++){
- ......
- try{
- sZygoteSocket=newLocalSocket();
- sZygoteSocket.connect(newLocalSocketAddress(ZYGOTE_SOCKET,
- LocalSocketAddress.Namespace.RESERVED));
- sZygoteInputStream
- =newDataInputStream(sZygoteSocket.getInputStream());
- sZygoteWriter=
- newBufferedWriter(
- newOutputStreamWriter(
- sZygoteSocket.getOutputStream()),
- 256);
- ......
- }catch(IOExceptionex){
- ......
- }
- }
- ......
- }
- ......
- }
这里的ZYGOTE_SOCKET定义为:
- publicclassProcess{
- ......
- privatestaticfinalStringZYGOTE_SOCKET="zygote";
- ......
- }
它刚好就是对应/dev/socket目录下的zygote文件了。
Android系统中的socket机制和binder机制一样,都是可以用来进行进程间通信,读者可以自己对比一下这两者的不同之处,Binder进程间通信机制可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。
Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。
更多相关文章
- 从J2EE转向Android的第九天-----文件存储
- android 进程间通信示例
- Android笔记四 虚拟机Dalvik、Android各种java包功能、Android相
- Android系统进程Zygote启动过程的源代码分析
- android保存手势操作到文件&读取识别手势
- 一定是我打开的姿势不对——Android下使用kill命令杀死指定进程
- Android使用AIDL跨进程数据共享