268 lines
6.4 KiB
C
268 lines
6.4 KiB
C
|
/*
|
||
|
* 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 = ' ';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|