cutils: first pass at cleaning up legacy/obsolete code in cutils

Removed unused code and moved libraries with single clients
near their respective users.

Change-Id: I65f90f8659f27bd0f44ca5ddf33da2bce14674c1
Signed-off-by: Dima Zavin <dima@android.com>
This commit is contained in:
Dima Zavin 2013-05-07 00:05:53 -07:00
parent 69e9b17fa1
commit e00a12bf8a
17 changed files with 1 additions and 3356 deletions

View File

@ -1,103 +0,0 @@
/*
* Copyright 2009, 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.
*/
/* Helper to perform abortable blocking operations on a socket:
* asocket_connect()
* asocket_accept()
* asocket_read()
* asocket_write()
* These calls are similar to the regular syscalls, but can be aborted with:
* asocket_abort()
*
* Calling close() on a regular POSIX socket does not abort blocked syscalls on
* that socket in other threads.
*
* After calling asocket_abort() the socket cannot be reused.
*
* Call asocket_destory() *after* all threads have finished with the socket to
* finish closing the socket and free the asocket structure.
*
* The helper is implemented by setting the socket non-blocking to initiate
* syscalls connect(), accept(), read(), write(), then using a blocking poll()
* on both the primary socket and a local pipe. This makes the poll() abortable
* by writing a byte to the local pipe in asocket_abort().
*
* asocket_create() sets the fd to non-blocking mode. It must not be changed to
* blocking mode.
*
* Using asocket will triple the number of file descriptors required per
* socket, due to the local pipe. It may be possible to use a global pipe per
* process rather than per socket, but we have not been able to come up with a
* race-free implementation yet.
*
* All functions except asocket_init() and asocket_destroy() are thread safe.
*/
#include <stdlib.h>
#include <sys/socket.h>
#ifndef __CUTILS_ABORT_SOCKET_H__
#define __CUTILS_ABORT_SOCKET_H__
#ifdef __cplusplus
extern "C" {
#endif
struct asocket {
int fd; /* primary socket fd */
int abort_fd[2]; /* pipe used to abort */
};
/* Create an asocket from fd.
* Sets the socket to non-blocking mode.
* Returns NULL on error with errno set.
*/
struct asocket *asocket_init(int fd);
/* Blocking socket I/O with timeout.
* Calling asocket_abort() from another thread will cause each of these
* functions to immediately return with value -1 and errno ECANCELED.
* timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
* with errno ETIMEDOUT.
* EINTR is handled in-call.
* Other semantics are identical to the regular syscalls.
*/
int asocket_connect(struct asocket *s, const struct sockaddr *addr,
socklen_t addrlen, int timeout);
int asocket_accept(struct asocket *s, struct sockaddr *addr,
socklen_t *addrlen, int timeout);
int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
int asocket_write(struct asocket *s, const void *buf, size_t count,
int timeout);
/* Abort above calls and shutdown socket.
* Further I/O operations on this socket will immediately fail after this call.
* asocket_destroy() should be used to release resources once all threads
* have returned from blocking calls on the socket.
*/
void asocket_abort(struct asocket *s);
/* Close socket and free asocket structure.
* Must not be called until all calls on this structure have completed.
*/
void asocket_destroy(struct asocket *s);
#ifdef __cplusplus
}
#endif
#endif //__CUTILS_ABORT_SOCKET__H__

View File

@ -1,67 +0,0 @@
/*
* 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.
*/
/**
* A pointer array which intelligently expands its capacity ad needed.
*/
#ifndef __ARRAY_H
#define __ARRAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/** An array. */
typedef struct Array Array;
/** Constructs a new array. Returns NULL if we ran out of memory. */
Array* arrayCreate();
/** Frees an array. Does not free elements themselves. */
void arrayFree(Array* array);
/** Adds a pointer. Returns 0 is successful, < 0 otherwise. */
int arrayAdd(Array* array, void* pointer);
/** Gets the pointer at the specified index. */
void* arrayGet(Array* array, int index);
/** Removes the pointer at the given index and returns it. */
void* arrayRemove(Array* array, int index);
/** Sets pointer at the given index. Returns old pointer. */
void* arraySet(Array* array, int index, void* pointer);
/** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */
int arraySetSize(Array* array, int size);
/** Returns the size of the given array. */
int arraySize(Array* array);
/**
* Returns a pointer to a C-style array which will be valid until this array
* changes.
*/
const void** arrayUnwrap(Array* array);
#ifdef __cplusplus
}
#endif
#endif /* __ARRAY_H */

View File

@ -1,124 +0,0 @@
/*
* 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.
*/
/**
* IPC messaging library.
*/
#ifndef __MQ_H
#define __MQ_H
#ifdef __cplusplus
extern "C" {
#endif
/** A message. */
typedef struct MqMessage MqMessage;
/** A destination to which messages can be sent. */
typedef struct MqDestination MqDestination;
/* Array of bytes. */
typedef struct MqBytes MqBytes;
/**
* Hears messages.
*
* @param destination to which the message was sent
* @param message the message to hear
*/
typedef void MqMessageListener(MqDestination* destination, MqMessage* message);
/**
* Hears a destination close.
*
* @param destination that closed
*/
typedef void MqCloseListener(MqDestination* destination);
/** Message functions. */
/**
* Creates a new Message.
*
* @param header as defined by user
* @param body as defined by user
* @param replyTo destination to which replies should be sent, NULL if none
*/
MqMessage* mqCreateMessage(MqBytes header, MqBytes body,
MqDestination* replyTo);
/** Sends a message to a destination. */
void mqSendMessage(MqMessage* message, MqDestination* destination);
/** Destination functions. */
/**
* Creates a new destination. Acquires a reference implicitly.
*
* @param messageListener function to call when a message is recieved
* @param closeListener function to call when the destination closes
* @param userData user-specific data to associate with the destination.
* Retrieve using mqGetDestinationUserData().
*/
MqDestination* mqCreateDestination(MqMessageListener* messageListener,
MqCloseListener* closeListener, void* userData);
/**
* Gets user data which was associated with the given destination at
* construction time.
*
* It is only valid to call this function in the same process that the
* given destination was created in.
* This function returns a null pointer if you call it on a destination
* created in a remote process.
*/
void* mqGetUserData(MqDestination* destination);
/**
* Returns 1 if the destination was created in this process, or 0 if
* the destination was created in a different process, in which case you have
* a remote stub.
*/
int mqIsDestinationLocal(MqDestination* destination);
/**
* Increments the destination's reference count.
*/
void mqKeepDestination(MqDesintation* destination);
/**
* Decrements the destination's reference count.
*/
void mqFreeDestination(MqDestination* desintation);
/** Registry API. */
/**
* Gets the destination bound to a name.
*/
MqDestination* mqGetDestination(char* name);
/**
* Binds a destination to a name.
*/
void mqPutDestination(char* name, MqDestination* desintation);
#ifdef __cplusplus
}
#endif
#endif /* __MQ_H */

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2012 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.
*/
/*
* Provides a portable version of qsort_r, called qsort_r_compat, which is a
* reentrant variant of qsort that passes a user data pointer to its comparator.
* This implementation follows the BSD parameter convention.
*/
#ifndef _LIBS_CUTILS_QSORT_R_COMPAT_H
#define _LIBS_CUTILS_QSORT_R_COMPAT_H
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
int (*compar)(void*, const void* , const void* ));
#ifdef __cplusplus
}
#endif
#endif // _LIBS_CUTILS_QSORT_R_COMPAT_H

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2006 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.
*/
/*
* A simple utility for reading fixed records out of a stream fd
*/
#ifndef _CUTILS_RECORD_STREAM_H
#define _CUTILS_RECORD_STREAM_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct RecordStream RecordStream;
extern RecordStream *record_stream_new(int fd, size_t maxRecordLen);
extern void record_stream_free(RecordStream *p_rs);
extern int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
size_t *p_outRecordLen);
#ifdef __cplusplus
}
#endif
#endif /*_CUTILS_RECORD_STREAM_H*/

View File

@ -1,130 +0,0 @@
/*
* 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.
*/
/**
* Framework for multiplexing I/O. A selector manages a set of file
* descriptors and calls out to user-provided callback functions to read and
* write data and handle errors.
*/
#ifndef __SELECTOR_H
#define __SELECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
/**
* Manages SelectableFds and invokes their callbacks at appropriate times.
*/
typedef struct Selector Selector;
/**
* A selectable descriptor. Contains callbacks which the selector can invoke
* before calling select(), when the descriptor is readable or writable, and
* when the descriptor contains out-of-band data. Simply set a callback to
* NULL if you're not interested in that particular event.
*
* A selectable descriptor can indicate that it needs to be removed from the
* selector by setting the 'remove' flag. The selector will remove the
* descriptor at a later time and invoke the onRemove() callback.
*
* SelectableFd fields should only be modified from the selector loop.
*/
typedef struct SelectableFd SelectableFd;
struct SelectableFd {
/** The file descriptor itself. */
int fd;
/** Pointer to user-specific data. Can be NULL. */
void* data;
/**
* Set this flag when you no longer wish to be selected. The selector
* will invoke onRemove() when the descriptor is actually removed.
*/
bool remove;
/**
* Invoked by the selector before calling select. You can set up other
* callbacks from here as necessary.
*/
void (*beforeSelect)(SelectableFd* self);
/**
* Invoked by the selector when the descriptor has data available. Set to
* NULL to indicate that you're not interested in reading.
*/
void (*onReadable)(SelectableFd* self);
/**
* Invoked by the selector when the descriptor can accept data. Set to
* NULL to indicate that you're not interested in writing.
*/
void (*onWritable)(SelectableFd* self);
/**
* Invoked by the selector when out-of-band (OOB) data is available. Set to
* NULL to indicate that you're not interested in OOB data.
*/
void (*onExcept)(SelectableFd* self);
/**
* Invoked by the selector after the descriptor is removed from the
* selector but before the selector frees the SelectableFd memory.
*/
void (*onRemove)(SelectableFd* self);
/**
* The selector which selected this fd. Set by the selector itself.
*/
Selector* selector;
};
/**
* Creates a new selector.
*/
Selector* selectorCreate(void);
/**
* Creates a new selectable fd, adds it to the given selector and returns a
* pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL
* by default.
*
* The selectable fd should only be modified from the selector loop thread.
*/
SelectableFd* selectorAdd(Selector* selector, int fd);
/**
* Wakes up the selector even though no I/O events occurred. Use this
* to indicate that you're ready to write to a descriptor.
*/
void selectorWakeUp(Selector* selector);
/**
* Loops continuously selecting file descriptors and firing events.
* Does not return.
*/
void selectorLoop(Selector* selector);
#ifdef __cplusplus
}
#endif
#endif /* __SELECTOR_H */

View File

@ -1,31 +0,0 @@
/*
* 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.
*/
#ifndef __CUTILS_ZYGOTE_H
#define __CUTILS_ZYGOTE_H
#ifdef __cplusplus
extern "C" {
#endif
int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
int zygote_run(int argc, const char **argv);
#ifdef __cplusplus
}
#endif
#endif /* __CUTILS_ZYGOTE_H */

View File

@ -24,11 +24,9 @@ endif
hostSmpFlag := -DANDROID_SMP=0
commonSources := \
array.c \
hashmap.c \
atomic.c.arm \
native_handle.c \
buffer.c \
socket_inaddr_any_server.c \
socket_local_client.c \
socket_local_server.c \
@ -43,10 +41,8 @@ commonSources := \
open_memstream.c \
strdup16to8.c \
strdup8to16.c \
record_stream.c \
process_name.c \
properties.c \
qsort_r_compat.c \
threads.c \
sched_policy.c \
iosched_policy.c \
@ -74,11 +70,8 @@ ifeq ($(WINDOWS_HOST_ONLY),1)
uio.c
else
commonSources += \
abort_socket.c \
fs.c \
selector.c \
multiuser.c \
zygote.c
multiuser.c
endif
@ -118,7 +111,6 @@ LOCAL_SRC_FILES := $(commonSources) \
ashmem-dev.c \
debugger.c \
klog.c \
mq.c \
partition_utils.c \
qtaguid.c \
trace.c \

View File

@ -1,293 +0,0 @@
/*
* Copyright 2009, 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.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include "cutils/abort_socket.h"
struct asocket *asocket_init(int fd) {
int abort_fd[2];
int flags;
struct asocket *s;
/* set primary socket to non-blocking */
flags = fcntl(fd, F_GETFL);
if (flags == -1)
return NULL;
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
return NULL;
/* create pipe with non-blocking write, so that asocket_close() cannot
block */
if (pipe(abort_fd))
return NULL;
flags = fcntl(abort_fd[1], F_GETFL);
if (flags == -1)
return NULL;
if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK))
return NULL;
s = malloc(sizeof(struct asocket));
if (!s)
return NULL;
s->fd = fd;
s->abort_fd[0] = abort_fd[0];
s->abort_fd[1] = abort_fd[1];
return s;
}
int asocket_connect(struct asocket *s, const struct sockaddr *addr,
socklen_t addrlen, int timeout) {
int ret;
do {
ret = connect(s->fd, addr, addrlen);
} while (ret && errno == EINTR);
if (ret && errno == EINPROGRESS) {
/* ready to poll() */
socklen_t retlen;
struct pollfd pfd[2];
pfd[0].fd = s->fd;
pfd[0].events = POLLOUT;
pfd[0].revents = 0;
pfd[1].fd = s->abort_fd[0];
pfd[1].events = POLLIN;
pfd[1].revents = 0;
do {
ret = poll(pfd, 2, timeout);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
return -1;
else if (ret == 0) {
/* timeout */
errno = ETIMEDOUT;
return -1;
}
if (pfd[1].revents) {
/* abort due to asocket_abort() */
errno = ECANCELED;
return -1;
}
if (pfd[0].revents) {
if (pfd[0].revents & POLLOUT) {
/* connect call complete, read return code */
retlen = sizeof(ret);
if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen))
return -1;
/* got connect() return code */
if (ret) {
errno = ret;
}
} else {
/* some error event on this fd */
errno = ECONNABORTED;
return -1;
}
}
}
return ret;
}
int asocket_accept(struct asocket *s, struct sockaddr *addr,
socklen_t *addrlen, int timeout) {
int ret;
struct pollfd pfd[2];
pfd[0].fd = s->fd;
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = s->abort_fd[0];
pfd[1].events = POLLIN;
pfd[1].revents = 0;
do {
ret = poll(pfd, 2, timeout);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
return -1;
else if (ret == 0) {
/* timeout */
errno = ETIMEDOUT;
return -1;
}
if (pfd[1].revents) {
/* abort due to asocket_abort() */
errno = ECANCELED;
return -1;
}
if (pfd[0].revents) {
if (pfd[0].revents & POLLIN) {
/* ready to accept() without blocking */
do {
ret = accept(s->fd, addr, addrlen);
} while (ret < 0 && errno == EINTR);
} else {
/* some error event on this fd */
errno = ECONNABORTED;
return -1;
}
}
return ret;
}
int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) {
int ret;
struct pollfd pfd[2];
pfd[0].fd = s->fd;
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = s->abort_fd[0];
pfd[1].events = POLLIN;
pfd[1].revents = 0;
do {
ret = poll(pfd, 2, timeout);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
return -1;
else if (ret == 0) {
/* timeout */
errno = ETIMEDOUT;
return -1;
}
if (pfd[1].revents) {
/* abort due to asocket_abort() */
errno = ECANCELED;
return -1;
}
if (pfd[0].revents) {
if (pfd[0].revents & POLLIN) {
/* ready to read() without blocking */
do {
ret = read(s->fd, buf, count);
} while (ret < 0 && errno == EINTR);
} else {
/* some error event on this fd */
errno = ECONNABORTED;
return -1;
}
}
return ret;
}
int asocket_write(struct asocket *s, const void *buf, size_t count,
int timeout) {
int ret;
struct pollfd pfd[2];
pfd[0].fd = s->fd;
pfd[0].events = POLLOUT;
pfd[0].revents = 0;
pfd[1].fd = s->abort_fd[0];
pfd[1].events = POLLIN;
pfd[1].revents = 0;
do {
ret = poll(pfd, 2, timeout);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
return -1;
else if (ret == 0) {
/* timeout */
errno = ETIMEDOUT;
return -1;
}
if (pfd[1].revents) {
/* abort due to asocket_abort() */
errno = ECANCELED;
return -1;
}
if (pfd[0].revents) {
if (pfd[0].revents & POLLOUT) {
/* ready to write() without blocking */
do {
ret = write(s->fd, buf, count);
} while (ret < 0 && errno == EINTR);
} else {
/* some error event on this fd */
errno = ECONNABORTED;
return -1;
}
}
return ret;
}
void asocket_abort(struct asocket *s) {
int ret;
char buf = 0;
/* Prevent further use of fd, without yet releasing the fd */
shutdown(s->fd, SHUT_RDWR);
/* wake up calls blocked at poll() */
do {
ret = write(s->abort_fd[1], &buf, 1);
} while (ret < 0 && errno == EINTR);
}
void asocket_destroy(struct asocket *s) {
struct asocket s_copy = *s;
/* Clients should *not* be using these fd's after calling
asocket_destroy(), but in case they do, set to -1 so they cannot use a
stale fd */
s->fd = -1;
s->abort_fd[0] = -1;
s->abort_fd[1] = -1;
/* Call asocket_abort() in case there are still threads blocked on this
socket. Clients should not rely on this behavior - it is racy because we
are about to close() these sockets - clients should instead make sure
all threads are done with the socket before calling asocket_destory().
*/
asocket_abort(&s_copy);
/* enough safety checks, close and release memory */
close(s_copy.abort_fd[1]);
close(s_copy.abort_fd[0]);
close(s_copy.fd);
free(s);
}

View File

@ -1,170 +0,0 @@
/*
* 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.
*/
#include <cutils/array.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define INITIAL_CAPACITY (4)
#define MAX_CAPACITY ((int)(UINT_MAX/sizeof(void*)))
struct Array {
void** contents;
int size;
int capacity;
};
Array* arrayCreate() {
return calloc(1, sizeof(struct Array));
}
void arrayFree(Array* array) {
assert(array != NULL);
// Free internal array.
free(array->contents);
// Free the Array itself.
free(array);
}
/** Returns 0 if successful, < 0 otherwise.. */
static int ensureCapacity(Array* array, int capacity) {
int oldCapacity = array->capacity;
if (capacity > oldCapacity) {
int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity;
// Ensure we're not doing something nasty
if (capacity > MAX_CAPACITY)
return -1;
// Keep doubling capacity until we surpass necessary capacity.
while (newCapacity < capacity) {
int newCap = newCapacity*2;
// Handle integer overflows
if (newCap < newCapacity || newCap > MAX_CAPACITY) {
newCap = MAX_CAPACITY;
}
newCapacity = newCap;
}
// Should not happen, but better be safe than sorry
if (newCapacity < 0 || newCapacity > MAX_CAPACITY)
return -1;
void** newContents;
if (array->contents == NULL) {
// Allocate new array.
newContents = malloc(newCapacity * sizeof(void*));
if (newContents == NULL) {
return -1;
}
} else {
// Expand existing array.
newContents = realloc(array->contents, sizeof(void*) * newCapacity);
if (newContents == NULL) {
return -1;
}
}
array->capacity = newCapacity;
array->contents = newContents;
}
return 0;
}
int arrayAdd(Array* array, void* pointer) {
assert(array != NULL);
int size = array->size;
int result = ensureCapacity(array, size + 1);
if (result < 0) {
return result;
}
array->contents[size] = pointer;
array->size++;
return 0;
}
static inline void checkBounds(Array* array, int index) {
assert(array != NULL);
assert(index < array->size);
assert(index >= 0);
}
void* arrayGet(Array* array, int index) {
checkBounds(array, index);
return array->contents[index];
}
void* arrayRemove(Array* array, int index) {
checkBounds(array, index);
void* pointer = array->contents[index];
int newSize = array->size - 1;
// Shift entries left.
if (index != newSize) {
memmove(array->contents + index, array->contents + index + 1,
(sizeof(void*)) * (newSize - index));
}
array->size = newSize;
return pointer;
}
void* arraySet(Array* array, int index, void* pointer) {
checkBounds(array, index);
void* old = array->contents[index];
array->contents[index] = pointer;
return old;
}
int arraySetSize(Array* array, int newSize) {
assert(array != NULL);
assert(newSize >= 0);
int oldSize = array->size;
if (newSize > oldSize) {
// Expand.
int result = ensureCapacity(array, newSize);
if (result < 0) {
return result;
}
// Zero out new entries.
memset(array->contents + sizeof(void*) * oldSize, 0,
sizeof(void*) * (newSize - oldSize));
}
array->size = newSize;
return 0;
}
int arraySize(Array* array) {
assert(array != NULL);
return array->size;
}
const void** arrayUnwrap(Array* array) {
return (const void**)array->contents;
}

View File

@ -1,116 +0,0 @@
/*
* 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 "buffer"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "buffer.h"
#include "loghack.h"
Buffer* bufferCreate(size_t capacity) {
Buffer* buffer = malloc(sizeof(Buffer));
if (buffer == NULL) {
return NULL;
}
buffer->capacity = capacity;
buffer->expected = 0;
buffer->data = malloc(capacity);
if (buffer->data == NULL) {
free(buffer);
return NULL;
}
return buffer;
}
void bufferFree(Buffer* buffer) {
free(buffer->data);
free(buffer);
}
Buffer* bufferWrap(char* data, size_t capacity, size_t size) {
Buffer* buffer = malloc(sizeof(Buffer));
if (buffer == NULL) {
return NULL;
}
buffer->data = data;
buffer->capacity = capacity;
buffer->size = size;
buffer->expected = 0;
return buffer;
}
int bufferPrepareForRead(Buffer* buffer, size_t expected) {
if (expected > buffer->capacity) {
// Expand buffer.
char* expanded = realloc(buffer->data, expected);
if (expanded == NULL) {
errno = ENOMEM;
return -1;
}
buffer->capacity = expected;
buffer->data = expanded;
}
buffer->size = 0;
buffer->expected = expected;
return 0;
}
ssize_t bufferRead(Buffer* buffer, int fd) {
assert(buffer->size < buffer->expected);
ssize_t bytesRead = read(fd,
buffer->data + buffer->size,
buffer->expected - buffer->size);
if (bytesRead > 0) {
buffer->size += bytesRead;
return buffer->size;
}
return bytesRead;
}
void bufferPrepareForWrite(Buffer* buffer) {
buffer->remaining = buffer->size;
}
ssize_t bufferWrite(Buffer* buffer, int fd) {
assert(buffer->remaining > 0);
assert(buffer->remaining <= buffer->size);
ssize_t bytesWritten = write(fd,
buffer->data + buffer->size - buffer->remaining,
buffer->remaining);
if (bytesWritten >= 0) {
buffer->remaining -= bytesWritten;
ALOGD("Buffer bytes written: %d", (int) bytesWritten);
ALOGD("Buffer size: %d", (int) buffer->size);
ALOGD("Buffer remaining: %d", (int) buffer->remaining);
return buffer->remaining;
}
return bytesWritten;
}

View File

@ -1,112 +0,0 @@
/*
* 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.
*/
/**
* Byte buffer utilities.
*/
#ifndef __BUFFER_H
#define __BUFFER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/**
* Byte buffer of known size. Keeps track of how much data has been read
* into or written out of the buffer.
*/
typedef struct {
/** Buffered data. */
char* data;
union {
/** For reading. # of bytes we expect. */
size_t expected;
/** For writing. # of bytes to write. */
size_t remaining;
};
/** Actual # of bytes in the buffer. */
size_t size;
/** Amount of memory allocated for this buffer. */
size_t capacity;
} Buffer;
/**
* Returns true if all data has been read into the buffer.
*/
#define bufferReadComplete(buffer) (buffer->expected == buffer->size)
/**
* Returns true if the buffer has been completely written.
*/
#define bufferWriteComplete(buffer) (buffer->remaining == 0)
/**
* Creates a new buffer with the given initial capacity.
*/
Buffer* bufferCreate(size_t initialCapacity);
/**
* Wraps an existing byte array.
*/
Buffer* bufferWrap(char* data, size_t capacity, size_t size);
/**
* Frees and its data.
*/
void bufferFree(Buffer* buffer);
/**
* Prepares buffer to read 'expected' number of bytes. Expands capacity if
* necessary. Returns 0 if successful or -1 if an error occurs allocating
* memory.
*/
int bufferPrepareForRead(Buffer* buffer, size_t expected);
/**
* Reads some data into a buffer. Returns -1 in case of an error and sets
* errno (see read()). Returns 0 for EOF. Updates buffer->size and returns
* the new size after a succesful read.
*
* Precondition: buffer->size < buffer->expected
*/
ssize_t bufferRead(Buffer* buffer, int fd);
/**
* Prepares a buffer to be written out.
*/
void bufferPrepareForWrite(Buffer* buffer);
/**
* Writes data from buffer to the given fd. Returns -1 and sets errno in case
* of an error. Updates buffer->remaining and returns the number of remaining
* bytes to be written after a successful write.
*
* Precondition: buffer->remaining > 0
*/
ssize_t bufferWrite(Buffer* buffer, int fd);
#ifdef __cplusplus
}
#endif
#endif /* __BUFFER_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,84 +0,0 @@
/*
* Copyright (C) 2012 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.
*/
#include <stdlib.h>
#include <cutils/qsort_r_compat.h>
#if HAVE_BSD_QSORT_R
/*
* BSD qsort_r parameter order is as we have defined here.
*/
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
int (*compar)(void*, const void* , const void*)) {
qsort_r(base, nel, width, thunk, compar);
}
#elif HAVE_GNU_QSORT_R
/*
* GNU qsort_r parameter order places the thunk parameter last.
*/
struct compar_data {
void* thunk;
int (*compar)(void*, const void* , const void*);
};
static int compar_wrapper(const void* a, const void* b, void* data) {
struct compar_data* compar_data = (struct compar_data*)data;
return compar_data->compar(compar_data->thunk, a, b);
}
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
int (*compar)(void*, const void* , const void*)) {
struct compar_data compar_data;
compar_data.thunk = thunk;
compar_data.compar = compar;
qsort_r(base, nel, width, compar_wrapper, &compar_data);
}
#else
/*
* Emulate qsort_r using thread local storage to access the thunk data.
*/
#include <cutils/threads.h>
static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
struct compar_data {
void* thunk;
int (*compar)(void*, const void* , const void*);
};
static int compar_wrapper(const void* a, const void* b) {
struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
return compar_data->compar(compar_data->thunk, a, b);
}
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
int (*compar)(void*, const void* , const void*)) {
struct compar_data compar_data;
compar_data.thunk = thunk;
compar_data.compar = compar;
thread_store_set(&compar_data_key, &compar_data, NULL);
qsort(base, nel, width, compar_wrapper);
}
#endif

View File

@ -1,186 +0,0 @@
/* libs/cutils/record_stream.c
**
** Copyright 2006, 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.
*/
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <cutils/record_stream.h>
#include <string.h>
#include <stdint.h>
#ifdef HAVE_WINSOCK
#include <winsock2.h> /* for ntohl */
#else
#include <netinet/in.h>
#endif
#define HEADER_SIZE 4
struct RecordStream {
int fd;
size_t maxRecordLen;
unsigned char *buffer;
unsigned char *unconsumed;
unsigned char *read_end;
unsigned char *buffer_end;
};
extern RecordStream *record_stream_new(int fd, size_t maxRecordLen)
{
RecordStream *ret;
assert (maxRecordLen <= 0xffff);
ret = (RecordStream *)calloc(1, sizeof(RecordStream));
ret->fd = fd;
ret->maxRecordLen = maxRecordLen;
ret->buffer = (unsigned char *)malloc (maxRecordLen + HEADER_SIZE);
ret->unconsumed = ret->buffer;
ret->read_end = ret->buffer;
ret->buffer_end = ret->buffer + maxRecordLen + HEADER_SIZE;
return ret;
}
extern void record_stream_free(RecordStream *rs)
{
free(rs->buffer);
free(rs);
}
/* returns NULL; if there isn't a full record in the buffer */
static unsigned char * getEndOfRecord (unsigned char *p_begin,
unsigned char *p_end)
{
size_t len;
unsigned char * p_ret;
if (p_end < p_begin + HEADER_SIZE) {
return NULL;
}
//First four bytes are length
len = ntohl(*((uint32_t *)p_begin));
p_ret = p_begin + HEADER_SIZE + len;
if (p_end < p_ret) {
return NULL;
}
return p_ret;
}
static void *getNextRecord (RecordStream *p_rs, size_t *p_outRecordLen)
{
unsigned char *record_start, *record_end;
record_end = getEndOfRecord (p_rs->unconsumed, p_rs->read_end);
if (record_end != NULL) {
/* one full line in the buffer */
record_start = p_rs->unconsumed + HEADER_SIZE;
p_rs->unconsumed = record_end;
*p_outRecordLen = record_end - record_start;
return record_start;
}
return NULL;
}
/**
* Reads the next record from stream fd
* Records are prefixed by a 16-bit big endian length value
* Records may not be larger than maxRecordLen
*
* Doesn't guard against EINTR
*
* p_outRecord and p_outRecordLen may not be NULL
*
* Return 0 on success, -1 on fail
* Returns 0 with *p_outRecord set to NULL on end of stream
* Returns -1 / errno = EAGAIN if it needs to read again
*/
int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
size_t *p_outRecordLen)
{
void *ret;
ssize_t countRead;
/* is there one record already in the buffer? */
ret = getNextRecord (p_rs, p_outRecordLen);
if (ret != NULL) {
*p_outRecord = ret;
return 0;
}
// if the buffer is full and we don't have a full record
if (p_rs->unconsumed == p_rs->buffer
&& p_rs->read_end == p_rs->buffer_end
) {
// this should never happen
//ALOGE("max record length exceeded\n");
assert (0);
errno = EFBIG;
return -1;
}
if (p_rs->unconsumed != p_rs->buffer) {
// move remainder to the beginning of the buffer
size_t toMove;
toMove = p_rs->read_end - p_rs->unconsumed;
if (toMove) {
memmove(p_rs->buffer, p_rs->unconsumed, toMove);
}
p_rs->read_end = p_rs->buffer + toMove;
p_rs->unconsumed = p_rs->buffer;
}
countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end);
if (countRead <= 0) {
/* note: end-of-stream drops through here too */
*p_outRecord = NULL;
return countRead;
}
p_rs->read_end += countRead;
ret = getNextRecord (p_rs, p_outRecordLen);
if (ret == NULL) {
/* not enough of a buffer to for a whole command */
errno = EAGAIN;
return -1;
}
*p_outRecord = ret;
return 0;
}

View File

@ -1,263 +0,0 @@
/*
* 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 "selector"
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <cutils/array.h>
#include <cutils/selector.h>
#include "loghack.h"
struct Selector {
Array* selectableFds;
bool looping;
fd_set readFds;
fd_set writeFds;
fd_set exceptFds;
int maxFd;
int wakeupPipe[2];
SelectableFd* wakeupFd;
bool inSelect;
pthread_mutex_t inSelectLock;
};
/** Reads and ignores wake up data. */
static void eatWakeupData(SelectableFd* wakeupFd) {
static char garbage[64];
if (read(wakeupFd->fd, garbage, sizeof(garbage)) < 0) {
if (errno == EINTR) {
ALOGI("read() interrupted.");
} else {
LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
}
}
}
static void setInSelect(Selector* selector, bool inSelect) {
pthread_mutex_lock(&selector->inSelectLock);
selector->inSelect = inSelect;
pthread_mutex_unlock(&selector->inSelectLock);
}
static bool isInSelect(Selector* selector) {
pthread_mutex_lock(&selector->inSelectLock);
bool inSelect = selector->inSelect;
pthread_mutex_unlock(&selector->inSelectLock);
return inSelect;
}
void selectorWakeUp(Selector* selector) {
if (!isInSelect(selector)) {
// We only need to write wake-up data if we're blocked in select().
return;
}
static char garbage[1];
if (write(selector->wakeupPipe[1], garbage, sizeof(garbage)) < 0) {
if (errno == EINTR) {
ALOGI("read() interrupted.");
} else {
LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
}
}
}
Selector* selectorCreate(void) {
Selector* selector = calloc(1, sizeof(Selector));
if (selector == NULL) {
LOG_ALWAYS_FATAL("malloc() error.");
}
selector->selectableFds = arrayCreate();
// Set up wake-up pipe.
if (pipe(selector->wakeupPipe) < 0) {
LOG_ALWAYS_FATAL("pipe() error: %s", strerror(errno));
}
ALOGD("Wakeup fd: %d", selector->wakeupPipe[0]);
SelectableFd* wakeupFd = selectorAdd(selector, selector->wakeupPipe[0]);
if (wakeupFd == NULL) {
LOG_ALWAYS_FATAL("malloc() error.");
}
wakeupFd->onReadable = &eatWakeupData;
pthread_mutex_init(&selector->inSelectLock, NULL);
return selector;
}
SelectableFd* selectorAdd(Selector* selector, int fd) {
assert(selector != NULL);
SelectableFd* selectableFd = calloc(1, sizeof(SelectableFd));
if (selectableFd != NULL) {
selectableFd->selector = selector;
selectableFd->fd = fd;
arrayAdd(selector->selectableFds, selectableFd);
}
return selectableFd;
}
/**
* Adds an fd to the given set if the callback is non-null. Returns true
* if the fd was added.
*/
static inline bool maybeAdd(SelectableFd* selectableFd,
void (*callback)(SelectableFd*), fd_set* fdSet) {
if (callback != NULL) {
FD_SET(selectableFd->fd, fdSet);
return true;
}
return false;
}
/**
* Removes stale file descriptors and initializes file descriptor sets.
*/
static void prepareForSelect(Selector* selector) {
fd_set* exceptFds = &selector->exceptFds;
fd_set* readFds = &selector->readFds;
fd_set* writeFds = &selector->writeFds;
FD_ZERO(exceptFds);
FD_ZERO(readFds);
FD_ZERO(writeFds);
Array* selectableFds = selector->selectableFds;
int i = 0;
selector->maxFd = 0;
int size = arraySize(selectableFds);
while (i < size) {
SelectableFd* selectableFd = arrayGet(selectableFds, i);
if (selectableFd->remove) {
// This descriptor should be removed.
arrayRemove(selectableFds, i);
size--;
if (selectableFd->onRemove != NULL) {
selectableFd->onRemove(selectableFd);
}
free(selectableFd);
} else {
if (selectableFd->beforeSelect != NULL) {
selectableFd->beforeSelect(selectableFd);
}
bool inSet = false;
if (maybeAdd(selectableFd, selectableFd->onExcept, exceptFds)) {
ALOGD("Selecting fd %d for writing...", selectableFd->fd);
inSet = true;
}
if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
ALOGD("Selecting fd %d for reading...", selectableFd->fd);
inSet = true;
}
if (maybeAdd(selectableFd, selectableFd->onWritable, writeFds)) {
inSet = true;
}
if (inSet) {
// If the fd is in a set, check it against max.
int fd = selectableFd->fd;
if (fd > selector->maxFd) {
selector->maxFd = fd;
}
}
// Move to next descriptor.
i++;
}
}
}
/**
* Invokes a callback if the callback is non-null and the fd is in the given
* set.
*/
static inline void maybeInvoke(SelectableFd* selectableFd,
void (*callback)(SelectableFd*), fd_set* fdSet) {
if (callback != NULL && !selectableFd->remove &&
FD_ISSET(selectableFd->fd, fdSet)) {
ALOGD("Selected fd %d.", selectableFd->fd);
callback(selectableFd);
}
}
/**
* Notifies user if file descriptors are readable or writable, or if
* out-of-band data is present.
*/
static void fireEvents(Selector* selector) {
Array* selectableFds = selector->selectableFds;
int size = arraySize(selectableFds);
int i;
for (i = 0; i < size; i++) {
SelectableFd* selectableFd = arrayGet(selectableFds, i);
maybeInvoke(selectableFd, selectableFd->onExcept,
&selector->exceptFds);
maybeInvoke(selectableFd, selectableFd->onReadable,
&selector->readFds);
maybeInvoke(selectableFd, selectableFd->onWritable,
&selector->writeFds);
}
}
void selectorLoop(Selector* selector) {
// Make sure we're not already looping.
if (selector->looping) {
LOG_ALWAYS_FATAL("Already looping.");
}
selector->looping = true;
while (true) {
setInSelect(selector, true);
prepareForSelect(selector);
ALOGD("Entering select().");
// Select file descriptors.
int result = select(selector->maxFd + 1, &selector->readFds,
&selector->writeFds, &selector->exceptFds, NULL);
ALOGD("Exiting select().");
setInSelect(selector, false);
if (result == -1) {
// Abort on everything except EINTR.
if (errno == EINTR) {
ALOGI("select() interrupted.");
} else {
LOG_ALWAYS_FATAL("select() error: %s",
strerror(errno));
}
} else if (result > 0) {
fireEvents(selector);
}
}
}

View File

@ -1,229 +0,0 @@
/*
* 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
//ALOGE("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 */
}
/**
* 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 = ' ';
}
}
}