M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
#
# Copyright (C) 2008 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.
#
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
ifeq ($(TARGET_CPU_SMP),true)
targetSmpFlag := -DANDROID_SMP=1
else
targetSmpFlag := -DANDROID_SMP=0
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 \
socket_loopback_client.c \
socket_loopback_server.c \
socket_network_client.c \
config_utils.c \
cpu_info.c \
load_file.c \
open_memstream.c \
strdup16to8.c \
strdup8to16.c \
record_stream.c \
process_name.c \
properties.c \
threads.c \
sched_policy.c \
iosched_policy.c
commonHostSources := \
ashmem-host.c
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
# which are also hard or even impossible to port to native Win32
WINDOWS_HOST_ONLY :=
ifeq ($(HOST_OS),windows)
ifeq ($(strip $(USE_CYGWIN)),)
WINDOWS_HOST_ONLY := 1
endif
endif
# USE_MINGW is defined when we build against Mingw on Linux
ifneq ($(strip $(USE_MINGW)),)
WINDOWS_HOST_ONLY := 1
endif
ifeq ($(WINDOWS_HOST_ONLY),1)
commonSources += \
uio.c
else
commonSources += \
abort_socket.c \
mspace.c \
selector.c \
tztime.c \
zygote.c
commonHostSources += \
tzstrftime.c
endif
# Static library for host
# ========================================================
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
LOCAL_LDLIBS := -lpthread
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(hostSmpFlag)
include $(BUILD_HOST_STATIC_LIBRARY)
ifeq ($(TARGET_SIMULATOR),true)
# Shared library for simulator
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) memory.c dlmalloc_stubs.c
LOCAL_LDLIBS := -lpthread
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_SHARED_LIBRARY)
else #!sim
# Shared and static library for target
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += memset32.S
else # !arm
ifeq ($(TARGET_ARCH),sh)
LOCAL_SRC_FILES += memory.c atomic-android-sh.c
else # !sh
LOCAL_SRC_FILES += memory.c
endif # !sh
endif # !arm
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
LOCAL_WHOLE_STATIC_LIBRARIES := libcutils
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_SHARED_LIBRARY)
endif #!sim
+67
View File
@@ -0,0 +1,67 @@
# NOTE: Only supports builds of shared/static libraries for the target
common_sources := array.c
common_sources += hashmap.c
common_sources += atomic.c
common_sources += native_handle.c
common_sources += buffer.c
common_sources += socket_inaddr_any_server.c
common_sources += socket_local_client.c
common_sources += socket_local_server.c
common_sources += socket_loopback_client.c
common_sources += socket_loopback_server.c
common_sources += socket_network_client.c
common_sources += config_utils.c
common_sources += cpu_info.c
common_sources += load_file.c
common_sources += strdup16to8.c
common_sources += strdup8to16.c
common_sources += record_stream.c
common_sources += process_name.c
common_sources += properties.c
common_sources += threads.c
# common_sources += sched_policy.c
# common_sources += iosched_policy.c
# TODO: When building against Mingw, these files should NOT be built
common_sources += abort_socket.c
common_sources += mspace.c
common_sources += selector.c
common_sources += tztime.c
# common_sources += adb_networking.c
common_sources += zygote.c
# Target libcutils
lib_LIBRARIES := libcutils.a
libcutils_a_CPPFLAGS := -I../include
libcutils_a_CPPFLAGS += -I../liblog
libcutils_a_CPPFLAGS += -DHAVE_PTHREADS
libcutils_a_CPPFLAGS += -DLINUX_ENABLED
libcutils_a_CPPFLAGS += -DANDROID_SMP=0
libcutils_a_CPPFLAGS += -include ../include/arch/linux-arm/OEConfig.h
# libcutils_a_LDFLAGS := -version-info 1:0:0
# libcutils_a_LIBADD := -lpthread
requiredlibs = -lpthread
libcutils_a_SOURCES := $(common_sources)
libcutils_a_SOURCES += ashmem-dev.c
libcutils_a_SOURCES += mq.c
libcutils_a_SOURCES += memory.c
if ARM
libcutils_a_CPPFLAGS += -DHAVE_ASM_MEMSET
libcutils_a_SOURCES += memset32.S
endif # !ARM
# Build a DSO too
lib_LTLIBRARIES := libcutils.la
libcutils_la_SOURCES := $(libcutils_a_SOURCES)
libcutils_la_CPPFLAGS := $(libcutils_a_CPPFLAGS)
pkgconfigdir := $(libdir)/pkgconfig
pkgconfig_DATA := libcutils.pc
EXTRA_DIST := $(pkgconfig_DATA)
+190
View File
@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, 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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+293
View File
@@ -0,0 +1,293 @@
/*
* 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);
}
+170
View File
@@ -0,0 +1,170 @@
/*
* 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;
}
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2008 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.
*/
/*
* Implementation of the user-space ashmem API for devices, which have our
* ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
* used by the simulator.
*/
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#if !LINUX_ENABLED
#include <linux/ashmem.h>
#endif /* !LINUX_ENABLED */
#include <cutils/ashmem.h>
#define ASHMEM_DEVICE "/dev/ashmem"
/*
* ashmem_create_region - creates a new ashmem region and returns the file
* descriptor, or <0 on error
*
* `name' is an optional label to give the region (visible in /proc/pid/maps)
* `size' is the size of the region, in page-aligned bytes
*/
int ashmem_create_region(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
if (name) {
char buf[ASHMEM_NAME_LEN];
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
if (ret < 0)
goto error;
}
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
goto error;
return fd;
error:
close(fd);
return ret;
}
int ashmem_set_prot_region(int fd, int prot)
{
return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
}
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
return ioctl(fd, ASHMEM_PIN, &pin);
}
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
return ioctl(fd, ASHMEM_UNPIN, &pin);
}
int ashmem_get_size_region(int fd)
{
return ioctl(fd, ASHMEM_GET_SIZE, NULL);
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2008 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.
*/
/*
* Implementation of the user-space ashmem API for the simulator, which lacks
* an ashmem-enabled kernel. See ashmem-dev.c for the real ashmem-based version.
*/
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <limits.h>
#include <cutils/ashmem.h>
int ashmem_create_region(const char *ignored, size_t size)
{
static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char name[64];
unsigned int retries = 0;
pid_t pid = getpid();
int fd;
srand(time(NULL) + pid);
retry:
/* not beautiful, its just wolf-like loop unrolling */
snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
pid,
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
/* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd == -1) {
/* unlikely, but if we failed because `name' exists, retry */
if (errno == EEXIST && ++retries < 6)
goto retry;
return -1;
}
/* truncate the file to `len' bytes */
if (ftruncate(fd, size) == -1)
goto error;
if (unlink(name) == -1)
goto error;
return fd;
error:
close(fd);
return -1;
}
int ashmem_set_prot_region(int fd, int prot)
{
return 0;
}
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
return ASHMEM_NOT_PURGED;
}
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
return ASHMEM_IS_UNPINNED;
}
int ashmem_get_size_region(int fd)
{
struct stat buf;
int result;
result = fstat(fd, &buf);
if (result == -1) {
return -1;
}
// Check if this is an "ashmem" region.
// TODO: This is very hacky, and can easily break. We need some reliable indicator.
if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
errno = ENOTTY;
return -1;
}
return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
}
+149
View File
@@ -0,0 +1,149 @@
/*
* 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/atomic.h>
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
#else
#include <sched.h>
#endif
/*
* Note :
*
* (1) SuperH does not have CMPXCHG. It has only TAS for atomic
* operations. It does not seem a good idea to implement CMPXCHG,
* with TAS. So, we choose to implemnt these operations with
* posix mutexes. Please be sure that this might cause performance
* problem for Android-SH. Using LL/SC instructions supported in SH-X3,
* best performnace would be realized.
*
* (2) Mutex initialization problem happens, which is commented for
* ARM implementation, in this file above.
* We follow the fact that the initializer for mutex is a simple zero
* value.
*
* (3) These operations are NOT safe for SMP, as there is no currently
* no definition for a memory barrier operation.
*/
#include <pthread.h>
#define SWAP_LOCK_COUNT 32U
static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
#define SWAP_LOCK(addr) \
&_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
int32_t android_atomic_acquire_load(volatile const int32_t* addr)
{
return *addr;
}
int32_t android_atomic_release_load(volatile const int32_t* addr)
{
return *addr;
}
void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, value, addr));
}
void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, value, addr));
}
int32_t android_atomic_inc(volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, oldValue+1, addr));
return oldValue;
}
int32_t android_atomic_dec(volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, oldValue-1, addr));
return oldValue;
}
int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, oldValue+value, addr));
return oldValue;
}
int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, oldValue&value, addr));
return oldValue;
}
int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_release_cas(oldValue, oldValue|value, addr));
return oldValue;
}
int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
return android_atomic_release_swap(value, addr);
}
int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
} while (android_atomic_cmpxchg(oldValue, value, addr));
return oldValue;
}
int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
return android_atomic_release_cmpxchg(oldValue, newValue, addr);
}
int android_atomic_release_cmpxchg(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
int result;
pthread_mutex_t* lock = SWAP_LOCK(addr);
pthread_mutex_lock(lock);
if (*addr == oldvalue) {
*addr = newvalue;
result = 0;
} else {
result = 1;
}
pthread_mutex_unlock(lock);
return result;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* 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 inline
#include <cutils/atomic-inline.h>
+116
View File
@@ -0,0 +1,116 @@
/*
* 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;
LOGD("Buffer bytes written: %d", (int) bytesWritten);
LOGD("Buffer size: %d", (int) buffer->size);
LOGD("Buffer remaining: %d", (int) buffer->remaining);
return buffer->remaining;
}
return bytesWritten;
}
+112
View File
@@ -0,0 +1,112 @@
/*
* 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 */
+317
View File
@@ -0,0 +1,317 @@
/*
* 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 <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <cutils/config_utils.h>
#include <cutils/misc.h>
cnode* config_node(const char *name, const char *value)
{
cnode *node;
node = calloc(sizeof(cnode), 1);
if(node) {
node->name = name ? name : "";
node->value = value ? value : "";
}
return node;
}
cnode* config_find(cnode *root, const char *name)
{
cnode *node, *match = NULL;
/* we walk the whole list, as we need to return the last (newest) entry */
for(node = root->first_child; node; node = node->next)
if(!strcmp(node->name, name))
match = node;
return match;
}
static cnode* _config_create(cnode *root, const char *name)
{
cnode *node;
node = config_node(name, NULL);
if(root->last_child)
root->last_child->next = node;
else
root->first_child = node;
root->last_child = node;
return node;
}
int config_bool(cnode *root, const char *name, int _default)
{
cnode *node;
node = config_find(root, name);
if(!node)
return _default;
switch(node->value[0]) {
case 'y':
case 'Y':
case '1':
return 1;
default:
return 0;
}
}
const char* config_str(cnode *root, const char *name, const char *_default)
{
cnode *node;
node = config_find(root, name);
if(!node)
return _default;
return node->value;
}
void config_set(cnode *root, const char *name, const char *value)
{
cnode *node;
node = config_find(root, name);
if(node)
node->value = value;
else {
node = _config_create(root, name);
node->value = value;
}
}
#define T_EOF 0
#define T_TEXT 1
#define T_DOT 2
#define T_OBRACE 3
#define T_CBRACE 4
typedef struct
{
char *data;
char *text;
int len;
char next;
} cstate;
static int _lex(cstate *cs, int value)
{
char c;
char *s;
char *data;
data = cs->data;
if(cs->next != 0) {
c = cs->next;
cs->next = 0;
goto got_c;
}
restart:
for(;;) {
c = *data++;
got_c:
if(isspace(c))
continue;
switch(c) {
case 0:
return T_EOF;
case '#':
for(;;) {
switch(*data) {
case 0:
cs->data = data;
return T_EOF;
case '\n':
cs->data = data + 1;
goto restart;
default:
data++;
}
}
break;
case '.':
cs->data = data;
return T_DOT;
case '{':
cs->data = data;
return T_OBRACE;
case '}':
cs->data = data;
return T_CBRACE;
default:
s = data - 1;
if(value) {
for(;;) {
if(*data == 0) {
cs->data = data;
break;
}
if(*data == '\n') {
cs->data = data + 1;
*data-- = 0;
break;
}
data++;
}
/* strip trailing whitespace */
while(data > s){
if(!isspace(*data)) break;
*data-- = 0;
}
goto got_text;
} else {
for(;;) {
if(isspace(*data)) {
*data = 0;
cs->data = data + 1;
goto got_text;
}
switch(*data) {
case 0:
cs->data = data;
goto got_text;
case '.':
case '{':
case '}':
cs->next = *data;
*data = 0;
cs->data = data + 1;
goto got_text;
default:
data++;
}
}
}
}
}
got_text:
cs->text = s;
return T_TEXT;
}
#if 0
char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
static int lex(cstate *cs, int value)
{
int tok = _lex(cs, value);
printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
tok == T_TEXT ? cs->text : "");
return tok;
}
#else
#define lex(cs,v) _lex(cs,v)
#endif
static int parse_expr(cstate *cs, cnode *node);
static int parse_block(cstate *cs, cnode *node)
{
for(;;){
switch(lex(cs, 0)){
case T_TEXT:
if(parse_expr(cs, node)) return -1;
continue;
case T_CBRACE:
return 0;
default:
return -1;
}
}
}
static int parse_expr(cstate *cs, cnode *root)
{
cnode *node;
/* last token was T_TEXT */
node = config_find(root, cs->text);
if(!node || *node->value)
node = _config_create(root, cs->text);
for(;;) {
switch(lex(cs, 1)) {
case T_DOT:
if(lex(cs, 0) != T_TEXT)
return -1;
node = _config_create(node, cs->text);
continue;
case T_TEXT:
node->value = cs->text;
return 0;
case T_OBRACE:
return parse_block(cs, node);
default:
return -1;
}
}
}
void config_load(cnode *root, char *data)
{
if(data != 0) {
cstate cs;
cs.data = data;
cs.next = 0;
for(;;) {
switch(lex(&cs, 0)) {
case T_TEXT:
if(parse_expr(&cs, root))
return;
break;
default:
return;
}
}
}
}
void config_load_file(cnode *root, const char *fn)
{
char *data;
data = load_file(fn, 0);
config_load(root, data);
}
+83
View File
@@ -0,0 +1,83 @@
/* libs/cutils/cpu_info.c
**
** Copyright 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/cpu_info.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// we cache the serial number here.
// this is also used as a fgets() line buffer when we are reading /proc/cpuinfo
static char serial_number[100] = { 0 };
extern const char* get_cpu_serial_number(void)
{
if (serial_number[0] == 0)
{
FILE* file;
char* chp, *end;
char* whitespace;
int length;
// read serial number from /proc/cpuinfo
file = fopen("proc/cpuinfo", "r");
if (! file)
return NULL;
while ((chp = fgets(serial_number, sizeof(serial_number), file)) != NULL)
{
// look for something like "Serial : 999206122a03591c"
if (strncmp(chp, "Serial", 6) != 0)
continue;
chp = strchr(chp, ':');
if (!chp)
continue;
// skip colon and whitespace
while ( *(++chp) == ' ') {}
// truncate trailing whitespace
end = chp;
while (*end && *end != ' ' && *end != '\t' && *end != '\n' && *end != '\r')
++end;
*end = 0;
whitespace = strchr(chp, ' ');
if (whitespace)
*whitespace = 0;
whitespace = strchr(chp, '\t');
if (whitespace)
*whitespace = 0;
whitespace = strchr(chp, '\r');
if (whitespace)
*whitespace = 0;
whitespace = strchr(chp, '\n');
if (whitespace)
*whitespace = 0;
// shift serial number to beginning of the buffer
memmove(serial_number, chp, strlen(chp) + 1);
break;
}
fclose(file);
}
return (serial_number[0] ? serial_number : NULL);
}
+334
View File
@@ -0,0 +1,334 @@
/*
* 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 <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sha1.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <resolv.h>
#include <cutils/dir_hash.h>
/**
* Copies, if it fits within max_output_string bytes, into output_string
* a hash of the contents, size, permissions, uid, and gid of the file
* specified by path, using the specified algorithm. Returns the length
* of the output string, or a negative number if the buffer is too short.
*/
int get_file_hash(HashAlgorithm algorithm, const char *path,
char *output_string, size_t max_output_string) {
SHA1_CTX context;
struct stat sb;
unsigned char md[SHA1_DIGEST_LENGTH];
int used;
size_t n;
if (algorithm != SHA_1) {
errno = EINVAL;
return -1;
}
if (stat(path, &sb) != 0) {
return -1;
}
if (S_ISLNK(sb.st_mode)) {
char buf[PATH_MAX];
int len;
len = readlink(path, buf, sizeof(buf));
if (len < 0) {
return -1;
}
SHA1Init(&context);
SHA1Update(&context, (unsigned char *) buf, len);
SHA1Final(md, &context);
} else if (S_ISREG(sb.st_mode)) {
char buf[10000];
FILE *f = fopen(path, "rb");
int len;
if (f == NULL) {
return -1;
}
SHA1Init(&context);
while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
SHA1Update(&context, (unsigned char *) buf, len);
}
if (ferror(f)) {
fclose(f);
return -1;
}
fclose(f);
SHA1Final(md, &context);
}
if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
used = b64_ntop(md, SHA1_DIGEST_LENGTH,
output_string, max_output_string);
if (used < 0) {
errno = ENOSPC;
return -1;
}
n = snprintf(output_string + used, max_output_string - used,
" %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
(int) sb.st_uid, (int) sb.st_gid);
} else {
n = snprintf(output_string, max_output_string,
"- - 0%o %d %d", sb.st_mode,
(int) sb.st_uid, (int) sb.st_gid);
}
if (n >= max_output_string - used) {
errno = ENOSPC;
return -(used + n);
}
return used + n;
}
struct list {
char *name;
struct list *next;
};
static int cmp(const void *a, const void *b) {
struct list *const *ra = a;
struct list *const *rb = b;
return strcmp((*ra)->name, (*rb)->name);
}
static int recurse(HashAlgorithm algorithm, const char *directory_path,
struct list **out) {
struct list *list = NULL;
struct list *f;
struct dirent *de;
DIR *d = opendir(directory_path);
if (d == NULL) {
return -1;
}
while ((de = readdir(d)) != NULL) {
if (strcmp(de->d_name, ".") == 0) {
continue;
}
if (strcmp(de->d_name, "..") == 0) {
continue;
}
char *name = malloc(strlen(de->d_name) + 1);
struct list *node = malloc(sizeof(struct list));
if (name == NULL || node == NULL) {
struct list *next;
for (f = list; f != NULL; f = next) {
next = f->next;
free(f->name);
free(f);
}
free(name);
free(node);
return -1;
}
strcpy(name, de->d_name);
node->name = name;
node->next = list;
list = node;
}
closedir(d);
for (f = list; f != NULL; f = f->next) {
struct stat sb;
char *name;
char outstr[NAME_MAX + 100];
char *keep;
struct list *res;
name = malloc(strlen(f->name) + strlen(directory_path) + 2);
if (name == NULL) {
struct list *next;
for (f = list; f != NULL; f = f->next) {
next = f->next;
free(f->name);
free(f);
}
for (f = *out; f != NULL; f = f->next) {
next = f->next;
free(f->name);
free(f);
}
*out = NULL;
return -1;
}
sprintf(name, "%s/%s", directory_path, f->name);
int len = get_file_hash(algorithm, name,
outstr, sizeof(outstr));
if (len < 0) {
// should not happen
return -1;
}
keep = malloc(len + strlen(name) + 3);
res = malloc(sizeof(struct list));
if (keep == NULL || res == NULL) {
struct list *next;
for (f = list; f != NULL; f = f->next) {
next = f->next;
free(f->name);
free(f);
}
for (f = *out; f != NULL; f = f->next) {
next = f->next;
free(f->name);
free(f);
}
*out = NULL;
free(keep);
free(res);
return -1;
}
sprintf(keep, "%s %s\n", name, outstr);
res->name = keep;
res->next = *out;
*out = res;
if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
if (recurse(algorithm, name, out) < 0) {
struct list *next;
for (f = list; f != NULL; f = next) {
next = f->next;
free(f->name);
free(f);
}
return -1;
}
}
}
struct list *next;
for (f = list; f != NULL; f = next) {
next = f->next;
free(f->name);
free(f);
}
}
/**
* Allocates a string containing the names and hashes of all files recursively
* reached under the specified directory_path, using the specified algorithm.
* The string is returned as *output_string; the return value is the length
* of the string, or a negative number if there was a failure.
*/
int get_recursive_hash_manifest(HashAlgorithm algorithm,
const char *directory_path,
char **output_string) {
struct list *out = NULL;
struct list *r;
struct list **list;
int count = 0;
int len = 0;
int retlen = 0;
int i;
char *buf;
if (recurse(algorithm, directory_path, &out) < 0) {
return -1;
}
for (r = out; r != NULL; r = r->next) {
count++;
len += strlen(r->name);
}
list = malloc(count * sizeof(struct list *));
if (list == NULL) {
struct list *next;
for (r = out; r != NULL; r = next) {
next = r->next;
free(r->name);
free(r);
}
return -1;
}
count = 0;
for (r = out; r != NULL; r = r->next) {
list[count++] = r;
}
qsort(list, count, sizeof(struct list *), cmp);
buf = malloc(len + 1);
if (buf == NULL) {
struct list *next;
for (r = out; r != NULL; r = next) {
next = r->next;
free(r->name);
free(r);
}
free(list);
return -1;
}
for (i = 0; i < count; i++) {
int n = strlen(list[i]->name);
strcpy(buf + retlen, list[i]->name);
retlen += n;
}
free(list);
struct list *next;
for (r = out; r != NULL; r = next) {
next = r->next;
free(r->name);
free(r);
}
*output_string = buf;
return retlen;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* 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.
*/
/* No-op stubs for functions defined in system/bionic/bionic/dlmalloc.c.
*/
void dlmalloc_walk_free_pages()
{
}
void dlmalloc_walk_heap()
{
}
void dlmalloc_trim()
{
}
+350
View File
@@ -0,0 +1,350 @@
/*
* 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/hashmap.h>
#include <assert.h>
#include <errno.h>
#include <cutils/threads.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
typedef struct Entry Entry;
struct Entry {
void* key;
int hash;
void* value;
Entry* next;
};
struct Hashmap {
Entry** buckets;
size_t bucketCount;
int (*hash)(void* key);
bool (*equals)(void* keyA, void* keyB);
mutex_t lock;
size_t size;
};
Hashmap* hashmapCreate(size_t initialCapacity,
int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
assert(hash != NULL);
assert(equals != NULL);
Hashmap* map = malloc(sizeof(Hashmap));
if (map == NULL) {
return NULL;
}
// 0.75 load factor.
size_t minimumBucketCount = initialCapacity * 4 / 3;
map->bucketCount = 1;
while (map->bucketCount <= minimumBucketCount) {
// Bucket count must be power of 2.
map->bucketCount <<= 1;
}
map->buckets = calloc(map->bucketCount, sizeof(Entry*));
if (map->buckets == NULL) {
free(map);
return NULL;
}
map->size = 0;
map->hash = hash;
map->equals = equals;
mutex_init(&map->lock);
return map;
}
/**
* Hashes the given key.
*/
static inline int hashKey(Hashmap* map, void* key) {
int h = map->hash(key);
// We apply this secondary hashing discovered by Doug Lea to defend
// against bad hashes.
h += ~(h << 9);
h ^= (((unsigned int) h) >> 14);
h += (h << 4);
h ^= (((unsigned int) h) >> 10);
return h;
}
size_t hashmapSize(Hashmap* map) {
return map->size;
}
static inline size_t calculateIndex(size_t bucketCount, int hash) {
return ((size_t) hash) & (bucketCount - 1);
}
static void expandIfNecessary(Hashmap* map) {
// If the load factor exceeds 0.75...
if (map->size > (map->bucketCount * 3 / 4)) {
// Start off with a 0.33 load factor.
size_t newBucketCount = map->bucketCount << 1;
Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*));
if (newBuckets == NULL) {
// Abort expansion.
return;
}
// Move over existing entries.
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
while (entry != NULL) {
Entry* next = entry->next;
size_t index = calculateIndex(newBucketCount, entry->hash);
entry->next = newBuckets[index];
newBuckets[index] = entry;
entry = next;
}
}
// Copy over internals.
free(map->buckets);
map->buckets = newBuckets;
map->bucketCount = newBucketCount;
}
}
void hashmapLock(Hashmap* map) {
mutex_lock(&map->lock);
}
void hashmapUnlock(Hashmap* map) {
mutex_unlock(&map->lock);
}
void hashmapFree(Hashmap* map) {
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
while (entry != NULL) {
Entry* next = entry->next;
free(entry);
entry = next;
}
}
free(map->buckets);
mutex_destroy(&map->lock);
free(map);
}
int hashmapHash(void* key, size_t keySize) {
int h = keySize;
char* data = (char*) key;
size_t i;
for (i = 0; i < keySize; i++) {
h = h * 31 + *data;
data++;
}
return h;
}
static Entry* createEntry(void* key, int hash, void* value) {
Entry* entry = malloc(sizeof(Entry));
if (entry == NULL) {
return NULL;
}
entry->key = key;
entry->hash = hash;
entry->value = value;
entry->next = NULL;
return entry;
}
static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
bool (*equals)(void*, void*)) {
if (keyA == keyB) {
return true;
}
if (hashA != hashB) {
return false;
}
return equals(keyA, keyB);
}
void* hashmapPut(Hashmap* map, void* key, void* value) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
Entry** p = &(map->buckets[index]);
while (true) {
Entry* current = *p;
// Add a new entry.
if (current == NULL) {
*p = createEntry(key, hash, value);
if (*p == NULL) {
errno = ENOMEM;
return NULL;
}
map->size++;
expandIfNecessary(map);
return NULL;
}
// Replace existing entry.
if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
void* oldValue = current->value;
current->value = value;
return oldValue;
}
// Move to next entry.
p = &current->next;
}
}
void* hashmapGet(Hashmap* map, void* key) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
Entry* entry = map->buckets[index];
while (entry != NULL) {
if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
return entry->value;
}
entry = entry->next;
}
return NULL;
}
bool hashmapContainsKey(Hashmap* map, void* key) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
Entry* entry = map->buckets[index];
while (entry != NULL) {
if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
return true;
}
entry = entry->next;
}
return false;
}
void* hashmapMemoize(Hashmap* map, void* key,
void* (*initialValue)(void* key, void* context), void* context) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
Entry** p = &(map->buckets[index]);
while (true) {
Entry* current = *p;
// Add a new entry.
if (current == NULL) {
*p = createEntry(key, hash, NULL);
if (*p == NULL) {
errno = ENOMEM;
return NULL;
}
void* value = initialValue(key, context);
(*p)->value = value;
map->size++;
expandIfNecessary(map);
return value;
}
// Return existing value.
if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
return current->value;
}
// Move to next entry.
p = &current->next;
}
}
void* hashmapRemove(Hashmap* map, void* key) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
// Pointer to the current entry.
Entry** p = &(map->buckets[index]);
Entry* current;
while ((current = *p) != NULL) {
if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
void* value = current->value;
*p = current->next;
free(current);
map->size--;
return value;
}
p = &current->next;
}
return NULL;
}
void hashmapForEach(Hashmap* map,
bool (*callback)(void* key, void* value, void* context),
void* context) {
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
while (entry != NULL) {
if (!callback(entry->key, entry->value, context)) {
return;
}
entry = entry->next;
}
}
}
size_t hashmapCurrentCapacity(Hashmap* map) {
size_t bucketCount = map->bucketCount;
return bucketCount * 3 / 4;
}
size_t hashmapCountCollisions(Hashmap* map) {
size_t collisions = 0;
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
while (entry != NULL) {
if (entry->next != NULL) {
collisions++;
}
entry = entry->next;
}
}
return collisions;
}
int hashmapIntHash(void* key) {
// Return the key value itself.
return *((int*) key);
}
bool hashmapIntEquals(void* keyA, void* keyB) {
int a = *((int*) keyA);
int b = *((int*) keyB);
return a == b;
}
+67
View File
@@ -0,0 +1,67 @@
/* libs/cutils/iosched_policy.c
**
** Copyright 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_SCHED_H
#include <cutils/iosched_policy.h>
extern int ioprio_set(int which, int who, int ioprio);
enum {
WHO_PROCESS = 1,
WHO_PGRP,
WHO_USER,
};
#define CLASS_SHIFT 13
#define IOPRIO_NORM 4
int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) {
#ifdef HAVE_ANDROID_OS
if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
return -1;
}
#endif
return 0;
}
int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) {
#ifdef HAVE_ANDROID_OS
int rc;
if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
return -1;
}
*clazz = (rc >> CLASS_SHIFT);
*ioprio = (rc & 0xff);
#else
*clazz = IoSchedClass_NONE;
*ioprio = 0;
#endif
return 0;
}
#endif /* HAVE_SCHED_H */
+10
View File
@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: cutils
Description: cutils library
Version: @VERSION@
Libs: -L${libdir} -lcutils
Cflags: -I${includedir}
+51
View File
@@ -0,0 +1,51 @@
/* libs/cutils/load_file.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 <fcntl.h>
void *load_file(const char *fn, unsigned *_sz)
{
char *data;
int sz;
int fd;
data = 0;
fd = open(fn, O_RDONLY);
if(fd < 0) return 0;
sz = lseek(fd, 0, SEEK_END);
if(sz < 0) goto oops;
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
data = (char*) malloc(sz + 1);
if(data == 0) goto oops;
if(read(fd, data, sz) != sz) goto oops;
close(fd);
data[sz] = 0;
if(_sz) *_sz = sz;
return data;
oops:
close(fd);
if(data != 0) free(data);
return 0;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* 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.
*/
/**
* This is a temporary hack to enable logging from cutils.
*/
#ifndef _CUTILS_LOGHACK_H
#define _CUTILS_LOGHACK_H
#ifdef HAVE_ANDROID_OS
#include <cutils/log.h>
#else
#include <stdio.h>
#define LOG(level, ...) \
((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
#define LOGV(...) LOG("V", __VA_ARGS__)
#define LOGD(...) LOG("D", __VA_ARGS__)
#define LOGI(...) LOG("I", __VA_ARGS__)
#define LOGW(...) LOG("W", __VA_ARGS__)
#define LOGE(...) LOG("E", __VA_ARGS__)
#define LOG_ALWAYS_FATAL(...) do { LOGE(__VA_ARGS__); exit(1); } while (0)
#endif
#endif // _CUTILS_LOGHACK_H
+89
View File
@@ -0,0 +1,89 @@
/*
* 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/memory.h>
#if !HAVE_ASM_MEMSET
void android_memset16(uint16_t* dst, uint16_t value, size_t size)
{
size >>= 1;
while (size--) {
*dst++ = value;
}
}
void android_memset32(uint32_t* dst, uint32_t value, size_t size)
{
size >>= 2;
while (size--) {
*dst++ = value;
}
}
#endif
#if !HAVE_STRLCPY
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/* Implementation of strlcpy() for platforms that don't already have it. */
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif
+93
View File
@@ -0,0 +1,93 @@
/*
* 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.
*/
/*
* memset32.S
*
*/
.text
.align
.global android_memset32
.type android_memset32, %function
.global android_memset16
.type android_memset16, %function
/*
* Optimized memset32 and memset16 for ARM.
*
* void android_memset16(uint16_t* dst, uint16_t value, size_t size);
* void android_memset32(uint32_t* dst, uint32_t value, size_t size);
*
*/
android_memset16:
.fnstart
cmp r2, #1
bxle lr
/* expand the data to 32 bits */
mov r1, r1, lsl #16
orr r1, r1, r1, lsr #16
/* align to 32 bits */
tst r0, #2
strneh r1, [r0], #2
subne r2, r2, #2
.fnend
android_memset32:
.fnstart
.save {lr}
str lr, [sp, #-4]!
/* align the destination to a cache-line */
mov r12, r1
mov lr, r1
rsb r3, r0, #0
ands r3, r3, #0x1C
beq .Laligned32
cmp r3, r2
andhi r3, r2, #0x1C
sub r2, r2, r3
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
stmcsia r0!, {r1, lr}
stmcsia r0!, {r1, lr}
stmmiia r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
.Laligned32:
mov r3, r1
1: subs r2, r2, #32
stmhsia r0!, {r1,r3,r12,lr}
stmhsia r0!, {r1,r3,r12,lr}
bhs 1b
add r2, r2, #32
/* conditionally stores 0 to 30 bytes */
movs r2, r2, lsl #28
stmcsia r0!, {r1,r3,r12,lr}
stmmiia r0!, {r1,lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
strmih lr, [r0], #2
ldr lr, [sp], #4
bx lr
.fnend
File diff suppressed because it is too large Load Diff
+288
View File
@@ -0,0 +1,288 @@
/* Copyright 2006 The Android Open Source Project */
/* A wrapper file for dlmalloc.c that compiles in the
* mspace_*() functions, which provide an interface for
* creating multiple heaps.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <cutils/ashmem.h>
/* It's a pain getting the mallinfo stuff to work
* with Linux, OSX, and klibc, so just turn it off
* for now.
* TODO: make mallinfo work
*/
#define NO_MALLINFO 1
/* Allow setting the maximum heap footprint.
*/
#define USE_MAX_ALLOWED_FOOTPRINT 1
/* Don't try to trim memory.
* TODO: support this.
*/
#define MORECORE_CANNOT_TRIM 1
/* Use mmap()d anonymous memory to guarantee
* that an mspace is contiguous.
*
* create_mspace() won't work right if this is
* defined, so hide the definition of it and
* break any users at build time.
*/
#define USE_CONTIGUOUS_MSPACES 1
#if USE_CONTIGUOUS_MSPACES
/* This combination of settings forces sys_alloc()
* to always use MORECORE(). It won't expect the
* results to be contiguous, but we'll guarantee
* that they are.
*/
#define HAVE_MMAP 0
#define HAVE_MORECORE 1
#define MORECORE_CONTIGUOUS 0
/* m is always the appropriate local when MORECORE() is called. */
#define MORECORE(S) contiguous_mspace_morecore(m, S)
#define create_mspace HIDDEN_create_mspace_HIDDEN
#define destroy_mspace HIDDEN_destroy_mspace_HIDDEN
typedef struct malloc_state *mstate0;
static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb);
#endif
#define MSPACES 1
#define ONLY_MSPACES 1
#if !LINUX_ENABLED
#include "../../../bionic/libc/bionic/dlmalloc.c"
#ifndef PAGESIZE
#define PAGESIZE mparams.page_size
#endif
#define ALIGN_UP(p, alignment) \
(((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1))
/* A direct copy of dlmalloc_usable_size(),
* which isn't compiled in when ONLY_MSPACES is set.
* The mspace parameter isn't actually necessary,
* but we include it to be consistent with the
* rest of the mspace_*() functions.
*/
size_t mspace_usable_size(mspace _unused, const void* mem) {
if (mem != 0) {
const mchunkptr p = mem2chunk(mem);
if (cinuse(p))
return chunksize(p) - overhead_for(p);
}
return 0;
}
#if USE_CONTIGUOUS_MSPACES
#include <sys/mman.h>
#include <limits.h>
#define CONTIG_STATE_MAGIC 0xf00dd00d
struct mspace_contig_state {
unsigned int magic;
char *brk;
char *top;
mspace m;
};
static void *contiguous_mspace_morecore(mstate m, ssize_t nb) {
struct mspace_contig_state *cs;
char *oldbrk;
const unsigned int pagesize = PAGESIZE;
cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1));
assert(cs->magic == CONTIG_STATE_MAGIC);
assert(cs->m == m);
assert(nb >= 0); //xxx deal with the trim case
oldbrk = cs->brk;
if (nb > 0) {
/* Break to the first page boundary that satisfies the request.
*/
char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize);
if (newbrk > cs->top)
return CMFAIL;
/* Update the protection on the underlying memory.
* Pages we've given to dlmalloc are read/write, and
* pages we haven't are not accessable (read or write
* will cause a seg fault).
*/
if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0)
return CMFAIL;
if (newbrk != cs->top) {
if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0)
return CMFAIL;
}
cs->brk = newbrk;
/* Make sure that dlmalloc will merge this block with the
* initial block that was passed to create_mspace_with_base().
* We don't care about extern vs. non-extern, so just clear it.
*/
m->seg.sflags &= ~EXTERN_BIT;
}
return oldbrk;
}
mspace create_contiguous_mspace_with_base(size_t starting_capacity,
size_t max_capacity, int locked, void *base) {
struct mspace_contig_state *cs;
unsigned int pagesize;
mstate m;
init_mparams();
pagesize = PAGESIZE;
assert(starting_capacity <= max_capacity);
assert(((uintptr_t)base & (pagesize-1)) == 0);
assert(((uintptr_t)max_capacity & (pagesize-1)) == 0);
starting_capacity = (size_t)ALIGN_UP(starting_capacity, pagesize);
/* Make the first page read/write. dlmalloc needs to use that page.
*/
if (mprotect(base, starting_capacity, PROT_READ | PROT_WRITE) < 0) {
goto error;
}
/* Create the mspace, pointing to the memory given.
*/
m = create_mspace_with_base((char *)base + sizeof(*cs), starting_capacity,
locked);
if (m == (mspace)0) {
goto error;
}
/* Make sure that m is in the same page as base.
*/
assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base);
/* Use some space for the information that our MORECORE needs.
*/
cs = (struct mspace_contig_state *)base;
/* Find out exactly how much of the memory the mspace
* is using.
*/
cs->brk = m->seg.base + m->seg.size;
cs->top = (char *)base + max_capacity;
assert((char *)base <= cs->brk);
assert(cs->brk <= cs->top);
/* Prevent access to the memory we haven't handed out yet.
*/
if (cs->brk != cs->top) {
/* mprotect() requires page-aligned arguments, but it's possible
* for cs->brk not to be page-aligned at this point.
*/
char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize);
if ((mprotect(base, prot_brk - (char *)base, PROT_READ | PROT_WRITE) < 0) ||
(mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0)) {
goto error;
}
}
cs->m = m;
cs->magic = CONTIG_STATE_MAGIC;
return (mspace)m;
error:
return (mspace)0;
}
mspace create_contiguous_mspace_with_name(size_t starting_capacity,
size_t max_capacity, int locked, char const *name) {
int fd, ret;
char buf[ASHMEM_NAME_LEN] = "mspace";
void *base;
unsigned int pagesize;
mstate m;
if (starting_capacity > max_capacity)
return (mspace)0;
init_mparams();
pagesize = PAGESIZE;
/* Create the anonymous memory that will back the mspace.
* This reserves all of the virtual address space we could
* ever need. Physical pages will be mapped as the memory
* is touched.
*
* Align max_capacity to a whole page.
*/
max_capacity = (size_t)ALIGN_UP(max_capacity, pagesize);
if (name)
snprintf(buf, sizeof(buf), "mspace/%s", name);
fd = ashmem_create_region(buf, max_capacity);
if (fd < 0)
return (mspace)0;
base = mmap(NULL, max_capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
if (base == MAP_FAILED)
return (mspace)0;
/* Make sure that base is at the beginning of a page.
*/
assert(((uintptr_t)base & (pagesize-1)) == 0);
m = create_contiguous_mspace_with_base(starting_capacity, max_capacity,
locked, base);
if (m == 0) {
munmap(base, max_capacity);
}
return m;
}
mspace create_contiguous_mspace(size_t starting_capacity,
size_t max_capacity, int locked) {
return create_contiguous_mspace_with_name(starting_capacity,
max_capacity, locked, NULL);
}
size_t destroy_contiguous_mspace(mspace msp) {
mstate ms = (mstate)msp;
if (ok_magic(ms)) {
struct mspace_contig_state *cs;
size_t length;
const unsigned int pagesize = PAGESIZE;
cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
assert(cs->magic == CONTIG_STATE_MAGIC);
assert(cs->m == ms);
length = cs->top - (char *)cs;
if (munmap((char *)cs, length) != 0)
return length;
}
else {
USAGE_ERROR_ACTION(ms, ms);
}
return 0;
}
void *contiguous_mspace_sbrk0(mspace msp) {
struct mspace_contig_state *cs;
mstate ms;
const unsigned int pagesize = PAGESIZE;
ms = (mstate)msp;
cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1));
assert(cs->magic == CONTIG_STATE_MAGIC);
assert(cs->m == ms);
return cs->brk;
}
#endif /* !LINUX_ENABLED */
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
* 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 "NativeHandle"
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <cutils/log.h>
#include <cutils/native_handle.h>
native_handle_t* native_handle_create(int numFds, int numInts)
{
native_handle_t* h = malloc(
sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));
h->version = sizeof(native_handle_t);
h->numFds = numFds;
h->numInts = numInts;
return h;
}
int native_handle_delete(native_handle_t* h)
{
if (h) {
if (h->version != sizeof(native_handle_t))
return -EINVAL;
free(h);
}
return 0;
}
int native_handle_close(const native_handle_t* h)
{
if (h->version != sizeof(native_handle_t))
return -EINVAL;
const int numFds = h->numFds;
int i;
for (i=0 ; i<numFds ; i++) {
close(h->data[i]);
}
return 0;
}
+381
View File
@@ -0,0 +1,381 @@
/*
* Copyright (C) 2010 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 HAVE_OPEN_MEMSTREAM
/*
* Implementation of the POSIX open_memstream() function, which Linux has
* but BSD lacks.
*
* Summary:
* - Works like a file-backed FILE* opened with fopen(name, "w"), but the
* backing is a chunk of memory rather than a file.
* - The buffer expands as you write more data. Seeking past the end
* of the file and then writing to it zero-fills the gap.
* - The values at "*bufp" and "*sizep" should be considered read-only,
* and are only valid immediately after an fflush() or fclose().
* - A '\0' is maintained just past the end of the file. This is not included
* in "*sizep". (The behavior w.r.t. fseek() is not clearly defined.
* The spec says the null byte is written when a write() advances EOF,
* but it looks like glibc ensures the null byte is always found at EOF,
* even if you just seeked backwards. The example on the opengroup.org
* page suggests that this is the expected behavior. The null must be
* present after a no-op fflush(), which we can't see, so we have to save
* and restore it. Annoying, but allows file truncation.)
* - After fclose(), the caller must eventually free(*bufp).
*
* This is built out of funopen(), which BSD has but Linux lacks. There is
* no flush() operator, so we need to keep the user pointers up to date
* after each operation.
*
* I don't think Windows has any of the above, but we don't need to use
* them there, so we just supply a stub.
*/
#include <cutils/open_memstream.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#if 0
# define DBUG(x) printf x
#else
# define DBUG(x) ((void)0)
#endif
#ifdef HAVE_FUNOPEN
/*
* Definition of a seekable, write-only memory stream.
*/
typedef struct {
char** bufp; /* pointer to buffer pointer */
size_t* sizep; /* pointer to eof */
size_t allocSize; /* size of buffer */
size_t eof; /* furthest point we've written to */
size_t offset; /* current write offset */
char saved; /* required by NUL handling */
} MemStream;
#define kInitialSize 1024
/*
* Ensure that we have enough storage to write "size" bytes at the
* current offset. We also have to take into account the extra '\0'
* that we maintain just past EOF.
*
* Returns 0 on success.
*/
static int ensureCapacity(MemStream* stream, int writeSize)
{
DBUG(("+++ ensureCap off=%d size=%d\n", stream->offset, writeSize));
size_t neededSize = stream->offset + writeSize + 1;
if (neededSize <= stream->allocSize)
return 0;
size_t newSize;
if (stream->allocSize == 0) {
newSize = kInitialSize;
} else {
newSize = stream->allocSize;
newSize += newSize / 2; /* expand by 3/2 */
}
if (newSize < neededSize)
newSize = neededSize;
DBUG(("+++ realloc %p->%p to size=%d\n",
stream->bufp, *stream->bufp, newSize));
char* newBuf = (char*) realloc(*stream->bufp, newSize);
if (newBuf == NULL)
return -1;
*stream->bufp = newBuf;
stream->allocSize = newSize;
return 0;
}
/*
* Write data to a memstream, expanding the buffer if necessary.
*
* If we previously seeked beyond EOF, zero-fill the gap.
*
* Returns the number of bytes written.
*/
static int write_memstream(void* cookie, const char* buf, int size)
{
MemStream* stream = (MemStream*) cookie;
if (ensureCapacity(stream, size) < 0)
return -1;
/* seeked past EOF earlier? */
if (stream->eof < stream->offset) {
DBUG(("+++ zero-fill gap from %d to %d\n",
stream->eof, stream->offset-1));
memset(*stream->bufp + stream->eof, '\0',
stream->offset - stream->eof);
}
/* copy data, advance write pointer */
memcpy(*stream->bufp + stream->offset, buf, size);
stream->offset += size;
if (stream->offset > stream->eof) {
/* EOF has advanced, update it and append null byte */
DBUG(("+++ EOF advanced to %d, appending nul\n", stream->offset));
assert(stream->offset < stream->allocSize);
stream->eof = stream->offset;
} else {
/* within previously-written area; save char we're about to stomp */
DBUG(("+++ within written area, saving '%c' at %d\n",
*(*stream->bufp + stream->offset), stream->offset));
stream->saved = *(*stream->bufp + stream->offset);
}
*(*stream->bufp + stream->offset) = '\0';
*stream->sizep = stream->offset;
return size;
}
/*
* Seek within a memstream.
*
* Returns the new offset, or -1 on failure.
*/
static fpos_t seek_memstream(void* cookie, fpos_t offset, int whence)
{
MemStream* stream = (MemStream*) cookie;
off_t newPosn = (off_t) offset;
if (whence == SEEK_CUR) {
newPosn += stream->offset;
} else if (whence == SEEK_END) {
newPosn += stream->eof;
}
if (newPosn < 0 || ((fpos_t)((size_t) newPosn)) != newPosn) {
/* bad offset - negative or huge */
DBUG(("+++ bogus seek offset %ld\n", (long) newPosn));
errno = EINVAL;
return (fpos_t) -1;
}
if (stream->offset < stream->eof) {
/*
* We were pointing to an area we'd already written to, which means
* we stomped on a character and must now restore it.
*/
DBUG(("+++ restoring char '%c' at %d\n",
stream->saved, stream->offset));
*(*stream->bufp + stream->offset) = stream->saved;
}
stream->offset = (size_t) newPosn;
if (stream->offset < stream->eof) {
/*
* We're seeked backward into the stream. Preserve the character
* at EOF and stomp it with a NUL.
*/
stream->saved = *(*stream->bufp + stream->offset);
*(*stream->bufp + stream->offset) = '\0';
*stream->sizep = stream->offset;
} else {
/*
* We're positioned at, or possibly beyond, the EOF. We want to
* publish the current EOF, not the current position.
*/
*stream->sizep = stream->eof;
}
return newPosn;
}
/*
* Close the memstream. We free everything but the data buffer.
*/
static int close_memstream(void* cookie)
{
free(cookie);
return 0;
}
/*
* Prepare a memstream.
*/
FILE* open_memstream(char** bufp, size_t* sizep)
{
FILE* fp;
MemStream* stream;
if (bufp == NULL || sizep == NULL) {
errno = EINVAL;
return NULL;
}
stream = (MemStream*) calloc(1, sizeof(MemStream));
if (stream == NULL)
return NULL;
fp = funopen(stream,
NULL, write_memstream, seek_memstream, close_memstream);
if (fp == NULL) {
free(stream);
return NULL;
}
*sizep = 0;
*bufp = NULL;
stream->bufp = bufp;
stream->sizep = sizep;
return fp;
}
#else /*not HAVE_FUNOPEN*/
FILE* open_memstream(char** bufp, size_t* sizep)
{
abort();
}
#endif /*HAVE_FUNOPEN*/
#if 0
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Simple regression test.
*
* To test on desktop Linux with valgrind, it's possible to make a simple
* change to open_memstream() to use fopencookie instead:
*
* cookie_io_functions_t iofuncs =
* { NULL, write_memstream, seek_memstream, close_memstream };
* fp = fopencookie(stream, "w", iofuncs);
*
* (Some tweaks to seek_memstream are also required, as that takes a
* pointer to an offset rather than an offset, and returns 0 or -1.)
*/
int testMemStream(void)
{
FILE *stream;
char *buf;
size_t len;
off_t eob;
printf("Test1\n");
/* std example */
stream = open_memstream(&buf, &len);
fprintf(stream, "hello my world");
fflush(stream);
printf("buf=%s, len=%zu\n", buf, len);
eob = ftello(stream);
fseeko(stream, 0, SEEK_SET);
fprintf(stream, "good-bye");
fseeko(stream, eob, SEEK_SET);
fclose(stream);
printf("buf=%s, len=%zu\n", buf, len);
free(buf);
printf("Test2\n");
/* std example without final seek-to-end */
stream = open_memstream(&buf, &len);
fprintf(stream, "hello my world");
fflush(stream);
printf("buf=%s, len=%zu\n", buf, len);
eob = ftello(stream);
fseeko(stream, 0, SEEK_SET);
fprintf(stream, "good-bye");
//fseeko(stream, eob, SEEK_SET);
fclose(stream);
printf("buf=%s, len=%zu\n", buf, len);
free(buf);
printf("Test3\n");
/* fancy example; should expand buffer with writes */
static const int kCmpLen = 1024 + 128;
char* cmp = malloc(kCmpLen);
memset(cmp, 0, 1024);
memset(cmp+1024, 0xff, kCmpLen-1024);
sprintf(cmp, "This-is-a-tes1234");
sprintf(cmp + 1022, "abcdef");
stream = open_memstream (&buf, &len);
setvbuf(stream, NULL, _IONBF, 0); /* note: crashes in glibc with this */
fprintf(stream, "This-is-a-test");
fseek(stream, -1, SEEK_CUR); /* broken in glibc; can use {13,SEEK_SET} */
fprintf(stream, "1234");
fseek(stream, 1022, SEEK_SET);
fputc('a', stream);
fputc('b', stream);
fputc('c', stream);
fputc('d', stream);
fputc('e', stream);
fputc('f', stream);
fflush(stream);
if (memcmp(buf, cmp, len+1) != 0) {
printf("mismatch\n");
} else {
printf("match\n");
}
printf("Test4\n");
stream = open_memstream (&buf, &len);
fseek(stream, 5000, SEEK_SET);
fseek(stream, 4096, SEEK_SET);
fseek(stream, -1, SEEK_SET); /* should have no effect */
fputc('x', stream);
if (ftell(stream) == 4097)
printf("good\n");
else
printf("BAD: offset is %ld\n", ftell(stream));
printf("DONE\n");
return 0;
}
/* expected output:
Test1
buf=hello my world, len=14
buf=good-bye world, len=14
Test2
buf=hello my world, len=14
buf=good-bye, len=8
Test3
match
Test4
good
DONE
*/
#endif
#endif /*!HAVE_OPEN_MEMSTREAM*/
+368
View File
@@ -0,0 +1,368 @@
#ifndef PRIVATE_H
#define PRIVATE_H
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/
/*
** This header is for use ONLY with the time conversion code.
** There is no guarantee that it will remain unchanged,
** or that it will remain at all.
** Do NOT copy it to any system include directory.
** Thank you!
*/
/*
** ID
*/
#ifndef lint
#ifndef NOID
static char privatehid[] = "@(#)private.h 8.2";
#endif /* !defined NOID */
#endif /* !defined lint */
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
/*
** Defaults for preprocessor symbols.
** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
*/
#ifndef HAVE_ADJTIME
#define HAVE_ADJTIME 1
#endif /* !defined HAVE_ADJTIME */
#ifndef HAVE_GETTEXT
#define HAVE_GETTEXT 0
#endif /* !defined HAVE_GETTEXT */
#ifndef HAVE_INCOMPATIBLE_CTIME_R
#define HAVE_INCOMPATIBLE_CTIME_R 0
#endif /* !defined INCOMPATIBLE_CTIME_R */
#ifndef HAVE_SETTIMEOFDAY
#define HAVE_SETTIMEOFDAY 3
#endif /* !defined HAVE_SETTIMEOFDAY */
#ifndef HAVE_STRERROR
#define HAVE_STRERROR 1
#endif /* !defined HAVE_STRERROR */
#ifndef HAVE_SYMLINK
#define HAVE_SYMLINK 1
#endif /* !defined HAVE_SYMLINK */
#ifndef HAVE_SYS_STAT_H
#define HAVE_SYS_STAT_H 1
#endif /* !defined HAVE_SYS_STAT_H */
#ifndef HAVE_SYS_WAIT_H
#define HAVE_SYS_WAIT_H 1
#endif /* !defined HAVE_SYS_WAIT_H */
#ifndef HAVE_UNISTD_H
#define HAVE_UNISTD_H 1
#endif /* !defined HAVE_UNISTD_H */
#ifndef HAVE_UTMPX_H
#define HAVE_UTMPX_H 0
#endif /* !defined HAVE_UTMPX_H */
#ifndef LOCALE_HOME
#define LOCALE_HOME "/usr/lib/locale"
#endif /* !defined LOCALE_HOME */
#if HAVE_INCOMPATIBLE_CTIME_R
#define asctime_r _incompatible_asctime_r
#define ctime_r _incompatible_ctime_r
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
/*
** Nested includes
*/
#include "sys/types.h" /* for time_t */
#include "stdio.h"
#include "errno.h"
#include "string.h"
#include "limits.h" /* for CHAR_BIT et al. */
#include "time.h"
#include "stdlib.h"
#if HAVE_GETTEXT
#include "libintl.h"
#endif /* HAVE_GETTEXT */
#if HAVE_SYS_WAIT_H
#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
#endif /* HAVE_SYS_WAIT_H */
#ifndef WIFEXITED
#define WIFEXITED(status) (((status) & 0xff) == 0)
#endif /* !defined WIFEXITED */
#ifndef WEXITSTATUS
#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
#endif /* !defined WEXITSTATUS */
#if HAVE_UNISTD_H
#include "unistd.h" /* for F_OK and R_OK */
#endif /* HAVE_UNISTD_H */
#if !HAVE_UNISTD_H
#ifndef F_OK
#define F_OK 0
#endif /* !defined F_OK */
#ifndef R_OK
#define R_OK 4
#endif /* !defined R_OK */
#endif /* !HAVE_UNISTD_H */
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
/*
** Define HAVE_STDINT_H's default value here, rather than at the
** start, since __GLIBC__'s value depends on previously-included
** files.
** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
*/
#ifndef HAVE_STDINT_H
#define HAVE_STDINT_H \
(199901 <= __STDC_VERSION__ || \
2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
#endif /* !defined HAVE_STDINT_H */
#if HAVE_STDINT_H
#include "stdint.h"
#endif /* !HAVE_STDINT_H */
#ifndef INT_FAST64_MAX
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
#if defined LLONG_MAX || defined __LONG_LONG_MAX__
typedef long long int_fast64_t;
#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
#if (LONG_MAX >> 31) < 0xffffffff
Please use a compiler that supports a 64-bit integer type (or wider);
you may need to compile with "-DHAVE_STDINT_H".
#endif /* (LONG_MAX >> 31) < 0xffffffff */
typedef long int_fast64_t;
#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
#endif /* !defined INT_FAST64_MAX */
#ifndef INT32_MAX
#define INT32_MAX 0x7fffffff
#endif /* !defined INT32_MAX */
#ifndef INT32_MIN
#define INT32_MIN (-1 - INT32_MAX)
#endif /* !defined INT32_MIN */
/*
** Workarounds for compilers/systems.
*/
/*
** If your compiler lacks prototypes, "#define P(x) ()".
*/
#ifndef P
#define P(x) x
#endif /* !defined P */
/*
** SunOS 4.1.1 headers lack EXIT_SUCCESS.
*/
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif /* !defined EXIT_SUCCESS */
/*
** SunOS 4.1.1 headers lack EXIT_FAILURE.
*/
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif /* !defined EXIT_FAILURE */
/*
** SunOS 4.1.1 headers lack FILENAME_MAX.
*/
#ifndef FILENAME_MAX
#ifndef MAXPATHLEN
#ifdef unix
#include "sys/param.h"
#endif /* defined unix */
#endif /* !defined MAXPATHLEN */
#ifdef MAXPATHLEN
#define FILENAME_MAX MAXPATHLEN
#endif /* defined MAXPATHLEN */
#ifndef MAXPATHLEN
#define FILENAME_MAX 1024 /* Pure guesswork */
#endif /* !defined MAXPATHLEN */
#endif /* !defined FILENAME_MAX */
/*
** SunOS 4.1.1 libraries lack remove.
*/
#ifndef remove
extern int unlink P((const char * filename));
#define remove unlink
#endif /* !defined remove */
/*
** Some ancient errno.h implementations don't declare errno.
** But some newer errno.h implementations define it as a macro.
** Fix the former without affecting the latter.
*/
#ifndef errno
extern int errno;
#endif /* !defined errno */
/*
** Some time.h implementations don't declare asctime_r.
** Others might define it as a macro.
** Fix the former without affecting the latter.
*/
#ifndef asctime_r
extern char * asctime_r();
#endif
/*
** Private function declarations.
*/
char * icalloc P((int nelem, int elsize));
char * icatalloc P((char * old, const char * new));
char * icpyalloc P((const char * string));
char * imalloc P((int n));
void * irealloc P((void * pointer, int size));
void icfree P((char * pointer));
void ifree P((char * pointer));
const char * scheck P((const char * string, const char * format));
/*
** Finally, some convenience items.
*/
#ifndef TRUE
#define TRUE 1
#endif /* !defined TRUE */
#ifndef FALSE
#define FALSE 0
#endif /* !defined FALSE */
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
/*
** Since the definition of TYPE_INTEGRAL contains floating point numbers,
** it cannot be used in preprocessor directives.
*/
#ifndef TYPE_INTEGRAL
#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
#endif /* !defined TYPE_INTEGRAL */
#ifndef INT_STRLEN_MAXIMUM
/*
** 302 / 1000 is log10(2.0) rounded up.
** Subtract one for the sign bit if the type is signed;
** add one for integer division truncation;
** add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/*
** INITIALIZE(x)
*/
#ifndef GNUC_or_lint
#ifdef lint
#define GNUC_or_lint
#endif /* defined lint */
#ifndef lint
#ifdef __GNUC__
#define GNUC_or_lint
#endif /* defined __GNUC__ */
#endif /* !defined lint */
#endif /* !defined GNUC_or_lint */
#ifndef INITIALIZE
#ifdef GNUC_or_lint
#define INITIALIZE(x) ((x) = 0)
#endif /* defined GNUC_or_lint */
#ifndef GNUC_or_lint
#define INITIALIZE(x)
#endif /* !defined GNUC_or_lint */
#endif /* !defined INITIALIZE */
/*
** For the benefit of GNU folk...
** `_(MSGID)' uses the current locale's message library string for MSGID.
** The default is to use gettext if available, and use MSGID otherwise.
*/
#ifndef _
#if HAVE_GETTEXT
#define _(msgid) gettext(msgid)
#else /* !HAVE_GETTEXT */
#define _(msgid) msgid
#endif /* !HAVE_GETTEXT */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
#define TZ_DOMAIN "tz"
#endif /* !defined TZ_DOMAIN */
#if HAVE_INCOMPATIBLE_CTIME_R
#undef asctime_r
#undef ctime_r
char *asctime_r P((struct tm const *, char *));
char *ctime_r P((time_t const *, char *));
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
#ifndef YEARSPERREPEAT
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
#endif /* !defined YEARSPERREPEAT */
/*
** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
*/
#ifndef AVGSECSPERYEAR
#define AVGSECSPERYEAR 31556952L
#endif /* !defined AVGSECSPERYEAR */
#ifndef SECSPERREPEAT
#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
#endif /* !defined SECSPERREPEAT */
#ifndef SECSPERREPEAT_BITS
#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
#endif /* !defined SECSPERREPEAT_BITS */
/*
** UNIX was a registered trademark of The Open Group in 2003.
*/
#endif /* !defined PRIVATE_H */
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2008 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 <string.h>
#include <cutils/process_name.h>
#include <cutils/properties.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif
#define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
static const char* process_name = "unknown";
static int running_in_emulator = -1;
void set_process_name(const char* new_name) {
char propBuf[PROPERTY_VALUE_MAX];
if (new_name == NULL) {
return;
}
// We never free the old name. Someone else could be using it.
int len = strlen(new_name);
char* copy = (char*) malloc(len + 1);
strcpy(copy, new_name);
process_name = (const char*) copy;
#if defined(HAVE_PRCTL)
if (len < 16) {
prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
} else {
prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0);
}
#endif
// If we know we are not running in the emulator, then return.
if (running_in_emulator == 0) {
return;
}
// If the "running_in_emulator" variable has not been initialized,
// then do it now.
if (running_in_emulator == -1) {
property_get("ro.kernel.qemu", propBuf, "");
if (propBuf[0] == '1') {
running_in_emulator = 1;
} else {
running_in_emulator = 0;
return;
}
}
// If the emulator was started with the "-trace file" command line option
// then we want to record the process name in the trace even if we are
// not currently tracing instructions (so that we will know the process
// name when we do start tracing instructions). We do not need to execute
// this code if we are just running in the emulator without the "-trace"
// command line option, but we don't know that here and this function
// isn't called frequently enough to bother optimizing that case.
int fd = open(PROCESS_NAME_DEVICE, O_RDWR);
if (fd < 0)
return;
write(fd, process_name, strlen(process_name) + 1);
close(fd);
}
const char* get_process_name(void) {
return process_name;
}
+368
View File
@@ -0,0 +1,368 @@
/*
* 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.
*/
#define LOG_TAG "properties"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <errno.h>
#include <assert.h>
#include <cutils/properties.h>
#include "loghack.h"
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
static int send_prop_msg(prop_msg *msg)
{
int s;
int r;
s = socket_local_client(PROP_SERVICE_NAME,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if(s < 0) return -1;
while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {
if((errno == EINTR) || (errno == EAGAIN)) continue;
break;
}
if(r == sizeof(prop_msg)) {
r = 0;
} else {
r = -1;
}
close(s);
return r;
}
int property_set(const char *key, const char *value)
{
prop_msg msg;
unsigned resp;
if(key == 0) return -1;
if(value == 0) value = "";
if(strlen(key) >= PROP_NAME_MAX) return -1;
if(strlen(value) >= PROP_VALUE_MAX) return -1;
msg.cmd = PROP_MSG_SETPROP;
strcpy((char*) msg.name, key);
strcpy((char*) msg.value, value);
return send_prop_msg(&msg);
}
int property_get(const char *key, char *value, const char *default_value)
{
int len;
len = __system_property_get(key, value);
if(len > 0) {
return len;
}
if(default_value) {
len = strlen(default_value);
memcpy(value, default_value, len + 1);
}
return len;
}
int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
void *cookie)
{
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
const prop_info *pi;
unsigned n;
for(n = 0; (pi = __system_property_find_nth(n)); n++) {
__system_property_read(pi, name, value);
propfn(name, value, cookie);
}
return 0;
}
#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
/*
* The Linux simulator provides a "system property server" that uses IPC
* to set/get/list properties. The file descriptor is shared by all
* threads in the process, so we use a mutex to ensure that requests
* from multiple threads don't get interleaved.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>
static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
static int gPropFd = -1;
/*
* Connect to the properties server.
*
* Returns the socket descriptor on success.
*/
static int connectToServer(const char* fileName)
{
int sock = -1;
int cc;
struct sockaddr_un addr;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
LOGW("UNIX domain socket create failed (errno=%d)\n", errno);
return -1;
}
/* connect to socket; fails if file doesn't exist */
strcpy(addr.sun_path, fileName); // max 108 bytes
addr.sun_family = AF_UNIX;
cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
if (cc < 0) {
// ENOENT means socket file doesn't exist
// ECONNREFUSED means socket exists but nobody is listening
//LOGW("AF_UNIX connect failed for '%s': %s\n",
// fileName, strerror(errno));
close(sock);
return -1;
}
return sock;
}
/*
* Perform one-time initialization.
*/
static void init(void)
{
assert(gPropFd == -1);
gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
if (gPropFd < 0) {
//LOGW("not connected to system property server\n");
} else {
//LOGV("Connected to system property server\n");
}
}
int property_get(const char *key, char *value, const char *default_value)
{
char sendBuf[1+PROPERTY_KEY_MAX];
char recvBuf[1+PROPERTY_VALUE_MAX];
int len = -1;
//LOGV("PROPERTY GET [%s]\n", key);
pthread_once(&gInitOnce, init);
if (gPropFd < 0) {
/* this mimics the behavior of the device implementation */
if (default_value != NULL) {
strcpy(value, default_value);
len = strlen(value);
}
return len;
}
if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
sendBuf[0] = (char) kSystemPropertyGet;
strcpy(sendBuf+1, key);
pthread_mutex_lock(&gPropertyFdLock);
if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
pthread_mutex_unlock(&gPropertyFdLock);
return -1;
}
if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
pthread_mutex_unlock(&gPropertyFdLock);
return -1;
}
pthread_mutex_unlock(&gPropertyFdLock);
/* first byte is 0 if value not defined, 1 if found */
if (recvBuf[0] == 0) {
if (default_value != NULL) {
strcpy(value, default_value);
len = strlen(value);
} else {
/*
* If the value isn't defined, hand back an empty string and
* a zero length, rather than a failure. This seems wrong,
* since you can't tell the difference between "undefined" and
* "defined but empty", but it's what the device does.
*/
value[0] = '\0';
len = 0;
}
} else if (recvBuf[0] == 1) {
strcpy(value, recvBuf+1);
len = strlen(value);
} else {
LOGE("Got strange response to property_get request (%d)\n",
recvBuf[0]);
assert(0);
return -1;
}
//LOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
// recvBuf[0], default_value, len, key, value);
return len;
}
int property_set(const char *key, const char *value)
{
char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
char recvBuf[1];
int result = -1;
//LOGV("PROPERTY SET [%s]: [%s]\n", key, value);
pthread_once(&gInitOnce, init);
if (gPropFd < 0)
return -1;
if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
sendBuf[0] = (char) kSystemPropertySet;
strcpy(sendBuf+1, key);
strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
pthread_mutex_lock(&gPropertyFdLock);
if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
pthread_mutex_unlock(&gPropertyFdLock);
return -1;
}
if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
pthread_mutex_unlock(&gPropertyFdLock);
return -1;
}
pthread_mutex_unlock(&gPropertyFdLock);
if (recvBuf[0] != 1)
return -1;
return 0;
}
int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
void *cookie)
{
//LOGV("PROPERTY LIST\n");
pthread_once(&gInitOnce, init);
if (gPropFd < 0)
return -1;
return 0;
}
#else
/* SUPER-cheesy place-holder implementation for Win32 */
#include <cutils/threads.h>
static mutex_t env_lock = MUTEX_INITIALIZER;
int property_get(const char *key, char *value, const char *default_value)
{
char ename[PROPERTY_KEY_MAX + 6];
char *p;
int len;
len = strlen(key);
if(len >= PROPERTY_KEY_MAX) return -1;
memcpy(ename, "PROP_", 5);
memcpy(ename + 5, key, len + 1);
mutex_lock(&env_lock);
p = getenv(ename);
if(p == 0) p = "";
len = strlen(p);
if(len >= PROPERTY_VALUE_MAX) {
len = PROPERTY_VALUE_MAX - 1;
}
if((len == 0) && default_value) {
len = strlen(default_value);
memcpy(value, default_value, len + 1);
} else {
memcpy(value, p, len);
value[len] = 0;
}
mutex_unlock(&env_lock);
return len;
}
int property_set(const char *key, const char *value)
{
char ename[PROPERTY_KEY_MAX + 6];
char *p;
int len;
int r;
if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
len = strlen(key);
if(len >= PROPERTY_KEY_MAX) return -1;
memcpy(ename, "PROP_", 5);
memcpy(ename + 5, key, len + 1);
mutex_lock(&env_lock);
#ifdef HAVE_MS_C_RUNTIME
{
char temp[256];
snprintf( temp, sizeof(temp), "%s=%s", ename, value);
putenv(temp);
r = 0;
}
#else
r = setenv(ename, value, 1);
#endif
mutex_unlock(&env_lock);
return r;
}
int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
void *cookie)
{
return 0;
}
#endif
+186
View File
@@ -0,0 +1,186 @@
/* 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
//LOGE("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;
}
+277
View File
@@ -0,0 +1,277 @@
/* libs/cutils/sched_policy.c
**
** Copyright 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#define LOG_TAG "SchedPolicy"
#include "cutils/log.h"
#ifdef HAVE_SCHED_H
#ifdef HAVE_PTHREADS
#include <sched.h>
#include <pthread.h>
#include <cutils/sched_policy.h>
#ifndef SCHED_NORMAL
#define SCHED_NORMAL 0
#endif
#ifndef SCHED_BATCH
#define SCHED_BATCH 3
#endif
#define POLICY_DEBUG 0
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
static int __sys_supports_schedgroups = -1;
// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
static int normal_cgroup_fd = -1;
static int bg_cgroup_fd = -1;
/* Add tid to the scheduling group defined by the policy */
static int add_tid_to_cgroup(int tid, SchedPolicy policy)
{
int fd;
if (policy == SP_BACKGROUND) {
fd = bg_cgroup_fd;
} else {
fd = normal_cgroup_fd;
}
if (fd < 0) {
SLOGE("add_tid_to_cgroup failed; background=%d\n",
policy == SP_BACKGROUND ? 1 : 0);
return -1;
}
// specialized itoa -- works for tid > 0
char text[22];
char *end = text + sizeof(text) - 1;
char *ptr = end;
*ptr = '\0';
while (tid > 0) {
*--ptr = '0' + (tid % 10);
tid = tid / 10;
}
if (write(fd, ptr, end - ptr) < 0) {
/*
* If the thread is in the process of exiting,
* don't flag an error
*/
if (errno == ESRCH)
return 0;
SLOGW("add_tid_to_cgroup failed to write '%s' (%s); background=%d\n",
ptr, strerror(errno), policy == SP_BACKGROUND ? 1 : 0);
return -1;
}
return 0;
}
static void __initialize(void) {
char* filename;
if (!access("/dev/cpuctl/tasks", F_OK)) {
__sys_supports_schedgroups = 1;
filename = "/dev/cpuctl/tasks";
normal_cgroup_fd = open(filename, O_WRONLY);
if (normal_cgroup_fd < 0) {
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
}
filename = "/dev/cpuctl/bg_non_interactive/tasks";
bg_cgroup_fd = open(filename, O_WRONLY);
if (bg_cgroup_fd < 0) {
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
}
} else {
__sys_supports_schedgroups = 0;
}
}
/*
* Try to get the scheduler group.
*
* The data from /proc/<pid>/cgroup looks (something) like:
* 2:cpu:/bg_non_interactive
* 1:cpuacct:/
*
* We return the part after the "/", which will be an empty string for
* the default cgroup. If the string is longer than "bufLen", the string
* will be truncated.
*/
static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
{
#ifdef HAVE_ANDROID_OS
char pathBuf[32];
char lineBuf[256];
FILE *fp;
snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
if (!(fp = fopen(pathBuf, "r"))) {
return -1;
}
while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
char *next = lineBuf;
char *subsys;
char *grp;
size_t len;
/* Junk the first field */
if (!strsep(&next, ":")) {
goto out_bad_data;
}
if (!(subsys = strsep(&next, ":"))) {
goto out_bad_data;
}
if (strcmp(subsys, "cpu")) {
/* Not the subsys we're looking for */
continue;
}
if (!(grp = strsep(&next, ":"))) {
goto out_bad_data;
}
grp++; /* Drop the leading '/' */
len = strlen(grp);
grp[len-1] = '\0'; /* Drop the trailing '\n' */
if (bufLen <= len) {
len = bufLen - 1;
}
strncpy(buf, grp, len);
buf[len] = '\0';
fclose(fp);
return 0;
}
SLOGE("Failed to find cpu subsys");
fclose(fp);
return -1;
out_bad_data:
SLOGE("Bad cgroup data {%s}", lineBuf);
fclose(fp);
return -1;
#else
errno = ENOSYS;
return -1;
#endif
}
int get_sched_policy(int tid, SchedPolicy *policy)
{
pthread_once(&the_once, __initialize);
if (__sys_supports_schedgroups) {
char grpBuf[32];
if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
return -1;
if (grpBuf[0] == '\0') {
*policy = SP_FOREGROUND;
} else if (!strcmp(grpBuf, "bg_non_interactive")) {
*policy = SP_BACKGROUND;
} else {
errno = ERANGE;
return -1;
}
} else {
int rc = sched_getscheduler(tid);
if (rc < 0)
return -1;
else if (rc == SCHED_NORMAL)
*policy = SP_FOREGROUND;
else if (rc == SCHED_BATCH)
*policy = SP_BACKGROUND;
else {
errno = ERANGE;
return -1;
}
}
return 0;
}
int set_sched_policy(int tid, SchedPolicy policy)
{
pthread_once(&the_once, __initialize);
#if POLICY_DEBUG
char statfile[64];
char statline[1024];
char thread_name[255];
int fd;
sprintf(statfile, "/proc/%d/stat", tid);
memset(thread_name, 0, sizeof(thread_name));
fd = open(statfile, O_RDONLY);
if (fd >= 0) {
int rc = read(fd, statline, 1023);
close(fd);
statline[rc] = 0;
char *p = statline;
char *q;
for (p = statline; *p != '('; p++);
p++;
for (q = p; *q != ')'; q++);
strncpy(thread_name, p, (q-p));
}
if (policy == SP_BACKGROUND) {
SLOGD("vvv tid %d (%s)", tid, thread_name);
} else if (policy == SP_FOREGROUND) {
SLOGD("^^^ tid %d (%s)", tid, thread_name);
} else {
SLOGD("??? tid %d (%s)", tid, thread_name);
}
#endif
if (__sys_supports_schedgroups) {
if (add_tid_to_cgroup(tid, policy)) {
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
} else {
struct sched_param param;
param.sched_priority = 0;
sched_setscheduler(tid,
(policy == SP_BACKGROUND) ?
SCHED_BATCH : SCHED_NORMAL,
&param);
}
return 0;
}
#endif /* HAVE_PTHREADS */
#endif /* HAVE_SCHED_H */
+263
View File
@@ -0,0 +1,263 @@
/*
* 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) {
LOGI("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) {
LOGI("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));
}
LOGD("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)) {
LOGD("Selecting fd %d for writing...", selectableFd->fd);
inSet = true;
}
if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
LOGD("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)) {
LOGD("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);
LOGD("Entering select().");
// Select file descriptors.
int result = select(selector->maxFd + 1, &selector->readFds,
&selector->writeFds, &selector->exceptFds, NULL);
LOGD("Exiting select().");
setInSelect(selector, false);
if (result == -1) {
// Abort on everything except EINTR.
if (errno == EINTR) {
LOGI("select() interrupted.");
} else {
LOG_ALWAYS_FATAL("select() error: %s",
strerror(errno));
}
} else if (result > 0) {
fireEvents(selector);
}
}
}
@@ -0,0 +1,70 @@
/* libs/cutils/socket_inaddr_any_server.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 <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#endif
#define LISTEN_BACKLOG 4
/* open listen() port on any interface */
int socket_inaddr_any_server(int port, int type)
{
struct sockaddr_in addr;
size_t alen;
int s, n;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, type, 0);
if(s < 0) return -1;
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
if (type == SOCK_STREAM) {
int ret;
ret = listen(s, LISTEN_BACKLOG);
if (ret < 0) {
close(s);
return -1;
}
}
return s;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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.
*/
#ifndef __SOCKET_LOCAL_H
#define __SOCKET_LOCAL_H
#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
/*
* Set up a given sockaddr_un, to have it refer to the given
* name in the given namespace. The namespace must be one
* of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
* <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
* <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
* the pointed at sockaddr_un is filled in and the pointed at
* socklen_t is set to indicate the final length. This function
* will fail if the namespace is invalid (not one of the indicated
* constants) or if the name is too long.
*
* @return 0 on success or -1 on failure
*/
int socket_make_sockaddr_un(const char *name, int namespaceId,
struct sockaddr_un *p_addr, socklen_t *alen);
#endif
+167
View File
@@ -0,0 +1,167 @@
/*
* 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.
*/
#include <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#ifdef HAVE_WINSOCK
int socket_local_client(const char *name, int namespaceId, int type)
{
errno = ENOSYS;
return -1;
}
#else /* !HAVE_WINSOCK */
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/types.h>
#include "socket_local.h"
#define LISTEN_BACKLOG 4
/* Documented in header file. */
int socket_make_sockaddr_un(const char *name, int namespaceId,
struct sockaddr_un *p_addr, socklen_t *alen)
{
memset (p_addr, 0, sizeof (*p_addr));
size_t namelen;
switch (namespaceId) {
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
namelen = strlen(name);
// Test with length +1 for the *initial* '\0'.
if ((namelen + 1) > sizeof(p_addr->sun_path)) {
goto error;
}
/*
* Note: The path in this case is *not* supposed to be
* '\0'-terminated. ("man 7 unix" for the gory details.)
*/
p_addr->sun_path[0] = 0;
memcpy(p_addr->sun_path + 1, name, namelen);
#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
/* this OS doesn't have the Linux abstract namespace */
namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
/* unix_path_max appears to be missing on linux */
if (namelen > sizeof(*p_addr)
- offsetof(struct sockaddr_un, sun_path) - 1) {
goto error;
}
strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
strcat(p_addr->sun_path, name);
#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
break;
case ANDROID_SOCKET_NAMESPACE_RESERVED:
namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
/* unix_path_max appears to be missing on linux */
if (namelen > sizeof(*p_addr)
- offsetof(struct sockaddr_un, sun_path) - 1) {
goto error;
}
strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
strcat(p_addr->sun_path, name);
break;
case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
namelen = strlen(name);
/* unix_path_max appears to be missing on linux */
if (namelen > sizeof(*p_addr)
- offsetof(struct sockaddr_un, sun_path) - 1) {
goto error;
}
strcpy(p_addr->sun_path, name);
break;
default:
// invalid namespace id
return -1;
}
p_addr->sun_family = AF_LOCAL;
*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
return 0;
error:
return -1;
}
/**
* connect to peer named "name" on fd
* returns same fd or -1 on error.
* fd is not closed on error. that's your job.
*
* Used by AndroidSocketImpl
*/
int socket_local_client_connect(int fd, const char *name, int namespaceId,
int type)
{
struct sockaddr_un addr;
socklen_t alen;
size_t namelen;
int err;
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
if (err < 0) {
goto error;
}
if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
goto error;
}
return fd;
error:
return -1;
}
/**
* connect to peer named "name"
* returns fd or -1 on error
*/
int socket_local_client(const char *name, int namespaceId, int type)
{
int s;
s = socket(AF_LOCAL, type, 0);
if(s < 0) return -1;
if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
close(s);
return -1;
}
return s;
}
#endif /* !HAVE_WINSOCK */
+124
View File
@@ -0,0 +1,124 @@
/* libs/cutils/socket_local_server.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 <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#ifdef HAVE_WINSOCK
int socket_local_server(const char *name, int namespaceId, int type)
{
errno = ENOSYS;
return -1;
}
#else /* !HAVE_WINSOCK */
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "socket_local.h"
#define LISTEN_BACKLOG 4
/**
* Binds a pre-created socket(AF_LOCAL) 's' to 'name'
* returns 's' on success, -1 on fail
*
* Does not call listen()
*/
int socket_local_server_bind(int s, const char *name, int namespaceId)
{
struct sockaddr_un addr;
socklen_t alen;
int n;
int err;
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
if (err < 0) {
return -1;
}
/* basically: if this is a filesystem path, unlink first */
#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
if (1) {
#else
if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
|| namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
#endif
/*ignore ENOENT*/
unlink(addr.sun_path);
}
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
if(bind(s, (struct sockaddr *) &addr, alen) < 0) {
return -1;
}
return s;
}
/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem
* namespace
*
* Returns fd on success, -1 on fail
*/
int socket_local_server(const char *name, int namespace, int type)
{
int err;
int s;
s = socket(AF_LOCAL, type, 0);
if (s < 0) return -1;
err = socket_local_server_bind(s, name, namespace);
if (err < 0) {
close(s);
return -1;
}
if (type == SOCK_STREAM) {
int ret;
ret = listen(s, LISTEN_BACKLOG);
if (ret < 0) {
close(s);
return -1;
}
}
return s;
}
#endif /* !HAVE_WINSOCK */
@@ -0,0 +1,59 @@
/* libs/cutils/socket_loopback_client.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 <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#endif
/* Connect to port on the loopback IP interface. type is
* SOCK_STREAM or SOCK_DGRAM.
* return is a file descriptor or -1 on error
*/
int socket_loopback_client(int port, int type)
{
struct sockaddr_in addr;
socklen_t alen;
int s;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
s = socket(AF_INET, type, 0);
if(s < 0) return -1;
if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
@@ -0,0 +1,71 @@
/* libs/cutils/socket_loopback_server.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 <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#define LISTEN_BACKLOG 4
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#endif
/* open listen() port on loopback interface */
int socket_loopback_server(int port, int type)
{
struct sockaddr_in addr;
size_t alen;
int s, n;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
s = socket(AF_INET, type, 0);
if(s < 0) return -1;
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
if (type == SOCK_STREAM) {
int ret;
ret = listen(s, LISTEN_BACKLOG);
if (ret < 0) {
close(s);
return -1;
}
}
return s;
}
@@ -0,0 +1,65 @@
/* libs/cutils/socket_network_client.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 <cutils/sockets.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
/* Connect to port on the IP interface. type is
* SOCK_STREAM or SOCK_DGRAM.
* return is a file descriptor or -1 on error
*/
int socket_network_client(const char *host, int port, int type)
{
struct hostent *hp;
struct sockaddr_in addr;
socklen_t alen;
int s;
hp = gethostbyname(host);
if(hp == 0) return -1;
memset(&addr, 0, sizeof(addr));
addr.sin_family = hp->h_addrtype;
addr.sin_port = htons(port);
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
s = socket(hp->h_addrtype, type, 0);
if(s < 0) return -1;
if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
+168
View File
@@ -0,0 +1,168 @@
/* libs/cutils/strdup16to8.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 <limits.h> /* for SIZE_MAX */
#include <cutils/jstring.h>
#include <assert.h>
#include <stdlib.h>
/**
* Given a UTF-16 string, compute the length of the corresponding UTF-8
* string in bytes.
*/
extern size_t strnlen16to8(const char16_t* utf16Str, size_t len)
{
size_t utf8Len = 0;
/* A small note on integer overflow. The result can
* potentially be as big as 3*len, which will overflow
* for len > SIZE_MAX/3.
*
* Moreover, the result of a strnlen16to8 is typically used
* to allocate a destination buffer to strncpy16to8 which
* requires one more byte to terminate the UTF-8 copy, and
* this is generally done by careless users by incrementing
* the result without checking for integer overflows, e.g.:
*
* dst = malloc(strnlen16to8(utf16,len)+1)
*
* Due to this, the following code will try to detect
* overflows, and never return more than (SIZE_MAX-1)
* when it detects one. A careless user will try to malloc
* SIZE_MAX bytes, which will return NULL which can at least
* be detected appropriately.
*
* As far as I know, this function is only used by strndup16(),
* but better be safe than sorry.
*/
/* Fast path for the usual case where 3*len is < SIZE_MAX-1.
*/
if (len < (SIZE_MAX-1)/3) {
while (len--) {
unsigned int uic = *utf16Str++;
if (uic > 0x07ff)
utf8Len += 3;
else if (uic > 0x7f || uic == 0)
utf8Len += 2;
else
utf8Len++;
}
return utf8Len;
}
/* The slower but paranoid version */
while (len--) {
unsigned int uic = *utf16Str++;
size_t utf8Cur = utf8Len;
if (uic > 0x07ff)
utf8Len += 3;
else if (uic > 0x7f || uic == 0)
utf8Len += 2;
else
utf8Len++;
if (utf8Len < utf8Cur) /* overflow detected */
return SIZE_MAX-1;
}
/* don't return SIZE_MAX to avoid common user bug */
if (utf8Len == SIZE_MAX)
utf8Len = SIZE_MAX-1;
return utf8Len;
}
/**
* Convert a Java-Style UTF-16 string + length to a JNI-Style UTF-8 string.
*
* This basically means: embedded \0's in the UTF-16 string are encoded
* as "0xc0 0x80"
*
* Make sure you allocate "utf8Str" with the result of strlen16to8() + 1,
* not just "len".
*
* Please note, a terminated \0 is always added, so your result will always
* be "strlen16to8() + 1" bytes long.
*/
extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len)
{
char* utf8cur = utf8Str;
/* Note on overflows: We assume the user did check the result of
* strnlen16to8() properly or at a minimum checked the result of
* its malloc(SIZE_MAX) in case of overflow.
*/
while (len--) {
unsigned int uic = *utf16Str++;
if (uic > 0x07ff) {
*utf8cur++ = (uic >> 12) | 0xe0;
*utf8cur++ = ((uic >> 6) & 0x3f) | 0x80;
*utf8cur++ = (uic & 0x3f) | 0x80;
} else if (uic > 0x7f || uic == 0) {
*utf8cur++ = (uic >> 6) | 0xc0;
*utf8cur++ = (uic & 0x3f) | 0x80;
} else {
*utf8cur++ = uic;
if (uic == 0) {
break;
}
}
}
*utf8cur = '\0';
return utf8Str;
}
/**
* Convert a UTF-16 string to UTF-8.
*
*/
char * strndup16to8 (const char16_t* s, size_t n)
{
char* ret;
size_t len;
if (s == NULL) {
return NULL;
}
len = strnlen16to8(s, n);
/* We are paranoid, and we check for SIZE_MAX-1
* too since it is an overflow value for our
* strnlen16to8 implementation.
*/
if (len >= SIZE_MAX-1)
return NULL;
ret = malloc(len + 1);
if (ret == NULL)
return NULL;
strncpy16to8 (ret, s, n);
return ret;
}
+214
View File
@@ -0,0 +1,214 @@
/* libs/cutils/strdup8to16.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 <cutils/jstring.h>
#include <assert.h>
#include <stdlib.h>
#include <limits.h>
/* See http://www.unicode.org/reports/tr22/ for discussion
* on invalid sequences
*/
#define UTF16_REPLACEMENT_CHAR 0xfffd
/* Clever trick from Dianne that returns 1-4 depending on leading bit sequence*/
#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1)
/* note: macro expands to multiple lines */
#define UTF8_SHIFT_AND_MASK(unicode, byte) \
(unicode)<<=6; (unicode) |= (0x3f & (byte));
#define UNICODE_UPPER_LIMIT 0x10fffd
/**
* out_len is an out parameter (which may not be null) containing the
* length of the UTF-16 string (which may contain embedded \0's)
*/
extern char16_t * strdup8to16 (const char* s, size_t *out_len)
{
char16_t *ret;
size_t len;
if (s == NULL) return NULL;
len = strlen8to16(s);
// fail on overflow
if (len && SIZE_MAX/len < sizeof(char16_t))
return NULL;
// no plus-one here. UTF-16 strings are not null terminated
ret = (char16_t *) malloc (sizeof(char16_t) * len);
return strcpy8to16 (ret, s, out_len);
}
/**
* Like "strlen", but for strings encoded with Java's modified UTF-8.
*
* The value returned is the number of UTF-16 characters required
* to represent this string.
*/
extern size_t strlen8to16 (const char* utf8Str)
{
size_t len = 0;
int ic;
int expected = 0;
while ((ic = *utf8Str++) != '\0') {
/* bytes that start 0? or 11 are lead bytes and count as characters.*/
/* bytes that start 10 are extention bytes and are not counted */
if ((ic & 0xc0) == 0x80) {
/* count the 0x80 extention bytes. if we have more than
* expected, then start counting them because strcpy8to16
* will insert UTF16_REPLACEMENT_CHAR's
*/
expected--;
if (expected < 0) {
len++;
}
} else {
len++;
expected = UTF8_SEQ_LENGTH(ic) - 1;
/* this will result in a surrogate pair */
if (expected == 3) {
len++;
}
}
}
return len;
}
/*
* Retrieve the next UTF-32 character from a UTF-8 string.
*
* Stops at inner \0's
*
* Returns UTF16_REPLACEMENT_CHAR if an invalid sequence is encountered
*
* Advances "*pUtf8Ptr" to the start of the next character.
*/
static inline uint32_t getUtf32FromUtf8(const char** pUtf8Ptr)
{
uint32_t ret;
int seq_len;
int i;
/* Mask for leader byte for lengths 1, 2, 3, and 4 respectively*/
static const char leaderMask[4] = {0xff, 0x1f, 0x0f, 0x07};
/* Bytes that start with bits "10" are not leading characters. */
if (((**pUtf8Ptr) & 0xc0) == 0x80) {
(*pUtf8Ptr)++;
return UTF16_REPLACEMENT_CHAR;
}
/* note we tolerate invalid leader 11111xxx here */
seq_len = UTF8_SEQ_LENGTH(**pUtf8Ptr);
ret = (**pUtf8Ptr) & leaderMask [seq_len - 1];
if (**pUtf8Ptr == '\0') return ret;
(*pUtf8Ptr)++;
for (i = 1; i < seq_len ; i++, (*pUtf8Ptr)++) {
if ((**pUtf8Ptr) == '\0') return UTF16_REPLACEMENT_CHAR;
if (((**pUtf8Ptr) & 0xc0) != 0x80) return UTF16_REPLACEMENT_CHAR;
UTF8_SHIFT_AND_MASK(ret, **pUtf8Ptr);
}
return ret;
}
/**
* out_len is an out parameter (which may not be null) containing the
* length of the UTF-16 string (which may contain embedded \0's)
*/
extern char16_t * strcpy8to16 (char16_t *utf16Str, const char*utf8Str,
size_t *out_len)
{
char16_t *dest = utf16Str;
while (*utf8Str != '\0') {
uint32_t ret;
ret = getUtf32FromUtf8(&utf8Str);
if (ret <= 0xffff) {
*dest++ = (char16_t) ret;
} else if (ret <= UNICODE_UPPER_LIMIT) {
/* Create surrogate pairs */
/* See http://en.wikipedia.org/wiki/UTF-16/UCS-2#Method_for_code_points_in_Plane_1.2C_Plane_2 */
*dest++ = 0xd800 | ((ret - 0x10000) >> 10);
*dest++ = 0xdc00 | ((ret - 0x10000) & 0x3ff);
} else {
*dest++ = UTF16_REPLACEMENT_CHAR;
}
}
*out_len = dest - utf16Str;
return utf16Str;
}
/**
* length is the number of characters in the UTF-8 string.
* out_len is an out parameter (which may not be null) containing the
* length of the UTF-16 string (which may contain embedded \0's)
*/
extern char16_t * strcpylen8to16 (char16_t *utf16Str, const char*utf8Str,
int length, size_t *out_len)
{
/* TODO: Share more of this code with the method above. Only 2 lines changed. */
char16_t *dest = utf16Str;
const char *end = utf8Str + length; /* This line */
while (utf8Str < end) { /* and this line changed. */
uint32_t ret;
ret = getUtf32FromUtf8(&utf8Str);
if (ret <= 0xffff) {
*dest++ = (char16_t) ret;
} else if (ret <= UNICODE_UPPER_LIMIT) {
/* Create surrogate pairs */
/* See http://en.wikipedia.org/wiki/UTF-16/UCS-2#Method_for_code_points_in_Plane_1.2C_Plane_2 */
*dest++ = 0xd800 | ((ret - 0x10000) >> 10);
*dest++ = 0xdc00 | ((ret - 0x10000) & 0x3ff);
} else {
*dest++ = UTF16_REPLACEMENT_CHAR;
}
}
*out_len = dest - utf16Str;
return utf16Str;
}
+84
View File
@@ -0,0 +1,84 @@
/* libs/cutils/threads.c
**
** Copyright (C) 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <cutils/threads.h>
#ifdef HAVE_PTHREADS
void* thread_store_get( thread_store_t* store )
{
const pthread_key_t k = store->tls;
if (!store->has_tls)
return NULL;
return pthread_getspecific( store->tls );
}
extern void thread_store_set( thread_store_t* store,
void* value,
thread_store_destruct_t destroy)
{
pthread_mutex_lock( &store->lock );
if (!store->has_tls) {
if (pthread_key_create( &store->tls, destroy) != 0) {
pthread_mutex_unlock(&store->lock);
return;
}
store->has_tls = 1;
}
pthread_mutex_unlock( &store->lock );
pthread_setspecific( store->tls, value );
}
#endif
#ifdef HAVE_WIN32_THREADS
void* thread_store_get( thread_store_t* store )
{
if (!store->has_tls)
return NULL;
return (void*) TlsGetValue( store->tls );
}
void thread_store_set( thread_store_t* store,
void* value,
thread_store_destruct_t destroy )
{
/* XXX: can't use destructor on thread exit */
if (!store->lock_init) {
store->lock_init = -1;
InitializeCriticalSection( &store->lock );
store->lock_init = -2;
} else while (store->lock_init != -2) {
Sleep(10); /* 10ms */
}
EnterCriticalSection( &store->lock );
if (!store->has_tls) {
store->tls = TlsAlloc();
if (store->tls == TLS_OUT_OF_INDEXES) {
LeaveCriticalSection( &store->lock );
return;
}
store->has_tls = 1;
}
LeaveCriticalSection( &store->lock );
TlsSetValue( store->tls, value );
}
#endif
+180
View File
@@ -0,0 +1,180 @@
#ifndef TZFILE_H
#define TZFILE_H
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/
/*
** This header is for use ONLY with the time conversion code.
** There is no guarantee that it will remain unchanged,
** or that it will remain at all.
** Do NOT copy it to any system include directory.
** Thank you!
*/
/*
** ID
*/
#ifndef lint
#ifndef NOID
static char tzfilehid[] = "@(#)tzfile.h 8.1";
#endif /* !defined NOID */
#endif /* !defined lint */
/*
** Information about time zone files.
*/
#ifndef TZDIR
#define TZDIR "/usr/share/zoneinfo" /* "/android/usr/share/zoneinfo" */ /* Time zone object file directory */
#endif /* !defined TZDIR */
#ifndef TZDEFAULT
#define TZDEFAULT "localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
/*
** Each file begins with. . .
*/
#define TZ_MAGIC "TZif"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' as of 2005 */
char tzh_reserved[15]; /* reserved--must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
char tzh_typecnt[4]; /* coded number of local time types */
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
** tzh_timecnt (char [4])s coded transition times a la time(2)
** tzh_timecnt (unsigned char)s types of local time starting at above
** tzh_typecnt repetitions of
** one (char [4]) coded UTC offset in seconds
** one (unsigned char) used to set tm_isdst
** one (unsigned char) that's an abbreviation list index
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
** time is standard time, if FALSE,
** transition time is wall clock time
** if absent, transition times are
** assumed to be wall clock time
** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
** time is UTC, if FALSE,
** transition time is local time
** if absent, transition times are
** assumed to be local time
*/
/*
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
** then a POSIX-TZ-environment-variable-style string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX representation for
** such instants).
*/
/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
#define TZ_MAX_TIMES 1200
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
#ifndef NOSOLAR
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined NOSOLAR */
#ifdef NOSOLAR
/*
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
** as noted by Earl Chew.
*/
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif /* !defined NOSOLAR */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
/* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_JANUARY 0
#define TM_FEBRUARY 1
#define TM_MARCH 2
#define TM_APRIL 3
#define TM_MAY 4
#define TM_JUNE 5
#define TM_JULY 6
#define TM_AUGUST 7
#define TM_SEPTEMBER 8
#define TM_OCTOBER 9
#define TM_NOVEMBER 10
#define TM_DECEMBER 11
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
/*
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
** isleap(y) == isleap(y % 400)
** and so
** isleap(a + b) == isleap((a + b) % 400)
** or
** isleap(a + b) == isleap(a % 400 + b % 400)
** This is true even if % means modulo rather than Fortran remainder
** (which is allowed by C89 but not C99).
** We use this to avoid addition overflow problems.
*/
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
#endif /* !defined TZFILE_H */
+841
View File
@@ -0,0 +1,841 @@
#ifndef lint
#ifndef NOID
static char elsieid[] = "@(#)strftime.c 8.1";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain character".
*/
#endif /* !defined NOID */
#endif /* !defined lint */
#include <time.h>
#include <tzfile.h>
#include <limits.h>
#include <cutils/tztime.h>
/*
** Copyright (c) 1989 The Regents of the University of California.
** All rights reserved.
**
** Redistribution and use in source and binary forms are permitted
** provided that the above copyright notice and this paragraph are
** duplicated in all such forms and that any documentation,
** advertising materials, and other materials related to such
** distribution and use acknowledge that the software was developed
** by the University of California, Berkeley. The name of the
** University may not be used to endorse or promote products derived
** from this software without specific prior written permission.
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef LIBC_SCCS
#ifndef lint
static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
#endif /* !defined lint */
#endif /* !defined LIBC_SCCS */
#include <ctype.h>
#define P(x) x
static char * _add P((const char *, char *, const char *, int));
static char * _conv P((int, const char *, char *, const char *));
static char * _fmt P((const char *, const struct tm *, char *, const char *,
int *, const struct strftime_locale *Locale));
static char * _yconv P((int, int, int, int, char *, const char *, int));
static char * getformat P((int, char *, char *, char *, char *));
extern char * tzname[];
/* from private.h */
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
#ifndef INT_STRLEN_MAXIMUM
/*
* ** 302 / 1000 is log10(2.0) rounded up.
* ** Subtract one for the sign bit if the type is signed;
* ** add one for integer division truncation;
* ** add one more for a minus sign if the type is signed.
* */
#define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/* end of part from private.h */
#ifndef YEAR_2000_NAME
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */
#define IN_NONE 0
#define IN_SOME 1
#define IN_THIS 2
#define IN_ALL 3
#define FORCE_LOWER_CASE 0x100
size_t
strftime_tz(s, maxsize, format, t, Locale)
char * const s;
const size_t maxsize;
const char * const format;
const struct tm * const t;
const struct strftime_locale *Locale;
{
char * p;
int warn;
warn = IN_NONE;
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
#if 0
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf(stderr, "\n");
if (format == NULL)
(void) fprintf(stderr, "NULL strftime format ");
else (void) fprintf(stderr, "strftime format \"%s\" ",
format);
(void) fprintf(stderr, "yields only two digits of years in ");
if (warn == IN_SOME)
(void) fprintf(stderr, "some locales");
else if (warn == IN_THIS)
(void) fprintf(stderr, "the current locale");
else (void) fprintf(stderr, "all locales");
(void) fprintf(stderr, "\n");
}
#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
return 0;
*p = '\0';
return p - s;
}
static char *getformat(int modifier, char *normal, char *underscore,
char *dash, char *zero) {
switch (modifier) {
case '_':
return underscore;
case '-':
return dash;
case '0':
return zero;
}
return normal;
}
static char *
_fmt(format, t, pt, ptlim, warnp, Locale)
const char * format;
const struct tm * const t;
char * pt;
const char * const ptlim;
int * warnp;
const struct strftime_locale *Locale;
{
for ( ; *format; ++format) {
if (*format == '%') {
int modifier = 0;
label:
switch (*++format) {
case '\0':
--format;
break;
case 'A':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->weekday[t->tm_wday],
pt, ptlim, modifier);
continue;
case 'a':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->wday[t->tm_wday],
pt, ptlim, modifier);
continue;
case 'B':
if (modifier == '-') {
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->standalone_month[t->tm_mon],
pt, ptlim, modifier);
} else {
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->month[t->tm_mon],
pt, ptlim, modifier);
}
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->mon[t->tm_mon],
pt, ptlim, modifier);
continue;
case 'C':
/*
** %C used to do a...
** _fmt("%a %b %e %X %Y", t);
** ...whereas now POSIX 1003.2 calls for
** something completely different.
** (ado, 1993-05-24)
*/
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
pt, ptlim, modifier);
continue;
case 'c':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
continue;
case 'd':
pt = _conv(t->tm_mday,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'E':
case 'O':
/*
** C99 locale modifiers.
** The sequences
** %Ec %EC %Ex %EX %Ey %EY
** %Od %oe %OH %OI %Om %OM
** %OS %Ou %OU %OV %Ow %OW %Oy
** are supposed to provide alternate
** representations.
*/
goto label;
case '_':
case '-':
case '0':
case '^':
case '#':
modifier = *format;
goto label;
case 'e':
pt = _conv(t->tm_mday,
getformat(modifier, "%2d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
continue;
case 'H':
pt = _conv(t->tm_hour,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'j':
pt = _conv(t->tm_yday + 1,
getformat(modifier, "%03d", "%3d", "%d", "%03d"),
pt, ptlim);
continue;
case 'k':
/*
** This used to be...
** _conv(t->tm_hour % 12 ?
** t->tm_hour % 12 : 12, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbins'
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv(t->tm_hour,
getformat(modifier, "%2d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
pt = _add("kitchen sink", pt, ptlim, modifier);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
/*
** This used to be...
** _conv(t->tm_hour, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbin's
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
getformat(modifier, "%2d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'M':
pt = _conv(t->tm_min,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'm':
pt = _conv(t->tm_mon + 1,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'n':
pt = _add("\n", pt, ptlim, modifier);
continue;
case 'p':
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
Locale->pm :
Locale->am,
pt, ptlim, modifier);
continue;
case 'P':
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
Locale->pm :
Locale->am,
pt, ptlim, FORCE_LOWER_CASE);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
continue;
case 'r':
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
continue;
case 'S':
pt = _conv(t->tm_sec,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 's':
{
struct tm tm;
char buf[INT_STRLEN_MAXIMUM(
time_t) + 1];
time_t mkt;
tm = *t;
mkt = mktime(&tm);
if (TYPE_SIGNED(time_t))
(void) sprintf(buf, "%ld",
(long) mkt);
else (void) sprintf(buf, "%lu",
(unsigned long) mkt);
pt = _add(buf, pt, ptlim, modifier);
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
continue;
case 't':
pt = _add("\t", pt, ptlim, modifier);
continue;
case 'U':
pt = _conv((t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'u':
/*
** From Arnold Robbins' strftime version 3.0:
** "ISO 8601: Weekday as a decimal number
** [1 (Monday) - 7]"
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
continue;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
**
** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
** "Week 01 of a year is per definition the first week which has the
** Thursday in this year, which is equivalent to the week which contains
** the fourth day of January. In other words, the first week of a new year
** is the week which has the majority of its days in the new year. Week 01
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
{
int year;
int base;
int yday;
int wday;
int w;
year = t->tm_year;
base = TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int len;
int bot;
int top;
len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
** What yday (-3 ... 3) does
** the ISO year begin on?
*/
bot = ((yday + 11 - wday) %
DAYSPERWEEK) - 3;
/*
** What yday does the NEXT
** ISO year begin on?
*/
top = bot -
(len % DAYSPERWEEK);
if (top < -3)
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
++base;
w = 1;
break;
}
if (yday >= bot) {
w = 1 + ((yday - bot) /
DAYSPERWEEK);
break;
}
--base;
yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
if ((w == 52 &&
t->tm_mon == TM_JANUARY) ||
(w == 1 &&
t->tm_mon == TM_DECEMBER))
w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w,
getformat(modifier,
"%02d",
"%2d",
"%d",
"%02d"),
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = _yconv(year, base, 0, 1,
pt, ptlim, modifier);
} else pt = _yconv(year, base, 1, 1,
pt, ptlim, modifier);
}
continue;
case 'v':
/*
** From Arnold Robbins' strftime version 3.0:
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
(t->tm_wday - 1) :
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
continue;
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
continue;
case 'x':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'y':
*warnp = IN_ALL;
pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
pt, ptlim, modifier);
continue;
case 'Y':
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
pt, ptlim, modifier);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE != NULL)
pt = _add(t->TM_ZONE, pt, ptlim,
modifier);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst >= 0)
pt = _add(tzname[t->tm_isdst != 0],
pt, ptlim, modifier);
/*
** C99 says that %Z must be replaced by the
** empty string if the time zone is not
** determinable.
*/
continue;
case 'z':
{
int diff;
char const * sign;
if (t->tm_isdst < 0)
continue;
#ifdef TM_GMTOFF
diff = t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
/*
** C99 says that the UTC offset must
** be computed by looking only at
** tm_isdst. This requirement is
** incorrect, since it means the code
** must rely on magic (in this case
** altzone and timezone), and the
** magic might not have the correct
** offset. Doing things correctly is
** tricky and requires disobeying C99;
** see GNU C strftime for details.
** For now, punt and conform to the
** standard, even though it's incorrect.
**
** C99 says that %z must be replaced by the
** empty string if the time zone is not
** determinable, so output nothing if the
** appropriate variables are not available.
*/
if (t->tm_isdst == 0)
#ifdef USG_COMPAT
diff = -timezone;
#else /* !defined USG_COMPAT */
continue;
#endif /* !defined USG_COMPAT */
else
#ifdef ALTZONE
diff = -altzone;
#else /* !defined ALTZONE */
continue;
#endif /* !defined ALTZONE */
#endif /* !defined TM_GMTOFF */
if (diff < 0) {
sign = "-";
diff = -diff;
} else sign = "+";
pt = _add(sign, pt, ptlim, modifier);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 +
(diff % MINSPERHOUR);
pt = _conv(diff,
getformat(modifier, "%04d",
"%4d", "%d", "%04d"),
pt, ptlim);
}
continue;
case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp, Locale);
continue;
case '%':
/*
** X311J/88-090 (4.12.3.5): if conversion char is
** undefined, behavior is undefined. Print out the
** character itself as printf(3) also does.
*/
default:
break;
}
}
if (pt == ptlim)
break;
*pt++ = *format;
}
return pt;
}
static char *
_conv(n, format, pt, ptlim)
const int n;
const char * const format;
char * const pt;
const char * const ptlim;
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(void) sprintf(buf, format, n);
return _add(buf, pt, ptlim, 0);
}
static char *
_add(str, pt, ptlim, modifier)
const char * str;
char * pt;
const char * const ptlim;
int modifier;
{
int c;
switch (modifier) {
case FORCE_LOWER_CASE:
while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
++pt;
}
break;
case '^':
while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
++pt;
}
break;
case '#':
while (pt < ptlim && (c = *str++) != '\0') {
if (isupper(c)) {
c = tolower(c);
} else if (islower(c)) {
c = toupper(c);
}
*pt = c;
++pt;
}
break;
default:
while (pt < ptlim && (*pt = *str++) != '\0') {
++pt;
}
}
return pt;
}
/*
** POSIX and the C Standard are unclear or inconsistent about
** what %C and %y do if the year is negative or exceeds 9999.
** Use the convention that %C concatenated with %y yields the
** same output as %Y, and that %Y contains at least 4 bytes,
** with more only if necessary.
*/
static char *
_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
const int a;
const int b;
const int convert_top;
const int convert_yy;
char * pt;
const char * const ptlim;
int modifier;
{
register int lead;
register int trail;
#define DIVISOR 100
trail = a % DIVISOR + b % DIVISOR;
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
trail %= DIVISOR;
if (trail < 0 && lead > 0) {
trail += DIVISOR;
--lead;
} else if (lead < 0 && trail > 0) {
trail -= DIVISOR;
++lead;
}
if (convert_top) {
if (lead == 0 && trail < 0)
pt = _add("-0", pt, ptlim, modifier);
else pt = _conv(lead, getformat(modifier, "%02d",
"%2d", "%d", "%02d"),
pt, ptlim);
}
if (convert_yy)
pt = _conv(((trail < 0) ? -trail : trail),
getformat(modifier, "%02d", "%2d", "%d", "%02d"),
pt, ptlim);
return pt;
}
#ifdef LOCALE_HOME
static struct lc_time_T *
_loc P((void))
{
static const char locale_home[] = LOCALE_HOME;
static const char lc_time[] = "LC_TIME";
static char * locale_buf;
int fd;
int oldsun; /* "...ain't got nothin' to do..." */
char * lbuf;
char * name;
char * p;
const char ** ap;
const char * plim;
char filename[FILENAME_MAX];
struct stat st;
size_t namesize;
size_t bufsize;
/*
** Use localebuf.mon[0] to signal whether locale is already set up.
*/
if (localebuf.mon[0])
return &localebuf;
name = setlocale(LC_TIME, (char *) NULL);
if (name == NULL || *name == '\0')
goto no_locale;
/*
** If the locale name is the same as our cache, use the cache.
*/
lbuf = locale_buf;
if (lbuf != NULL && strcmp(name, lbuf) == 0) {
p = lbuf;
for (ap = (const char **) &localebuf;
ap < (const char **) (&localebuf + 1);
++ap)
*ap = p += strlen(p) + 1;
return &localebuf;
}
/*
** Slurp the locale file into the cache.
*/
namesize = strlen(name) + 1;
if (sizeof filename <
((sizeof locale_home) + namesize + (sizeof lc_time)))
goto no_locale;
oldsun = 0;
(void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
fd = open(filename, O_RDONLY);
if (fd < 0) {
/*
** Old Sun systems have a different naming and data convention.
*/
oldsun = 1;
(void) sprintf(filename, "%s/%s/%s", locale_home,
lc_time, name);
fd = open(filename, O_RDONLY);
if (fd < 0)
goto no_locale;
}
if (fstat(fd, &st) != 0)
goto bad_locale;
if (st.st_size <= 0)
goto bad_locale;
bufsize = namesize + st.st_size;
locale_buf = NULL;
lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
if (lbuf == NULL)
goto bad_locale;
(void) strcpy(lbuf, name);
p = lbuf + namesize;
plim = p + st.st_size;
if (read(fd, p, (size_t) st.st_size) != st.st_size)
goto bad_lbuf;
if (close(fd) != 0)
goto bad_lbuf;
/*
** Parse the locale file into localebuf.
*/
if (plim[-1] != '\n')
goto bad_lbuf;
for (ap = (const char **) &localebuf;
ap < (const char **) (&localebuf + 1);
++ap) {
if (p == plim)
goto bad_lbuf;
*ap = p;
while (*p != '\n')
++p;
*p++ = '\0';
}
if (oldsun) {
/*
** SunOS 4 used an obsolescent format; see localdtconv(3).
** c_fmt had the ``short format for dates and times together''
** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
** date_fmt had the ``long format for dates''
** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
** Discard the latter in favor of the former.
*/
localebuf.date_fmt = localebuf.c_fmt;
}
/*
** Record the successful parse in the cache.
*/
locale_buf = lbuf;
return &localebuf;
bad_lbuf:
free(lbuf);
bad_locale:
(void) close(fd);
no_locale:
localebuf = C_time_locale;
locale_buf = NULL;
return &localebuf;
}
#endif /* defined LOCALE_HOME */
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
/*
* 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 HAVE_SYS_UIO_H
#include <cutils/uio.h>
#include <unistd.h>
int readv( int fd, struct iovec* vecs, int count )
{
int total = 0;
for ( ; count > 0; count--, vecs++ ) {
const char* buf = vecs->iov_base;
int len = vecs->iov_len;
while (len > 0) {
int ret = read( fd, buf, len );
if (ret < 0) {
if (total == 0)
total = -1;
goto Exit;
}
if (ret == 0)
goto Exit;
total += ret;
buf += ret;
len -= ret;
}
}
Exit:
return total;
}
int writev( int fd, const struct iovec* vecs, int count )
{
int total = 0;
for ( ; count > 0; count--, vecs++ ) {
const char* buf = (const char*)vecs->iov_base;
int len = (int)vecs->iov_len;
while (len > 0) {
int ret = write( fd, buf, len );
if (ret < 0) {
if (total == 0)
total = -1;
goto Exit;
}
if (ret == 0)
goto Exit;
total += ret;
buf += ret;
len -= ret;
}
}
Exit:
return total;
}
#endif /* !HAVE_SYS_UIO_H */
+267
View File
@@ -0,0 +1,267 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Zygote"
#include <cutils/sockets.h>
#include <cutils/zygote.h>
#include <cutils/log.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#define ZYGOTE_SOCKET "zygote"
#define ZYGOTE_RETRY_COUNT 1000
#define ZYGOTE_RETRY_MILLIS 500
static void replace_nl(char *str);
/*
* If sendStdio is non-zero, the current process's stdio file descriptors
* will be sent and inherited by the spawned process.
*/
static int send_request(int fd, int sendStdio, int argc, const char **argv)
{
#ifndef HAVE_ANDROID_OS
// not supported on simulator targets
//LOGE("zygote_* not supported on simulator targets");
return -1;
#else /* HAVE_ANDROID_OS */
uint32_t pid;
int i;
struct iovec ivs[2];
struct msghdr msg;
char argc_buffer[12];
const char *newline_string = "\n";
struct cmsghdr *cmsg;
char msgbuf[CMSG_SPACE(sizeof(int) * 3)];
int *cmsg_payload;
ssize_t ret;
memset(&msg, 0, sizeof(msg));
memset(&ivs, 0, sizeof(ivs));
// First line is arg count
snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc);
ivs[0].iov_base = argc_buffer;
ivs[0].iov_len = strlen(argc_buffer);
msg.msg_iov = ivs;
msg.msg_iovlen = 1;
if (sendStdio != 0) {
// Pass the file descriptors with the first write
msg.msg_control = msgbuf;
msg.msg_controllen = sizeof msgbuf;
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg_payload = (int *)CMSG_DATA(cmsg);
cmsg_payload[0] = STDIN_FILENO;
cmsg_payload[1] = STDOUT_FILENO;
cmsg_payload[2] = STDERR_FILENO;
}
do {
ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
return -1;
}
// Only send the fd's once
msg.msg_control = NULL;
msg.msg_controllen = 0;
// replace any newlines with spaces and send the args
for (i = 0; i < argc; i++) {
char *tofree = NULL;
const char *toprint;
toprint = argv[i];
if (strchr(toprint, '\n') != NULL) {
tofree = strdup(toprint);
toprint = tofree;
replace_nl(tofree);
}
ivs[0].iov_base = (char *)toprint;
ivs[0].iov_len = strlen(toprint);
ivs[1].iov_base = (char *)newline_string;
ivs[1].iov_len = 1;
msg.msg_iovlen = 2;
do {
ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
} while (ret < 0 && errno == EINTR);
if (tofree != NULL) {
free(tofree);
}
if (ret < 0) {
return -1;
}
}
// Read the pid, as a 4-byte network-order integer
ivs[0].iov_base = &pid;
ivs[0].iov_len = sizeof(pid);
msg.msg_iovlen = 1;
do {
do {
ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
return -1;
}
ivs[0].iov_len -= ret;
ivs[0].iov_base += ret;
} while (ivs[0].iov_len > 0);
pid = ntohl(pid);
return pid;
#endif /* HAVE_ANDROID_OS */
}
int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int))
{
int fd;
int pid;
int err;
const char *newargv[argc + 1];
fd = socket_local_client(ZYGOTE_SOCKET,
ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL);
if (fd < 0) {
return -1;
}
// The command socket is passed to the peer as close-on-exec
// and will close when the peer dies
newargv[0] = "--peer-wait";
memcpy(newargv + 1, argv, argc * sizeof(*argv));
pid = send_request(fd, 1, argc + 1, newargv);
if (pid > 0 && post_run_func != NULL) {
post_run_func(pid);
}
// Wait for socket to close
do {
int dummy;
err = read(fd, &dummy, sizeof(dummy));
} while ((err < 0 && errno == EINTR) || err != 0);
do {
err = close(fd);
} while (err < 0 && errno == EINTR);
return 0;
}
/**
* Spawns a new dalvik instance via the Zygote process. The non-zygote
* arguments are passed to com.android.internal.os.RuntimeInit(). The
* first non-option argument should be a class name in the system class path.
*
* The arg list may start with zygote params such as --set-uid.
*
* If sendStdio is non-zero, the current process's stdio file descriptors
* will be sent and inherited by the spawned process.
*
* The pid of the child process is returned, or -1 if an error was
* encountered.
*
* zygote_run_oneshot waits up to ZYGOTE_RETRY_COUNT *
* ZYGOTE_RETRY_MILLIS for the zygote socket to be available.
*/
int zygote_run_oneshot(int sendStdio, int argc, const char **argv)
{
int fd = -1;
int err;
int i;
int retries;
int pid;
const char **newargv = argv;
const int newargc = argc;
for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) {
if (retries > 0) {
struct timespec ts;
memset(&ts, 0, sizeof(ts));
ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000;
do {
err = nanosleep (&ts, &ts);
} while (err < 0 && errno == EINTR);
}
fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL,
ANDROID_SOCKET_NAMESPACE_RESERVED);
}
if (fd < 0) {
return -1;
}
pid = send_request(fd, 0, newargc, newargv);
do {
err = close(fd);
} while (err < 0 && errno == EINTR);
return pid;
}
/**
* Replaces all occurrances of newline with space.
*/
static void replace_nl(char *str)
{
for(; *str; str++) {
if (*str == '\n') {
*str = ' ';
}
}
}