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:
parent
69e9b17fa1
commit
e00a12bf8a
|
@ -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__
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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*/
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
1357
libcutils/mq.c
1357
libcutils/mq.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue