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函数。
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 {
- ......
-
-
-
-
-
-
- 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);
-
-
- 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了,参考一文中的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进程间通信机制可以参考一文。
Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。
本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966546,如需转载请自行联系原作者