The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2007 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #define LOG_TAG "Zygote" |
| 18 | |
| 19 | #include <cutils/sockets.h> |
| 20 | #include <cutils/zygote.h> |
| 21 | #include <cutils/log.h> |
| 22 | |
| 23 | #include <stdio.h> |
| 24 | #include <string.h> |
| 25 | #include <errno.h> |
| 26 | #include <time.h> |
| 27 | #include <stdint.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <unistd.h> |
| 30 | #include <arpa/inet.h> |
| 31 | #include <sys/types.h> |
| 32 | #include <sys/socket.h> |
| 33 | |
| 34 | #define ZYGOTE_SOCKET "zygote" |
| 35 | |
| 36 | #define ZYGOTE_RETRY_COUNT 1000 |
| 37 | #define ZYGOTE_RETRY_MILLIS 500 |
| 38 | |
| 39 | static void replace_nl(char *str); |
| 40 | |
| 41 | /* |
| 42 | * If sendStdio is non-zero, the current process's stdio file descriptors |
| 43 | * will be sent and inherited by the spawned process. |
| 44 | */ |
| 45 | static int send_request(int fd, int sendStdio, int argc, const char **argv) |
| 46 | { |
| 47 | #ifndef HAVE_ANDROID_OS |
| 48 | // not supported on simulator targets |
Steve Block | 01dda20 | 2012-01-06 14:13:42 +0000 | [diff] [blame] | 49 | //ALOGE("zygote_* not supported on simulator targets"); |
The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 50 | return -1; |
| 51 | #else /* HAVE_ANDROID_OS */ |
| 52 | uint32_t pid; |
| 53 | int i; |
| 54 | struct iovec ivs[2]; |
| 55 | struct msghdr msg; |
| 56 | char argc_buffer[12]; |
| 57 | const char *newline_string = "\n"; |
| 58 | struct cmsghdr *cmsg; |
| 59 | char msgbuf[CMSG_SPACE(sizeof(int) * 3)]; |
| 60 | int *cmsg_payload; |
| 61 | ssize_t ret; |
| 62 | |
| 63 | memset(&msg, 0, sizeof(msg)); |
| 64 | memset(&ivs, 0, sizeof(ivs)); |
| 65 | |
| 66 | // First line is arg count |
| 67 | snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc); |
| 68 | |
| 69 | ivs[0].iov_base = argc_buffer; |
| 70 | ivs[0].iov_len = strlen(argc_buffer); |
| 71 | |
| 72 | msg.msg_iov = ivs; |
| 73 | msg.msg_iovlen = 1; |
| 74 | |
| 75 | if (sendStdio != 0) { |
| 76 | // Pass the file descriptors with the first write |
| 77 | msg.msg_control = msgbuf; |
| 78 | msg.msg_controllen = sizeof msgbuf; |
| 79 | |
| 80 | cmsg = CMSG_FIRSTHDR(&msg); |
| 81 | |
| 82 | cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); |
| 83 | cmsg->cmsg_level = SOL_SOCKET; |
| 84 | cmsg->cmsg_type = SCM_RIGHTS; |
| 85 | |
| 86 | cmsg_payload = (int *)CMSG_DATA(cmsg); |
| 87 | cmsg_payload[0] = STDIN_FILENO; |
| 88 | cmsg_payload[1] = STDOUT_FILENO; |
| 89 | cmsg_payload[2] = STDERR_FILENO; |
| 90 | } |
| 91 | |
| 92 | do { |
| 93 | ret = sendmsg(fd, &msg, MSG_NOSIGNAL); |
| 94 | } while (ret < 0 && errno == EINTR); |
| 95 | |
| 96 | if (ret < 0) { |
| 97 | return -1; |
| 98 | } |
| 99 | |
| 100 | // Only send the fd's once |
| 101 | msg.msg_control = NULL; |
| 102 | msg.msg_controllen = 0; |
| 103 | |
| 104 | // replace any newlines with spaces and send the args |
| 105 | for (i = 0; i < argc; i++) { |
| 106 | char *tofree = NULL; |
| 107 | const char *toprint; |
| 108 | |
| 109 | toprint = argv[i]; |
| 110 | |
| 111 | if (strchr(toprint, '\n') != NULL) { |
| 112 | tofree = strdup(toprint); |
| 113 | toprint = tofree; |
| 114 | replace_nl(tofree); |
| 115 | } |
| 116 | |
| 117 | ivs[0].iov_base = (char *)toprint; |
| 118 | ivs[0].iov_len = strlen(toprint); |
| 119 | ivs[1].iov_base = (char *)newline_string; |
| 120 | ivs[1].iov_len = 1; |
| 121 | |
| 122 | msg.msg_iovlen = 2; |
| 123 | |
| 124 | do { |
| 125 | ret = sendmsg(fd, &msg, MSG_NOSIGNAL); |
| 126 | } while (ret < 0 && errno == EINTR); |
| 127 | |
| 128 | if (tofree != NULL) { |
| 129 | free(tofree); |
| 130 | } |
| 131 | |
| 132 | if (ret < 0) { |
| 133 | return -1; |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // Read the pid, as a 4-byte network-order integer |
| 138 | |
| 139 | ivs[0].iov_base = &pid; |
| 140 | ivs[0].iov_len = sizeof(pid); |
| 141 | msg.msg_iovlen = 1; |
| 142 | |
| 143 | do { |
| 144 | do { |
| 145 | ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL); |
| 146 | } while (ret < 0 && errno == EINTR); |
| 147 | |
| 148 | if (ret < 0) { |
| 149 | return -1; |
| 150 | } |
| 151 | |
| 152 | ivs[0].iov_len -= ret; |
| 153 | ivs[0].iov_base += ret; |
| 154 | } while (ivs[0].iov_len > 0); |
| 155 | |
| 156 | pid = ntohl(pid); |
| 157 | |
| 158 | return pid; |
| 159 | #endif /* HAVE_ANDROID_OS */ |
| 160 | } |
| 161 | |
| 162 | int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)) |
| 163 | { |
| 164 | int fd; |
| 165 | int pid; |
| 166 | int err; |
| 167 | const char *newargv[argc + 1]; |
| 168 | |
| 169 | fd = socket_local_client(ZYGOTE_SOCKET, |
| 170 | ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL); |
| 171 | |
| 172 | if (fd < 0) { |
| 173 | return -1; |
| 174 | } |
| 175 | |
| 176 | // The command socket is passed to the peer as close-on-exec |
| 177 | // and will close when the peer dies |
| 178 | newargv[0] = "--peer-wait"; |
| 179 | memcpy(newargv + 1, argv, argc * sizeof(*argv)); |
| 180 | |
| 181 | pid = send_request(fd, 1, argc + 1, newargv); |
| 182 | |
| 183 | if (pid > 0 && post_run_func != NULL) { |
| 184 | post_run_func(pid); |
| 185 | } |
| 186 | |
| 187 | // Wait for socket to close |
| 188 | do { |
| 189 | int dummy; |
| 190 | err = read(fd, &dummy, sizeof(dummy)); |
| 191 | } while ((err < 0 && errno == EINTR) || err != 0); |
| 192 | |
| 193 | do { |
| 194 | err = close(fd); |
| 195 | } while (err < 0 && errno == EINTR); |
| 196 | |
| 197 | return 0; |
| 198 | } |
| 199 | |
| 200 | /** |
| 201 | * Spawns a new dalvik instance via the Zygote process. The non-zygote |
| 202 | * arguments are passed to com.android.internal.os.RuntimeInit(). The |
| 203 | * first non-option argument should be a class name in the system class path. |
| 204 | * |
| 205 | * The arg list may start with zygote params such as --set-uid. |
| 206 | * |
| 207 | * If sendStdio is non-zero, the current process's stdio file descriptors |
| 208 | * will be sent and inherited by the spawned process. |
| 209 | * |
| 210 | * The pid of the child process is returned, or -1 if an error was |
| 211 | * encountered. |
| 212 | * |
| 213 | * zygote_run_oneshot waits up to ZYGOTE_RETRY_COUNT * |
| 214 | * ZYGOTE_RETRY_MILLIS for the zygote socket to be available. |
| 215 | */ |
| 216 | int zygote_run_oneshot(int sendStdio, int argc, const char **argv) |
| 217 | { |
| 218 | int fd = -1; |
| 219 | int err; |
| 220 | int i; |
| 221 | int retries; |
| 222 | int pid; |
| 223 | const char **newargv = argv; |
| 224 | const int newargc = argc; |
| 225 | |
| 226 | for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) { |
| 227 | if (retries > 0) { |
| 228 | struct timespec ts; |
| 229 | |
| 230 | memset(&ts, 0, sizeof(ts)); |
| 231 | ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000; |
| 232 | |
| 233 | do { |
| 234 | err = nanosleep (&ts, &ts); |
| 235 | } while (err < 0 && errno == EINTR); |
| 236 | } |
| 237 | fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL, |
| 238 | ANDROID_SOCKET_NAMESPACE_RESERVED); |
| 239 | } |
| 240 | |
| 241 | if (fd < 0) { |
| 242 | return -1; |
| 243 | } |
| 244 | |
| 245 | pid = send_request(fd, 0, newargc, newargv); |
| 246 | |
| 247 | do { |
| 248 | err = close(fd); |
| 249 | } while (err < 0 && errno == EINTR); |
| 250 | |
| 251 | return pid; |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Replaces all occurrances of newline with space. |
| 256 | */ |
| 257 | static void replace_nl(char *str) |
| 258 | { |
| 259 | for(; *str; str++) { |
| 260 | if (*str == '\n') { |
| 261 | *str = ' '; |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | |
| 267 | |