Android系统进程Zygote启动过程的源代码分析

转载自: http://blog.csdn.net/luoshengyang/article/details/6768304

这是目前总结的启动流程,ARM->bootloader->fastboot(uboot)->linux kernel->init (init.rc)->zygote,转载的这篇文章讲解的是最后这两步init(init.rc)->zygote

在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于Zygote进程在Android系统中有着如此重要的地位,本文将详细分析它的启动过程。

        在前面一篇文章Android应用程序进程启动过程的源代码分析中,我们看到了,当ActivityManagerService启动一个应用程序的时候,就会通过Socket与Zygote进程进行通信,请求它fork一个子进程出来作为这个即将要启动的应用程序的进程;在前面两篇文章Android应用程序安装过程源代码分析Android系统默认Home应用程序(Launcher)的启动过程源代码分析中,我们又看到了,系统中的两个重要服务PackageManagerService和ActivityManagerService,都是由SystemServer进程来负责启动的,而SystemServer进程本身是Zygote进程在启动的过程中fork出来的。

        我们知道,Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
    socket zygote stream 666  
    onrestart write /sys/android_power/request_state wake  
    onrestart write /sys/power/state on  
    onrestart restart media  
    onrestart restart netd  

??对于init如何启动app_process的方式还有些疑问,从init.c没有找到具体调用,查询其他资料说是由action_for_each_trigger()函数来启动的,没有看明白??

前面的关键字service告诉init进程创建一个名为"zygote"的进程,这个zygote进程要执行的程序是/system/bin/app_process,后面是要传给app_process的参数。

        接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。这里定义的socket的类型为unix domain socket,它是用来作本地进程间通信用的,具体可以参考前面一篇文章Android学习启动篇提到的一书《Linux内核源代码情景分析》的第七章--基于socket的进程间通信。前面我们说到的ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。

        最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。

        关于init.rc文件的更多信息,请参考system/core/init/readme.txt文件。

        了解了这个信息之后,我们就知道Zygote进程要执行的程序便是system/bin/app_process了,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。在继续分析Zygote进程启动的过程之前,我们先来看看它的启动序列图:


下面我们就详细分析每一个步骤。

        Step 1. app_process.main

        这个函数定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

int main(int argc, const char* const argv[])  
{  
    // These are global variables in ProcessState.cpp  
    mArgC = argc;  
    mArgV = argv;  
  
    mArgLen = 0;  
    for (int i=0; i<argc; i++) {  
        mArgLen += strlen(argv[i]) + 1;  
    }  
    mArgLen--;  
  
    AppRuntime runtime;  
    const char *arg0;  
    argv0 = argv[0];  
  
    // Process command line arguments  
    // ignore argv[0]  
    argc--;  
    argv++;  
  
    // Everything up to '--' or first non '-' arg goes to the vm  
  
    int i = runtime.addVmArguments(argc, argv);  
  
    // Next arg is parent directory  
    if (i < argc) {  
        runtime.mParentDir = argv[i++];  
    }  
  
    // Next arg is startup classname or "--zygote"  
    if (i < argc) {  
        arg = argv[i++];  
        if (0 == strcmp("--zygote", arg)) {  
            bool startSystemServer = (i < argc) ?  
                strcmp(argv[i], "--start-system-server") == 0 : false;  
            setArgv0(argv0, "zygote");  
            set_process_name("zygote");  
            runtime.start("com.android.internal.os.ZygoteInit",  
                startSystemServer);  
        } else {  
            set_process_name(argv0);  
  
            runtime.mClassName = arg;  
  
            // Remainder of args get passed to startup class main()  
            runtime.mArgC = argc-i;  
            runtime.mArgV = argv+i;  
  
            LOGV("App process is starting with pid=%d, class=%s.\n",  
                getpid(), runtime.getClassName());  
            runtime.start();  
        }  
    } else {  
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");  
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");  
        app_usage();  
        return 10;  
    }  
  
}  
?? zygote最初名称为app_process,在这里重新修改了进程名称为zygote??
set_process_name("zygote");

这个函数的主要作用就是创建一个AppRuntime变量,然后调用它的start成员函数。AppRuntime这个类我们在 Android应用程序进程启动过程的源代码分析 一文中已经有过介绍了,它同样是在frameworks/base/cmds/app_process/app_main.cpp文件中定义:

class AppRuntime : public AndroidRuntime  
{  
    ......  
};

 它约继承于AndroidRuntime类, AndroidRuntime类定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

......  
  
static AndroidRuntime* gCurRuntime = NULL;  
  
......  
  
AndroidRuntime::AndroidRuntime()  
{  
    ......  
  
    assert(gCurRuntime == NULL);        // one per process  
    gCurRuntime = this;  
}  

当AppRuntime对象创建时,会调用其父类AndroidRuntime的构造函数,而在AndroidRuntime类的构造函数里面,会将this指针保存在静态全局变量gCurRuntime中,这样,当其它地方需要使用这个AppRuntime对象时,就可以通过同一个文件中的这个函数来获取这个对象的指针:

AndroidRuntime* AndroidRuntime::getRuntime()  
{  
    return gCurRuntime;  
}  

回到上面的main函数中,由于我们在init.rc文件中,设置了app_process启动参数--zygote和--start-system-server,因此,在main函数里面,最终会执行下面语句:

runtime.start("com.android.internal.os.ZygoteInit",  rtSystemServer); 

这里的参数startSystemServer为true,表示要启动SystemServer组件。由于AppRuntime没有实现自己的start函数,它继承了父类AndroidRuntime的start函数,因此,下面会执行AndroidRuntime类的start函数。

        Step 2. AndroidRuntime.start

        这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

/* 
* Start the Android runtime.  This involves starting the virtual machine 
* and calling the "static void main(String[] args)" method in the class 
* named by "className". 
*/  
void AndroidRuntime::start(const char* className, const bool startSystemServer)  
{  
    ......  
  
    char* slashClassName = NULL;  
    char* cp;  
    JNIEnv* env;  
  
    ......  
  
    /* start the virtual machine */  
    if (startVm(&mJavaVM, &env) != 0)  
        goto bail;  
  
    /* 
    * Register android functions. 
    */  
    if (startReg(env) < 0) {  
        LOGE("Unable to register all android natives\n");  
        goto bail;  
    }  
  
    /* 
    * We want to call main() with a String array with arguments in it. 
    * At present we only have one argument, the class name.  Create an 
    * array to hold it. 
    */  
    jclass stringClass;  
    jobjectArray strArray;  
    jstring classNameStr;  
    jstring startSystemServerStr;  
    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);  
  
    /* 
    * Start VM.  This thread becomes the main thread of the VM, and will 
    * not return until the VM exits. 
    */  
    jclass startClass;  
    jmethodID startMeth;  
  
    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函数。

??以前有遇到过Gallery等程序操作大图片时出现OOM的情况,由于目前的项目内存都比较大,所以都有直接去改过Dalvik VM默认内存分配限制,这个限制就可以从startVM中修改。当然更为合理的修改地方是在dalvik/vm/Init.c里面。??

        Step 3. ZygoteInit.main

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:


public class ZygoteInit {  
    ......  
  
    public static void main(String argv[]) {  
        try {  
            ......  
  
            registerZygoteSocket();  
              
            ......  
  
            ......  
  
            if (argv[1].equals("true")) {  
                startSystemServer();  
            } else if (!argv[1].equals("false")) {  
                ......  
            }  
  
            ......  
  
            if (ZYGOTE_FORK_MODE) {  
                ......  
            } else {  
                runSelectLoopMode();  
            }  
  
            ......  
        } catch (MethodAndArgsCaller caller) {  
            ......  
        } catch (RuntimeException ex) {  
            ......  
        }  
    }  
  
    ......  
}  

它主要作了三件事情,一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯,二是调用startSystemServer函数来启动SystemServer组件,三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。

         Step 4. ZygoteInit.registerZygoteSocket

         这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {  
    ......  
  
    /** 
    * Registers a server socket for zygote command connections 
    * 
    * @throws RuntimeException when open fails 
    */  
    private static void registerZygoteSocket() {  
        if (sServerSocket == null) {  
            int fileDesc;  
            try {  
                String env = System.getenv(ANDROID_SOCKET_ENV);  
                fileDesc = Integer.parseInt(env);  
            } catch (RuntimeException ex) {  
                ......  
            }  
  
            try {  
                sServerSocket = new LocalServerSocket(  
                    createFileDescriptor(fileDesc));  
            } catch (IOException ex) {  
                .......  
            }  
        }  
    }  
          
    ......  
} 

这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:

public class ZygoteInit {  
    ......  
  
    private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";  
          
    ......  
}  

那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:

void service_start(struct service *svc, const char *dynamic_args)  
{  
    ......  
  
    pid_t pid;  
  
    ......  
  
    pid = fork();  
  
    if (pid == 0) {  
        struct socketinfo *si;  
  
        ......  
  
        for (si = svc->sockets; si; si = si->next) {  
            int socket_type = (  
                !strcmp(si->type, "stream") ? SOCK_STREAM :  
                (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
            int s = 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函数写入到环境变量中去:

static void publish_socket(const char *name, int fd)  
{  
    char key[64] = ANDROID_SOCKET_ENV_PREFIX;  
    char val[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);  
  
    /* make sure we don't close-on-exec */  
    fcntl(fd, F_SETFD, 0);  
}  

这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:

#define ANDROID_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的:

public class Process {  
	......  
 
	private static void openZygoteSocketIfNeeded()  
			throws ZygoteStartFailedEx {  

		......

		for (int retry = 0  
			; (sZygoteSocket == null) && (retry < (retryCount + 1))  
			; retry++ ) {  

				......

				try {  
					sZygoteSocket = new LocalSocket();  
					sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,  
						LocalSocketAddress.Namespace.RESERVED));  

					sZygoteInputStream  
						= new DataInputStream(sZygoteSocket.getInputStream());  

					sZygoteWriter =  
						new BufferedWriter(  
						new OutputStreamWriter(  
						sZygoteSocket.getOutputStream()),  
						256);  

					......  
				} catch (IOException ex) {  
					......  
				}  
		}  

		......  
	}  

	......  
}

  这里的ZYGOTE_SOCKET定义为:

public class Process {  
	......  
 
	private static final String ZYGOTE_SOCKET = "zygote";  

	......  
} 

它刚好就是对应/dev/socket目录下的zygote文件了。

        Android系统中的socket机制和binder机制一样,都是可以用来进行进程间通信,读者可以自己对比一下这两者的不同之处,Binder进程间通信机制可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

       Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。

       Step 5. ZygoteInit.startSystemServer
       这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:


public class ZygoteInit {
	......

	private static boolean startSystemServer()
			throws MethodAndArgsCaller, RuntimeException {
		/* Hardcoded command line to start the system server */
		String args[] = {
			"--setuid=1000",
			"--setgid=1000",
			"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
			"--capabilities=130104352,130104352",
			"--runtime-init",
			"--nice-name=system_server",
			"com.android.server.SystemServer",
		};
		ZygoteConnection.Arguments parsedArgs = null;

		int pid;

		try {
			parsedArgs = new ZygoteConnection.Arguments(args);

			......

			/* Request to fork the system server process */
			pid = Zygote.forkSystemServer(
				parsedArgs.uid, parsedArgs.gid,
				parsedArgs.gids, debugFlags, null,
				parsedArgs.permittedCapabilities,
				parsedArgs.effectiveCapabilities);
		} catch (IllegalArgumentException ex) {
			......
		}

		/* For child process */
		if (pid == 0) {
			handleSystemServerProcess(parsedArgs);
		}

		return true;
	}
	
	......
}

这里我们可以看到,Zygote进程通过Zygote.forkSystemServer函数来创建一个新的进程来启动SystemServer组件,返回值pid等0的地方就是新的进程要执行的路径,即新创建的进程会执行handleSystemServerProcess函数。

        Step 6. ZygoteInit.handleSystemServerProcess
        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:


public class ZygoteInit {
	......

	private static void handleSystemServerProcess(
			ZygoteConnection.Arguments parsedArgs)
			throws ZygoteInit.MethodAndArgsCaller {
		closeServerSocket();

		/*
		* Pass the remaining arguments to SystemServer.
		* "--nice-name=system_server com.android.server.SystemServer"
		*/
		RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
		/* should never reach here */
	}

	......
} 

  由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 4中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。

        Step 7. RuntimeInit.zygoteInit

        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:


public class RuntimeInit {  
	......  

	public static final void zygoteInit(String[] argv)  
			throws ZygoteInit.MethodAndArgsCaller {  
		......  
  
		zygoteInitNative();  

		......  


		// Remaining arguments are passed to the start class's static main  

		String startClass = argv[curArg++];  
		String[] startArgs = new String[argv.length - curArg];  

		System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  
		invokeStaticMain(startClass, startArgs);  
	}  

	......  
}

这个函数会执行两个操作,一个是调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作,这个工作完成之后,这个进程中的Binder对象就可以方便地进行进程间通信了,另一个是调用上面Step 5传进来的com.android.server.SystemServer类的main函数。

         Step 8. RuntimeInit.zygoteInitNative

         这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class RuntimeInit {  
	......  

	public static final native void zygoteInitNative();  

	......  
}

这里可以看出,函数zygoteInitNative是一个Native函数,实现在frameworks/base/core/jni/AndroidRuntime.cpp文件中,这里我们就不再细看了,具体可以参考 Android应用程序进程启动过程的源代码分析 一文的Step 9,完成这一步后,这个进程的Binder进程间通信机制基础设施就准备好了。

        回到Step 7中的RuntimeInit.zygoteInitNative函数,下一步它就要执行com.android.server.SystemServer类的main函数了。

        Step 9. SystemServer.main

        这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

public class SystemServer  
{  
	......  

	native public static void init1(String[] args);  

	......  

	public static void main(String[] args) {  
		......  

		init1(args);  

		......  
	} 

	public static final void init2() {  
		Slog.i(TAG, "Entered the Android system server!");  
		Thread thr = new ServerThread();  
		thr.setName("android.server.ServerThread");  
		thr.start();  
	}  

	......  
}

这里的main函数首先会执行JNI方法init1,然后init1会调用这里的init2函数,在init2函数里面,会创建一个ServerThread线程对象来执行一些系统关键服务的启动操作,例如我们在前面两篇文章 Android应用程序安装过程源代码分析 Android系统默认Home应用程序(Launcher)的启动过程源代码分析 中提到的PackageManagerService和ActivityManagerService。
        这一步的具体执行过程可以参考 Android应用程序安装过程源代码分析 一文,这里就不再详述了。

        这里执行完成后,层层返回,最后回到上面的Step 3中的ZygoteInit.main函数中,接下来它就要调用runSelectLoopMode函数进入一个无限循环在前面Step 4中创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程了。

        Step 10. ZygoteInit.runSelectLoopMode

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {
	......

	private static void runSelectLoopMode() throws MethodAndArgsCaller {
		ArrayList<FileDescriptor> fds = new ArrayList();
		ArrayList<ZygoteConnection> peers = new ArrayList();
		FileDescriptor[] fdArray = new FileDescriptor[4];

		fds.add(sServerSocket.getFileDescriptor());
		peers.add(null);

		int loopCount = GC_LOOP_COUNT;
		while (true) {
			int index;

			......


			try {
				fdArray = fds.toArray(fdArray);
				index = selectReadable(fdArray);
			} catch (IOException ex) {
				throw new RuntimeException("Error in select()", ex);
			}

			if (index < 0) {
				throw new RuntimeException("Error in select()");
			} else if (index == 0) {
				ZygoteConnection newPeer = acceptCommandPeer();
				peers.add(newPeer);
				fds.add(newPeer.getFileDesciptor());
			} else {
				boolean done;
				done = peers.get(index).runOnce();

				if (done) {
					peers.remove(index);
					fds.remove(index);
				}
			}
		}
	}

	......
}      

这个函数我们已经在 Android应用程序进程启动过程的源代码分析 一文的Step 5中分析过了,这就是在等待ActivityManagerService来连接这个Socket,然后调用ZygoteConnection.runOnce函数来创建新的应用程序,有兴趣的读者可以参考 Android应用程序进程启动过程的源代码分析 这篇文章,这里就不再详述了。

        这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:

        1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。

        2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。

        3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值