|  | /* | 
|  | * 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 = ' '; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  |