diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h deleted file mode 100644 index fbb1112fa..000000000 --- a/include/cutils/abort_socket.h +++ /dev/null @@ -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 -#include - -#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__ diff --git a/include/cutils/array.h b/include/cutils/array.h deleted file mode 100644 index c97ff34cb..000000000 --- a/include/cutils/array.h +++ /dev/null @@ -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 - -/** 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 */ diff --git a/include/cutils/mq.h b/include/cutils/mq.h deleted file mode 100644 index b27456d4f..000000000 --- a/include/cutils/mq.h +++ /dev/null @@ -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 */ diff --git a/include/cutils/qsort_r_compat.h b/include/cutils/qsort_r_compat.h deleted file mode 100644 index 479a1ab38..000000000 --- a/include/cutils/qsort_r_compat.h +++ /dev/null @@ -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 - -#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 diff --git a/include/cutils/record_stream.h b/include/cutils/record_stream.h deleted file mode 100644 index bfac87a53..000000000 --- a/include/cutils/record_stream.h +++ /dev/null @@ -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*/ - diff --git a/include/cutils/selector.h b/include/cutils/selector.h deleted file mode 100644 index dfc2a9d34..000000000 --- a/include/cutils/selector.h +++ /dev/null @@ -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 - -/** - * 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 */ diff --git a/include/cutils/zygote.h b/include/cutils/zygote.h deleted file mode 100644 index a7480d320..000000000 --- a/include/cutils/zygote.h +++ /dev/null @@ -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 */ diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 503770563..afbc758a2 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -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 \ diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c deleted file mode 100644 index 6a5e5e461..000000000 --- a/libcutils/abort_socket.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#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); -} diff --git a/libcutils/array.c b/libcutils/array.c deleted file mode 100644 index 55ec055ff..000000000 --- a/libcutils/array.c +++ /dev/null @@ -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 -#include -#include -#include -#include - -#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; -} diff --git a/libcutils/buffer.c b/libcutils/buffer.c deleted file mode 100644 index af99bd728..000000000 --- a/libcutils/buffer.c +++ /dev/null @@ -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 -#include -#include -#include - -#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; -} - diff --git a/libcutils/buffer.h b/libcutils/buffer.h deleted file mode 100644 index d8bc108ee..000000000 --- a/libcutils/buffer.h +++ /dev/null @@ -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 - -/** - * 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 */ diff --git a/libcutils/mq.c b/libcutils/mq.c deleted file mode 100644 index 6f6740ebb..000000000 --- a/libcutils/mq.c +++ /dev/null @@ -1,1357 +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 "mq" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "loghack.h" -#include "buffer.h" - -/** Number of dead peers to remember. */ -#define PEER_HISTORY (16) - -typedef struct sockaddr SocketAddress; -typedef struct sockaddr_un UnixAddress; - -/** - * Process/user/group ID. We don't use ucred directly because it's only - * available on Linux. - */ -typedef struct { - pid_t pid; - uid_t uid; - gid_t gid; -} Credentials; - -/** Listens for bytes coming from remote peers. */ -typedef void BytesListener(Credentials credentials, char* bytes, size_t size); - -/** Listens for the deaths of remote peers. */ -typedef void DeathListener(pid_t pid); - -/** Types of packets. */ -typedef enum { - /** Request for a connection to another peer. */ - CONNECTION_REQUEST, - - /** A connection to another peer. */ - CONNECTION, - - /** Reports a failed connection attempt. */ - CONNECTION_ERROR, - - /** A generic packet of bytes. */ - BYTES, -} PacketType; - -typedef enum { - /** Reading a packet header. */ - READING_HEADER, - - /** Waiting for a connection from the master. */ - ACCEPTING_CONNECTION, - - /** Reading bytes. */ - READING_BYTES, -} InputState; - -/** A packet header. */ -// TODO: Use custom headers for master->peer, peer->master, peer->peer. -typedef struct { - PacketType type; - union { - /** Packet size. Used for BYTES. */ - size_t size; - - /** Credentials. Used for CONNECTION and CONNECTION_REQUEST. */ - Credentials credentials; - }; -} Header; - -/** A packet which will be sent to a peer. */ -typedef struct OutgoingPacket OutgoingPacket; -struct OutgoingPacket { - /** Packet header. */ - Header header; - - union { - /** Connection to peer. Used with CONNECTION. */ - int socket; - - /** Buffer of bytes. Used with BYTES. */ - Buffer* bytes; - }; - - /** Frees all resources associated with this packet. */ - void (*free)(OutgoingPacket* packet); - - /** Optional context. */ - void* context; - - /** Next packet in the queue. */ - OutgoingPacket* nextPacket; -}; - -/** Represents a remote peer. */ -typedef struct PeerProxy PeerProxy; - -/** Local peer state. You typically have one peer per process. */ -typedef struct { - /** This peer's PID. */ - pid_t pid; - - /** - * Map from pid to peer proxy. The peer has a peer proxy for each remote - * peer it's connected to. - * - * Acquire mutex before use. - */ - Hashmap* peerProxies; - - /** Manages I/O. */ - Selector* selector; - - /** Used to synchronize operations with the selector thread. */ - pthread_mutex_t mutex; - - /** Is this peer the master? */ - bool master; - - /** Peer proxy for the master. */ - PeerProxy* masterProxy; - - /** Listens for packets from remote peers. */ - BytesListener* onBytes; - - /** Listens for deaths of remote peers. */ - DeathListener* onDeath; - - /** Keeps track of recently dead peers. Requires mutex. */ - pid_t deadPeers[PEER_HISTORY]; - size_t deadPeerCursor; -} Peer; - -struct PeerProxy { - /** Credentials of the remote process. */ - Credentials credentials; - - /** Keeps track of data coming in from the remote peer. */ - InputState inputState; - Buffer* inputBuffer; - PeerProxy* connecting; - - /** File descriptor for this peer. */ - SelectableFd* fd; - - /** - * Queue of packets to be written out to the remote peer. - * - * Requires mutex. - */ - // TODO: Limit queue length. - OutgoingPacket* currentPacket; - OutgoingPacket* lastPacket; - - /** Used to write outgoing header. */ - Buffer outgoingHeader; - - /** True if this is the master's proxy. */ - bool master; - - /** Reference back to the local peer. */ - Peer* peer; - - /** - * Used in master only. Maps this peer proxy to other peer proxies to - * which the peer has been connected to. Maps pid to PeerProxy. Helps - * keep track of which connections we've sent to whom. - */ - Hashmap* connections; -}; - -/** Server socket path. */ -static const char* MASTER_PATH = "/master.peer"; - -/** Credentials of the master peer. */ -static const Credentials MASTER_CREDENTIALS = {0, 0, 0}; - -/** Creates a peer proxy and adds it to the peer proxy map. */ -static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials); - -/** Sets the non-blocking flag on a descriptor. */ -static void setNonBlocking(int fd) { - int flags; - if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { - LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno)); - } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { - LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno)); - } -} - -/** Closes a fd and logs a warning if the close fails. */ -static void closeWithWarning(int fd) { - int result = close(fd); - if (result == -1) { - ALOGW("close() error: %s", strerror(errno)); - } -} - -/** Hashes pid_t keys. */ -static int pidHash(void* key) { - pid_t* pid = (pid_t*) key; - return (int) (*pid); -} - -/** Compares pid_t keys. */ -static bool pidEquals(void* keyA, void* keyB) { - pid_t* a = (pid_t*) keyA; - pid_t* b = (pid_t*) keyB; - return *a == *b; -} - -/** Gets the master address. Not thread safe. */ -static UnixAddress* getMasterAddress() { - static UnixAddress masterAddress; - static bool initialized = false; - if (initialized == false) { - masterAddress.sun_family = AF_LOCAL; - strcpy(masterAddress.sun_path, MASTER_PATH); - initialized = true; - } - return &masterAddress; -} - -/** Gets exclusive access to the peer for this thread. */ -static void peerLock(Peer* peer) { - pthread_mutex_lock(&peer->mutex); -} - -/** Releases exclusive access to the peer. */ -static void peerUnlock(Peer* peer) { - pthread_mutex_unlock(&peer->mutex); -} - -/** Frees a simple, i.e. header-only, outgoing packet. */ -static void outgoingPacketFree(OutgoingPacket* packet) { - ALOGD("Freeing outgoing packet."); - free(packet); -} - -/** - * Prepare to read a new packet from the peer. - */ -static void peerProxyExpectHeader(PeerProxy* peerProxy) { - peerProxy->inputState = READING_HEADER; - bufferPrepareForRead(peerProxy->inputBuffer, sizeof(Header)); -} - -/** Sets up the buffer for the outgoing header. */ -static void peerProxyPrepareOutgoingHeader(PeerProxy* peerProxy) { - peerProxy->outgoingHeader.data - = (char*) &(peerProxy->currentPacket->header); - peerProxy->outgoingHeader.size = sizeof(Header); - bufferPrepareForWrite(&peerProxy->outgoingHeader); -} - -/** Adds a packet to the end of the queue. Callers must have the mutex. */ -static void peerProxyEnqueueOutgoingPacket(PeerProxy* peerProxy, - OutgoingPacket* newPacket) { - newPacket->nextPacket = NULL; // Just in case. - if (peerProxy->currentPacket == NULL) { - // The queue is empty. - peerProxy->currentPacket = newPacket; - peerProxy->lastPacket = newPacket; - - peerProxyPrepareOutgoingHeader(peerProxy); - } else { - peerProxy->lastPacket->nextPacket = newPacket; - } -} - -/** Takes the peer lock and enqueues the given packet. */ -static void peerProxyLockAndEnqueueOutgoingPacket(PeerProxy* peerProxy, - OutgoingPacket* newPacket) { - Peer* peer = peerProxy->peer; - peerLock(peer); - peerProxyEnqueueOutgoingPacket(peerProxy, newPacket); - peerUnlock(peer); -} - -/** - * Frees current packet and moves to the next one. Returns true if there is - * a next packet or false if the queue is empty. - */ -static bool peerProxyNextPacket(PeerProxy* peerProxy) { - Peer* peer = peerProxy->peer; - peerLock(peer); - - OutgoingPacket* current = peerProxy->currentPacket; - - if (current == NULL) { - // The queue is already empty. - peerUnlock(peer); - return false; - } - - OutgoingPacket* next = current->nextPacket; - peerProxy->currentPacket = next; - current->nextPacket = NULL; - current->free(current); - if (next == NULL) { - // The queue is empty. - peerProxy->lastPacket = NULL; - peerUnlock(peer); - return false; - } else { - peerUnlock(peer); - peerProxyPrepareOutgoingHeader(peerProxy); - - // TODO: Start writing next packet? It would reduce the number of - // system calls, but we could also starve other peers. - return true; - } -} - -/** - * Checks whether a peer died recently. - */ -static bool peerIsDead(Peer* peer, pid_t pid) { - size_t i; - for (i = 0; i < PEER_HISTORY; i++) { - pid_t deadPeer = peer->deadPeers[i]; - if (deadPeer == 0) { - return false; - } - if (deadPeer == pid) { - return true; - } - } - return false; -} - -/** - * Cleans up connection information. - */ -static bool peerProxyRemoveConnection(void* key, void* value, void* context) { - PeerProxy* deadPeer = (PeerProxy*) context; - PeerProxy* otherPeer = (PeerProxy*) value; - hashmapRemove(otherPeer->connections, &(deadPeer->credentials.pid)); - return true; -} - -/** - * Called when the peer dies. - */ -static void peerProxyKill(PeerProxy* peerProxy, bool errnoIsSet) { - if (errnoIsSet) { - ALOGI("Peer %d died. errno: %s", peerProxy->credentials.pid, - strerror(errno)); - } else { - ALOGI("Peer %d died.", peerProxy->credentials.pid); - } - - // If we lost the master, we're up a creek. We can't let this happen. - if (peerProxy->master) { - LOG_ALWAYS_FATAL("Lost connection to master."); - } - - Peer* localPeer = peerProxy->peer; - pid_t pid = peerProxy->credentials.pid; - - peerLock(localPeer); - - // Remember for awhile that the peer died. - localPeer->deadPeers[localPeer->deadPeerCursor] - = peerProxy->credentials.pid; - localPeer->deadPeerCursor++; - if (localPeer->deadPeerCursor == PEER_HISTORY) { - localPeer->deadPeerCursor = 0; - } - - // Remove from peer map. - hashmapRemove(localPeer->peerProxies, &pid); - - // External threads can no longer get to this peer proxy, so we don't - // need the lock anymore. - peerUnlock(localPeer); - - // Remove the fd from the selector. - if (peerProxy->fd != NULL) { - peerProxy->fd->remove = true; - } - - // Clear outgoing packet queue. - while (peerProxyNextPacket(peerProxy)) {} - - bufferFree(peerProxy->inputBuffer); - - // This only applies to the master. - if (peerProxy->connections != NULL) { - // We can't leave these other maps pointing to freed memory. - hashmapForEach(peerProxy->connections, &peerProxyRemoveConnection, - peerProxy); - hashmapFree(peerProxy->connections); - } - - // Invoke death listener. - localPeer->onDeath(pid); - - // Free the peer proxy itself. - free(peerProxy); -} - -static void peerProxyHandleError(PeerProxy* peerProxy, char* functionName) { - if (errno == EINTR) { - // Log interruptions but otherwise ignore them. - ALOGW("%s() interrupted.", functionName); - } else if (errno == EAGAIN) { - ALOGD("EWOULDBLOCK"); - // Ignore. - } else { - ALOGW("Error returned by %s().", functionName); - peerProxyKill(peerProxy, true); - } -} - -/** - * Buffers output sent to a peer. May be called multiple times until the entire - * buffer is filled. Returns true when the buffer is empty. - */ -static bool peerProxyWriteFromBuffer(PeerProxy* peerProxy, Buffer* outgoing) { - ssize_t size = bufferWrite(outgoing, peerProxy->fd->fd); - if (size < 0) { - peerProxyHandleError(peerProxy, "write"); - return false; - } else { - return bufferWriteComplete(outgoing); - } -} - -/** Writes packet bytes to peer. */ -static void peerProxyWriteBytes(PeerProxy* peerProxy) { - Buffer* buffer = peerProxy->currentPacket->bytes; - if (peerProxyWriteFromBuffer(peerProxy, buffer)) { - ALOGD("Bytes written."); - peerProxyNextPacket(peerProxy); - } -} - -/** Sends a socket to the peer. */ -static void peerProxyWriteConnection(PeerProxy* peerProxy) { - int socket = peerProxy->currentPacket->socket; - - // Why does sending and receiving fds have to be such a PITA? - struct msghdr msg; - struct iovec iov[1]; - - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof(int))]; - } control_un; - - struct cmsghdr *cmptr; - - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); - cmptr = CMSG_FIRSTHDR(&msg); - cmptr->cmsg_len = CMSG_LEN(sizeof(int)); - cmptr->cmsg_level = SOL_SOCKET; - cmptr->cmsg_type = SCM_RIGHTS; - - // Store the socket in the message. - *((int *) CMSG_DATA(cmptr)) = peerProxy->currentPacket->socket; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - iov[0].iov_base = ""; - iov[0].iov_len = 1; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - ssize_t result = sendmsg(peerProxy->fd->fd, &msg, 0); - - if (result < 0) { - peerProxyHandleError(peerProxy, "sendmsg"); - } else { - // Success. Queue up the next packet. - peerProxyNextPacket(peerProxy); - - } -} - -/** - * Writes some outgoing data. - */ -static void peerProxyWrite(SelectableFd* fd) { - // TODO: Try to write header and body with one system call. - - PeerProxy* peerProxy = (PeerProxy*) fd->data; - OutgoingPacket* current = peerProxy->currentPacket; - - if (current == NULL) { - // We have nothing left to write. - return; - } - - // Write the header. - Buffer* outgoingHeader = &peerProxy->outgoingHeader; - bool headerWritten = bufferWriteComplete(outgoingHeader); - if (!headerWritten) { - ALOGD("Writing header..."); - headerWritten = peerProxyWriteFromBuffer(peerProxy, outgoingHeader); - if (headerWritten) { - ALOGD("Header written."); - } - } - - // Write body. - if (headerWritten) { - PacketType type = current->header.type; - switch (type) { - case CONNECTION: - peerProxyWriteConnection(peerProxy); - break; - case BYTES: - peerProxyWriteBytes(peerProxy); - break; - case CONNECTION_REQUEST: - case CONNECTION_ERROR: - // These packets consist solely of a header. - peerProxyNextPacket(peerProxy); - break; - default: - LOG_ALWAYS_FATAL("Unknown packet type: %d", type); - } - } -} - -/** - * Sets up a peer proxy's fd before we try to select() it. - */ -static void peerProxyBeforeSelect(SelectableFd* fd) { - ALOGD("Before select..."); - - PeerProxy* peerProxy = (PeerProxy*) fd->data; - - peerLock(peerProxy->peer); - bool hasPackets = peerProxy->currentPacket != NULL; - peerUnlock(peerProxy->peer); - - if (hasPackets) { - ALOGD("Packets found. Setting onWritable()."); - - fd->onWritable = &peerProxyWrite; - } else { - // We have nothing to write. - fd->onWritable = NULL; - } -} - -/** Prepare to read bytes from the peer. */ -static void peerProxyExpectBytes(PeerProxy* peerProxy, Header* header) { - ALOGD("Expecting %d bytes.", header->size); - - peerProxy->inputState = READING_BYTES; - if (bufferPrepareForRead(peerProxy->inputBuffer, header->size) == -1) { - ALOGW("Couldn't allocate memory for incoming data. Size: %u", - (unsigned int) header->size); - - // TODO: Ignore the packet and log a warning? - peerProxyKill(peerProxy, false); - } -} - -/** - * Gets a peer proxy for the given ID. Creates a peer proxy if necessary. - * Sends a connection request to the master if desired. - * - * Returns NULL if an error occurs. Sets errno to EHOSTDOWN if the peer died - * or ENOMEM if memory couldn't be allocated. - */ -static PeerProxy* peerProxyGetOrCreate(Peer* peer, pid_t pid, - bool requestConnection) { - if (pid == peer->pid) { - errno = EINVAL; - return NULL; - } - - if (peerIsDead(peer, pid)) { - errno = EHOSTDOWN; - return NULL; - } - - PeerProxy* peerProxy = hashmapGet(peer->peerProxies, &pid); - if (peerProxy != NULL) { - return peerProxy; - } - - // If this is the master peer, we already know about all peers. - if (peer->master) { - errno = EHOSTDOWN; - return NULL; - } - - // Try to create a peer proxy. - Credentials credentials; - credentials.pid = pid; - - // Fake gid and uid until we have the real thing. The real creds are - // filled in by masterProxyExpectConnection(). These fake creds will - // never be exposed to the user. - credentials.uid = 0; - credentials.gid = 0; - - // Make sure we can allocate the connection request packet. - OutgoingPacket* packet = NULL; - if (requestConnection) { - packet = calloc(1, sizeof(OutgoingPacket)); - if (packet == NULL) { - errno = ENOMEM; - return NULL; - } - - packet->header.type = CONNECTION_REQUEST; - packet->header.credentials = credentials; - packet->free = &outgoingPacketFree; - } - - peerProxy = peerProxyCreate(peer, credentials); - if (peerProxy == NULL) { - free(packet); - errno = ENOMEM; - return NULL; - } else { - // Send a connection request to the master. - if (requestConnection) { - PeerProxy* masterProxy = peer->masterProxy; - peerProxyEnqueueOutgoingPacket(masterProxy, packet); - } - - return peerProxy; - } -} - -/** - * Switches the master peer proxy into a state where it's waiting for a - * connection from the master. - */ -static void masterProxyExpectConnection(PeerProxy* masterProxy, - Header* header) { - // TODO: Restructure things so we don't need this check. - // Verify that this really is the master. - if (!masterProxy->master) { - ALOGW("Non-master process %d tried to send us a connection.", - masterProxy->credentials.pid); - // Kill off the evil peer. - peerProxyKill(masterProxy, false); - return; - } - - masterProxy->inputState = ACCEPTING_CONNECTION; - Peer* localPeer = masterProxy->peer; - - // Create a peer proxy so we have somewhere to stash the creds. - // See if we already have a proxy set up. - pid_t pid = header->credentials.pid; - peerLock(localPeer); - PeerProxy* peerProxy = peerProxyGetOrCreate(localPeer, pid, false); - if (peerProxy == NULL) { - ALOGW("Peer proxy creation failed: %s", strerror(errno)); - } else { - // Fill in full credentials. - peerProxy->credentials = header->credentials; - } - peerUnlock(localPeer); - - // Keep track of which peer proxy we're accepting a connection for. - masterProxy->connecting = peerProxy; -} - -/** - * Reads input from a peer process. - */ -static void peerProxyRead(SelectableFd* fd); - -/** Sets up fd callbacks. */ -static void peerProxySetFd(PeerProxy* peerProxy, SelectableFd* fd) { - peerProxy->fd = fd; - fd->data = peerProxy; - fd->onReadable = &peerProxyRead; - fd->beforeSelect = &peerProxyBeforeSelect; - - // Make the socket non-blocking. - setNonBlocking(fd->fd); -} - -/** - * Accepts a connection sent by the master proxy. - */ -static void masterProxyAcceptConnection(PeerProxy* masterProxy) { - struct msghdr msg; - struct iovec iov[1]; - ssize_t size; - char ignored; - int incomingFd; - - // TODO: Reuse code which writes the connection. Who the heck designed - // this API anyway? - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof(int))]; - } control_un; - struct cmsghdr *cmptr; - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - - // We sent 1 byte of data so we can detect EOF. - iov[0].iov_base = &ignored; - iov[0].iov_len = 1; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - size = recvmsg(masterProxy->fd->fd, &msg, 0); - if (size < 0) { - if (errno == EINTR) { - // Log interruptions but otherwise ignore them. - ALOGW("recvmsg() interrupted."); - return; - } else if (errno == EAGAIN) { - // Keep waiting for the connection. - return; - } else { - LOG_ALWAYS_FATAL("Error reading connection from master: %s", - strerror(errno)); - } - } else if (size == 0) { - // EOF. - LOG_ALWAYS_FATAL("Received EOF from master."); - } - - // Extract fd from message. - if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL - && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { - if (cmptr->cmsg_level != SOL_SOCKET) { - LOG_ALWAYS_FATAL("Expected SOL_SOCKET."); - } - if (cmptr->cmsg_type != SCM_RIGHTS) { - LOG_ALWAYS_FATAL("Expected SCM_RIGHTS."); - } - incomingFd = *((int*) CMSG_DATA(cmptr)); - } else { - LOG_ALWAYS_FATAL("Expected fd."); - } - - // The peer proxy this connection is for. - PeerProxy* peerProxy = masterProxy->connecting; - if (peerProxy == NULL) { - ALOGW("Received connection for unknown peer."); - closeWithWarning(incomingFd); - } else { - Peer* peer = masterProxy->peer; - - SelectableFd* selectableFd = selectorAdd(peer->selector, incomingFd); - if (selectableFd == NULL) { - ALOGW("Error adding fd to selector for %d.", - peerProxy->credentials.pid); - closeWithWarning(incomingFd); - peerProxyKill(peerProxy, false); - } - - peerProxySetFd(peerProxy, selectableFd); - } - - peerProxyExpectHeader(masterProxy); -} - -/** - * Frees an outgoing packet containing a connection. - */ -static void outgoingPacketFreeSocket(OutgoingPacket* packet) { - closeWithWarning(packet->socket); - outgoingPacketFree(packet); -} - -/** - * Connects two known peers. - */ -static void masterConnectPeers(PeerProxy* peerA, PeerProxy* peerB) { - int sockets[2]; - int result = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets); - if (result == -1) { - ALOGW("socketpair() error: %s", strerror(errno)); - // TODO: Send CONNECTION_FAILED packets to peers. - return; - } - - OutgoingPacket* packetA = calloc(1, sizeof(OutgoingPacket)); - OutgoingPacket* packetB = calloc(1, sizeof(OutgoingPacket)); - if (packetA == NULL || packetB == NULL) { - free(packetA); - free(packetB); - ALOGW("malloc() error. Failed to tell process %d that process %d is" - " dead.", peerA->credentials.pid, peerB->credentials.pid); - return; - } - - packetA->header.type = CONNECTION; - packetB->header.type = CONNECTION; - - packetA->header.credentials = peerB->credentials; - packetB->header.credentials = peerA->credentials; - - packetA->socket = sockets[0]; - packetB->socket = sockets[1]; - - packetA->free = &outgoingPacketFreeSocket; - packetB->free = &outgoingPacketFreeSocket; - - peerLock(peerA->peer); - peerProxyEnqueueOutgoingPacket(peerA, packetA); - peerProxyEnqueueOutgoingPacket(peerB, packetB); - peerUnlock(peerA->peer); -} - -/** - * Informs a peer that the peer they're trying to connect to couldn't be - * found. - */ -static void masterReportConnectionError(PeerProxy* peerProxy, - Credentials credentials) { - OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket)); - if (packet == NULL) { - ALOGW("malloc() error. Failed to tell process %d that process %d is" - " dead.", peerProxy->credentials.pid, credentials.pid); - return; - } - - packet->header.type = CONNECTION_ERROR; - packet->header.credentials = credentials; - packet->free = &outgoingPacketFree; - - peerProxyLockAndEnqueueOutgoingPacket(peerProxy, packet); -} - -/** - * Handles a request to be connected to another peer. - */ -static void masterHandleConnectionRequest(PeerProxy* peerProxy, - Header* header) { - Peer* master = peerProxy->peer; - pid_t targetPid = header->credentials.pid; - if (!hashmapContainsKey(peerProxy->connections, &targetPid)) { - // We haven't connected these peers yet. - PeerProxy* targetPeer - = (PeerProxy*) hashmapGet(master->peerProxies, &targetPid); - if (targetPeer == NULL) { - // Unknown process. - masterReportConnectionError(peerProxy, header->credentials); - } else { - masterConnectPeers(peerProxy, targetPeer); - } - } - - // This packet is complete. Get ready for the next one. - peerProxyExpectHeader(peerProxy); -} - -/** - * The master told us this peer is dead. - */ -static void masterProxyHandleConnectionError(PeerProxy* masterProxy, - Header* header) { - Peer* peer = masterProxy->peer; - - // Look up the peer proxy. - pid_t pid = header->credentials.pid; - PeerProxy* peerProxy = NULL; - peerLock(peer); - peerProxy = hashmapGet(peer->peerProxies, &pid); - peerUnlock(peer); - - if (peerProxy != NULL) { - ALOGI("Couldn't connect to %d.", pid); - peerProxyKill(peerProxy, false); - } else { - ALOGW("Peer proxy for %d not found. This shouldn't happen.", pid); - } - - peerProxyExpectHeader(masterProxy); -} - -/** - * Handles a packet header. - */ -static void peerProxyHandleHeader(PeerProxy* peerProxy, Header* header) { - switch (header->type) { - case CONNECTION_REQUEST: - masterHandleConnectionRequest(peerProxy, header); - break; - case CONNECTION: - masterProxyExpectConnection(peerProxy, header); - break; - case CONNECTION_ERROR: - masterProxyHandleConnectionError(peerProxy, header); - break; - case BYTES: - peerProxyExpectBytes(peerProxy, header); - break; - default: - ALOGW("Invalid packet type from %d: %d", peerProxy->credentials.pid, - header->type); - peerProxyKill(peerProxy, false); - } -} - -/** - * Buffers input sent by peer. May be called multiple times until the entire - * buffer is filled. Returns true when the buffer is full. - */ -static bool peerProxyBufferInput(PeerProxy* peerProxy) { - Buffer* in = peerProxy->inputBuffer; - ssize_t size = bufferRead(in, peerProxy->fd->fd); - if (size < 0) { - peerProxyHandleError(peerProxy, "read"); - return false; - } else if (size == 0) { - // EOF. - ALOGI("EOF"); - peerProxyKill(peerProxy, false); - return false; - } else if (bufferReadComplete(in)) { - // We're done! - return true; - } else { - // Continue reading. - return false; - } -} - -/** - * Reads input from a peer process. - */ -static void peerProxyRead(SelectableFd* fd) { - ALOGD("Reading..."); - PeerProxy* peerProxy = (PeerProxy*) fd->data; - int state = peerProxy->inputState; - Buffer* in = peerProxy->inputBuffer; - switch (state) { - case READING_HEADER: - if (peerProxyBufferInput(peerProxy)) { - ALOGD("Header read."); - // We've read the complete header. - Header* header = (Header*) in->data; - peerProxyHandleHeader(peerProxy, header); - } - break; - case READING_BYTES: - ALOGD("Reading bytes..."); - if (peerProxyBufferInput(peerProxy)) { - ALOGD("Bytes read."); - // We have the complete packet. Notify bytes listener. - peerProxy->peer->onBytes(peerProxy->credentials, - in->data, in->size); - - // Get ready for the next packet. - peerProxyExpectHeader(peerProxy); - } - break; - case ACCEPTING_CONNECTION: - masterProxyAcceptConnection(peerProxy); - break; - default: - LOG_ALWAYS_FATAL("Unknown state: %d", state); - } -} - -static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials) { - PeerProxy* peerProxy = calloc(1, sizeof(PeerProxy)); - if (peerProxy == NULL) { - return NULL; - } - - peerProxy->inputBuffer = bufferCreate(sizeof(Header)); - if (peerProxy->inputBuffer == NULL) { - free(peerProxy); - return NULL; - } - - peerProxy->peer = peer; - peerProxy->credentials = credentials; - - // Initial state == expecting a header. - peerProxyExpectHeader(peerProxy); - - // Add this proxy to the map. Make sure the key points to the stable memory - // inside of the peer proxy itself. - pid_t* pid = &(peerProxy->credentials.pid); - hashmapPut(peer->peerProxies, pid, peerProxy); - return peerProxy; -} - -/** Accepts a connection to the master peer. */ -static void masterAcceptConnection(SelectableFd* listenerFd) { - // Accept connection. - int socket = accept(listenerFd->fd, NULL, NULL); - if (socket == -1) { - ALOGW("accept() error: %s", strerror(errno)); - return; - } - - ALOGD("Accepted connection as fd %d.", socket); - - // Get credentials. - Credentials credentials; - struct ucred ucredentials; - socklen_t credentialsSize = sizeof(struct ucred); - int result = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, - &ucredentials, &credentialsSize); - // We might want to verify credentialsSize. - if (result == -1) { - ALOGW("getsockopt() error: %s", strerror(errno)); - closeWithWarning(socket); - return; - } - - // Copy values into our own structure so we know we have the types right. - credentials.pid = ucredentials.pid; - credentials.uid = ucredentials.uid; - credentials.gid = ucredentials.gid; - - ALOGI("Accepted connection from process %d.", credentials.pid); - - Peer* masterPeer = (Peer*) listenerFd->data; - - peerLock(masterPeer); - - // Make sure we don't already have a connection from that process. - PeerProxy* peerProxy - = hashmapGet(masterPeer->peerProxies, &credentials.pid); - if (peerProxy != NULL) { - peerUnlock(masterPeer); - ALOGW("Alread connected to process %d.", credentials.pid); - closeWithWarning(socket); - return; - } - - // Add connection to the selector. - SelectableFd* socketFd = selectorAdd(masterPeer->selector, socket); - if (socketFd == NULL) { - peerUnlock(masterPeer); - ALOGW("malloc() failed."); - closeWithWarning(socket); - return; - } - - // Create a peer proxy. - peerProxy = peerProxyCreate(masterPeer, credentials); - peerUnlock(masterPeer); - if (peerProxy == NULL) { - ALOGW("malloc() failed."); - socketFd->remove = true; - closeWithWarning(socket); - } - peerProxy->connections = hashmapCreate(10, &pidHash, &pidEquals); - peerProxySetFd(peerProxy, socketFd); -} - -/** - * Creates the local peer. - */ -static Peer* peerCreate() { - Peer* peer = calloc(1, sizeof(Peer)); - if (peer == NULL) { - LOG_ALWAYS_FATAL("malloc() error."); - } - peer->peerProxies = hashmapCreate(10, &pidHash, &pidEquals); - peer->selector = selectorCreate(); - - pthread_mutexattr_t attributes; - if (pthread_mutexattr_init(&attributes) != 0) { - LOG_ALWAYS_FATAL("pthread_mutexattr_init() error."); - } - if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) { - LOG_ALWAYS_FATAL("pthread_mutexattr_settype() error."); - } - if (pthread_mutex_init(&peer->mutex, &attributes) != 0) { - LOG_ALWAYS_FATAL("pthread_mutex_init() error."); - } - - peer->pid = getpid(); - return peer; -} - -/** The local peer. */ -static Peer* localPeer; - -/** Frees a packet of bytes. */ -static void outgoingPacketFreeBytes(OutgoingPacket* packet) { - ALOGD("Freeing outgoing packet."); - bufferFree(packet->bytes); - free(packet); -} - -/** - * Sends a packet of bytes to a remote peer. Returns 0 on success. - * - * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be - * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno - * to EINVAL if pid is the same as the local pid. - */ -int peerSendBytes(pid_t pid, const char* bytes, size_t size) { - Peer* peer = localPeer; - assert(peer != NULL); - - OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket)); - if (packet == NULL) { - errno = ENOMEM; - return -1; - } - - Buffer* copy = bufferCreate(size); - if (copy == NULL) { - free(packet); - errno = ENOMEM; - return -1; - } - - // Copy data. - memcpy(copy->data, bytes, size); - copy->size = size; - - packet->bytes = copy; - packet->header.type = BYTES; - packet->header.size = size; - packet->free = outgoingPacketFreeBytes; - bufferPrepareForWrite(packet->bytes); - - peerLock(peer); - - PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true); - if (peerProxy == NULL) { - // The peer is already dead or we couldn't alloc memory. Either way, - // errno is set. - peerUnlock(peer); - packet->free(packet); - return -1; - } else { - peerProxyEnqueueOutgoingPacket(peerProxy, packet); - peerUnlock(peer); - selectorWakeUp(peer->selector); - return 0; - } -} - -/** Keeps track of how to free shared bytes. */ -typedef struct { - void (*free)(void* context); - void* context; -} SharedBytesFreer; - -/** Frees shared bytes. */ -static void outgoingPacketFreeSharedBytes(OutgoingPacket* packet) { - SharedBytesFreer* sharedBytesFreer - = (SharedBytesFreer*) packet->context; - sharedBytesFreer->free(sharedBytesFreer->context); - free(sharedBytesFreer); - free(packet); -} - -/** - * Sends a packet of bytes to a remote peer without copying the bytes. Calls - * free() with context after the bytes have been sent. - * - * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be - * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno - * to EINVAL if pid is the same as the local pid. - */ -int peerSendSharedBytes(pid_t pid, char* bytes, size_t size, - void (*free)(void* context), void* context) { - Peer* peer = localPeer; - assert(peer != NULL); - - OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket)); - if (packet == NULL) { - errno = ENOMEM; - return -1; - } - - Buffer* wrapper = bufferWrap(bytes, size, size); - if (wrapper == NULL) { - free(packet); - errno = ENOMEM; - return -1; - } - - SharedBytesFreer* sharedBytesFreer = malloc(sizeof(SharedBytesFreer)); - if (sharedBytesFreer == NULL) { - free(packet); - free(wrapper); - errno = ENOMEM; - return -1; - } - sharedBytesFreer->free = free; - sharedBytesFreer->context = context; - - packet->bytes = wrapper; - packet->context = sharedBytesFreer; - packet->header.type = BYTES; - packet->header.size = size; - packet->free = &outgoingPacketFreeSharedBytes; - bufferPrepareForWrite(packet->bytes); - - peerLock(peer); - - PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true); - if (peerProxy == NULL) { - // The peer is already dead or we couldn't alloc memory. Either way, - // errno is set. - peerUnlock(peer); - packet->free(packet); - return -1; - } else { - peerProxyEnqueueOutgoingPacket(peerProxy, packet); - peerUnlock(peer); - selectorWakeUp(peer->selector); - return 0; - } -} - -/** - * Starts the master peer. The master peer differs from other peers in that - * it is responsible for connecting the other peers. You can only have one - * master peer. - * - * Goes into an I/O loop and does not return. - */ -void masterPeerInitialize(BytesListener* bytesListener, - DeathListener* deathListener) { - // Create and bind socket. - int listenerSocket = socket(AF_LOCAL, SOCK_STREAM, 0); - if (listenerSocket == -1) { - LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno)); - } - unlink(MASTER_PATH); - int result = bind(listenerSocket, (SocketAddress*) getMasterAddress(), - sizeof(UnixAddress)); - if (result == -1) { - LOG_ALWAYS_FATAL("bind() error: %s", strerror(errno)); - } - - ALOGD("Listener socket: %d", listenerSocket); - - // Queue up to 16 connections. - result = listen(listenerSocket, 16); - if (result != 0) { - LOG_ALWAYS_FATAL("listen() error: %s", strerror(errno)); - } - - // Make socket non-blocking. - setNonBlocking(listenerSocket); - - // Create the peer for this process. Fail if we already have one. - if (localPeer != NULL) { - LOG_ALWAYS_FATAL("Peer is already initialized."); - } - localPeer = peerCreate(); - if (localPeer == NULL) { - LOG_ALWAYS_FATAL("malloc() failed."); - } - localPeer->master = true; - localPeer->onBytes = bytesListener; - localPeer->onDeath = deathListener; - - // Make listener socket selectable. - SelectableFd* listenerFd = selectorAdd(localPeer->selector, listenerSocket); - if (listenerFd == NULL) { - LOG_ALWAYS_FATAL("malloc() error."); - } - listenerFd->data = localPeer; - listenerFd->onReadable = &masterAcceptConnection; -} - -/** - * Starts a local peer. - * - * Goes into an I/O loop and does not return. - */ -void peerInitialize(BytesListener* bytesListener, - DeathListener* deathListener) { - // Connect to master peer. - int masterSocket = socket(AF_LOCAL, SOCK_STREAM, 0); - if (masterSocket == -1) { - LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno)); - } - int result = connect(masterSocket, (SocketAddress*) getMasterAddress(), - sizeof(UnixAddress)); - if (result != 0) { - LOG_ALWAYS_FATAL("connect() error: %s", strerror(errno)); - } - - // Create the peer for this process. Fail if we already have one. - if (localPeer != NULL) { - LOG_ALWAYS_FATAL("Peer is already initialized."); - } - localPeer = peerCreate(); - if (localPeer == NULL) { - LOG_ALWAYS_FATAL("malloc() failed."); - } - localPeer->onBytes = bytesListener; - localPeer->onDeath = deathListener; - - // Make connection selectable. - SelectableFd* masterFd = selectorAdd(localPeer->selector, masterSocket); - if (masterFd == NULL) { - LOG_ALWAYS_FATAL("malloc() error."); - } - - // Create a peer proxy for the master peer. - PeerProxy* masterProxy = peerProxyCreate(localPeer, MASTER_CREDENTIALS); - if (masterProxy == NULL) { - LOG_ALWAYS_FATAL("malloc() error."); - } - peerProxySetFd(masterProxy, masterFd); - masterProxy->master = true; - localPeer->masterProxy = masterProxy; -} - -/** Starts the master peer I/O loop. Doesn't return. */ -void peerLoop() { - assert(localPeer != NULL); - - // Start selector. - selectorLoop(localPeer->selector); -} - diff --git a/libcutils/qsort_r_compat.c b/libcutils/qsort_r_compat.c deleted file mode 100644 index 8971cb5bc..000000000 --- a/libcutils/qsort_r_compat.c +++ /dev/null @@ -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 -#include - -#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 - -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 diff --git a/libcutils/record_stream.c b/libcutils/record_stream.c deleted file mode 100644 index 69949047c..000000000 --- a/libcutils/record_stream.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#ifdef HAVE_WINSOCK -#include /* for ntohl */ -#else -#include -#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; -} diff --git a/libcutils/selector.c b/libcutils/selector.c deleted file mode 100644 index 3776bbbc5..000000000 --- a/libcutils/selector.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#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); - } - } -} diff --git a/libcutils/zygote.c b/libcutils/zygote.c deleted file mode 100644 index 37236e8a6..000000000 --- a/libcutils/zygote.c +++ /dev/null @@ -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 -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 = ' '; - } - } -} - - -