/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Zygote" #include <cutils/sockets.h> #include <cutils/zygote.h> #include <cutils/log.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <time.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #define ZYGOTE_SOCKET "zygote" #define ZYGOTE_RETRY_COUNT 1000 #define ZYGOTE_RETRY_MILLIS 500 static void replace_nl(char *str); /* * If sendStdio is non-zero, the current process's stdio file descriptors * will be sent and inherited by the spawned process. */ static int send_request(int fd, int sendStdio, int argc, const char **argv) { #ifndef HAVE_ANDROID_OS // not supported on simulator targets //LOGE("zygote_* not supported on simulator targets"); return -1; #else /* HAVE_ANDROID_OS */ uint32_t pid; int i; struct iovec ivs[2]; struct msghdr msg; char argc_buffer[12]; const char *newline_string = "\n"; struct cmsghdr *cmsg; char msgbuf[CMSG_SPACE(sizeof(int) * 3)]; int *cmsg_payload; ssize_t ret; memset(&msg, 0, sizeof(msg)); memset(&ivs, 0, sizeof(ivs)); // First line is arg count snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc); ivs[0].iov_base = argc_buffer; ivs[0].iov_len = strlen(argc_buffer); msg.msg_iov = ivs; msg.msg_iovlen = 1; if (sendStdio != 0) { // Pass the file descriptors with the first write msg.msg_control = msgbuf; msg.msg_controllen = sizeof msgbuf; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg_payload = (int *)CMSG_DATA(cmsg); cmsg_payload[0] = STDIN_FILENO; cmsg_payload[1] = STDOUT_FILENO; cmsg_payload[2] = STDERR_FILENO; } do { ret = sendmsg(fd, &msg, MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); if (ret < 0) { return -1; } // Only send the fd's once msg.msg_control = NULL; msg.msg_controllen = 0; // replace any newlines with spaces and send the args for (i = 0; i < argc; i++) { char *tofree = NULL; const char *toprint; toprint = argv[i]; if (strchr(toprint, '\n') != NULL) { tofree = strdup(toprint); toprint = tofree; replace_nl(tofree); } ivs[0].iov_base = (char *)toprint; ivs[0].iov_len = strlen(toprint); ivs[1].iov_base = (char *)newline_string; ivs[1].iov_len = 1; msg.msg_iovlen = 2; do { ret = sendmsg(fd, &msg, MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); if (tofree != NULL) { free(tofree); } if (ret < 0) { return -1; } } // Read the pid, as a 4-byte network-order integer ivs[0].iov_base = &pid; ivs[0].iov_len = sizeof(pid); msg.msg_iovlen = 1; do { do { ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL); } while (ret < 0 && errno == EINTR); if (ret < 0) { return -1; } ivs[0].iov_len -= ret; ivs[0].iov_base += ret; } while (ivs[0].iov_len > 0); pid = ntohl(pid); return pid; #endif /* HAVE_ANDROID_OS */ } int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)) { int fd; int pid; int err; const char *newargv[argc + 1]; fd = socket_local_client(ZYGOTE_SOCKET, ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL); if (fd < 0) { return -1; } // The command socket is passed to the peer as close-on-exec // and will close when the peer dies newargv[0] = "--peer-wait"; memcpy(newargv + 1, argv, argc * sizeof(*argv)); pid = send_request(fd, 1, argc + 1, newargv); if (pid > 0 && post_run_func != NULL) { post_run_func(pid); } // Wait for socket to close do { int dummy; err = read(fd, &dummy, sizeof(dummy)); } while ((err < 0 && errno == EINTR) || err != 0); do { err = close(fd); } while (err < 0 && errno == EINTR); return 0; } /** * Spawns a new dalvik instance via the Zygote process. The non-zygote * arguments are passed to com.android.internal.os.RuntimeInit(). The * first non-option argument should be a class name in the system class path. * * The arg list may start with zygote params such as --set-uid. * * If sendStdio is non-zero, the current process's stdio file descriptors * will be sent and inherited by the spawned process. * * The pid of the child process is returned, or -1 if an error was * encountered. * * zygote_run_oneshot waits up to ZYGOTE_RETRY_COUNT * * ZYGOTE_RETRY_MILLIS for the zygote socket to be available. */ int zygote_run_oneshot(int sendStdio, int argc, const char **argv) { int fd = -1; int err; int i; int retries; int pid; const char **newargv = argv; const int newargc = argc; for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) { if (retries > 0) { struct timespec ts; memset(&ts, 0, sizeof(ts)); ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000; do { err = nanosleep (&ts, &ts); } while (err < 0 && errno == EINTR); } fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL, ANDROID_SOCKET_NAMESPACE_RESERVED); } if (fd < 0) { return -1; } pid = send_request(fd, 0, newargc, newargv); do { err = close(fd); } while (err < 0 && errno == EINTR); return pid; } /** * Replaces all occurrances of newline with space. */ static void replace_nl(char *str) { for(; *str; str++) { if (*str == '\n') { *str = ' '; } } }