eclair snapshot
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 18d0ee3..1d1e576 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -20,7 +20,7 @@
 	array.c \
 	hashmap.c \
 	atomic.c \
-        native_handle.c \
+	native_handle.c \
 	buffer.c \
 	socket_inaddr_any_server.c \
 	socket_local_client.c \
@@ -36,40 +36,47 @@
 	record_stream.c \
 	process_name.c \
 	properties.c \
-	threads.c
+	threads.c \
+	sched_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
-WITH_MINGW :=
+WINDOWS_HOST_ONLY :=
 ifeq ($(HOST_OS),windows)
     ifeq ($(strip $(USE_CYGWIN)),)
-        WITH_MINGW := 1
+        WINDOWS_HOST_ONLY := 1
     endif
 endif
 # USE_MINGW is defined when we build against Mingw on Linux
 ifneq ($(strip $(USE_MINGW)),)
-    WITH_MINGW := 1
+    WINDOWS_HOST_ONLY := 1
 endif
 
-ifeq ($(WITH_MINGW),1)
+ifeq ($(WINDOWS_HOST_ONLY),1)
     commonSources += \
         uio.c
 else
     commonSources += \
+        abort_socket.c \
         mspace.c \
         selector.c \
         tztime.c \
-        tzstrftime.c \
         adb_networking.c \
-	zygote.c
+        zygote.c
+
+    commonHostSources += \
+        tzstrftime.c
 endif
 
 
 # Static library for host
 # ========================================================
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) ashmem-host.c
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources)
 LOCAL_LDLIBS := -lpthread
 LOCAL_STATIC_LIBRARIES := liblog
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -81,7 +88,7 @@
 # ========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) memory.c dlmalloc_stubs.c ashmem-host.c
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) memory.c dlmalloc_stubs.c
 LOCAL_LDLIBS := -lpthread
 LOCAL_SHARED_LIBRARIES := liblog
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
new file mode 100644
index 0000000..6a5e5e4
--- /dev/null
+++ b/libcutils/abort_socket.c
@@ -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);
+}
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
index c56ec5d..7befd78 100644
--- a/libcutils/atomic-android-arm.S
+++ b/libcutils/atomic-android-arm.S
@@ -55,23 +55,8 @@
  */
  
 android_atomic_write:
-    stmdb   sp!, {r4, lr}
-    mov     r2, r1
-    mov     r1, r0
-1: @ android_atomic_write
-    ldr     r0, [r2]
-    mov     r3, #kernel_atomic_base
-#ifdef __ARM_HAVE_PC_INTERWORK
-    add     lr, pc, #4
-    add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
-#else
-    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
-    mov     lr, pc
-    bx      r3
-#endif
-    bcc     1b
-    ldmia   sp!, {r4, lr}
-    bx      lr
+    str     r0, [r1]
+    bx      lr;
 
 /*
  * ----------------------------------------------------------------------------
@@ -81,6 +66,8 @@
  */
  
 android_atomic_inc:
+    .fnstart
+    .save {r4, lr}
     stmdb   sp!, {r4, lr}
     mov     r2, r0
 1: @ android_atomic_inc
@@ -100,6 +87,7 @@
     sub     r0, r1, #1
     ldmia   sp!, {r4, lr}
     bx      lr
+    .fnend
   
 /*
  * ----------------------------------------------------------------------------
@@ -109,6 +97,8 @@
  */
  
 android_atomic_dec:
+    .fnstart
+    .save {r4, lr}
     stmdb   sp!, {r4, lr}
     mov     r2, r0
 1: @ android_atomic_dec
@@ -128,6 +118,7 @@
     add     r0, r1, #1
     ldmia   sp!, {r4, lr}
     bx      lr
+    .fnend
     
 /*
  * ----------------------------------------------------------------------------
@@ -137,6 +128,8 @@
  */
 
 android_atomic_add:
+    .fnstart
+    .save {r4, lr}
     stmdb   sp!, {r4, lr}
     mov     r2, r1
     mov     r4, r0
@@ -157,6 +150,7 @@
     sub     r0, r1, r4
     ldmia   sp!, {r4, lr}
     bx      lr
+    .fnend
     
     
 /*
@@ -167,6 +161,8 @@
  */
 
 android_atomic_and:
+    .fnstart
+    .save {r4, r5, lr}
     stmdb   sp!, {r4, r5, lr}   
     mov     r2, r1              /* r2 = address */
     mov     r4, r0              /* r4 = the value */
@@ -189,6 +185,7 @@
     mov     r0, r5
     ldmia   sp!, {r4, r5, lr}
     bx      lr
+    .fnend
     
 /*
  * ----------------------------------------------------------------------------
@@ -198,6 +195,8 @@
  */
 
 android_atomic_or:
+    .fnstart
+    .save {r4, r5, lr}
     stmdb   sp!, {r4, r5, lr}   
     mov     r2, r1              /* r2 = address */
     mov     r4, r0              /* r4 = the value */
@@ -220,6 +219,7 @@
     mov     r0, r5
     ldmia   sp!, {r4, r5, lr}
     bx      lr
+    .fnend
 
 /*
  * ----------------------------------------------------------------------------
@@ -243,6 +243,8 @@
  */
 
 android_atomic_cmpxchg:
+    .fnstart
+    .save {r4, lr}
     stmdb   sp!, {r4, lr}
     mov     r4, r0          /* r4 = save oldvalue */
 1: @ android_atomic_cmpxchg
@@ -264,6 +266,7 @@
 2: @ android_atomic_cmpxchg
     ldmia   sp!, {r4, lr}
     bx      lr
+    .fnend
 
 /*
  * ----------------------------------------------------------------------------
diff --git a/libcutils/atomic-android-armv6.S b/libcutils/atomic-android-armv6.S
index 64146c1..a713089 100644
--- a/libcutils/atomic-android-armv6.S
+++ b/libcutils/atomic-android-armv6.S
@@ -45,11 +45,8 @@
  */
 
 android_atomic_write:
-1:  ldrex   r12, [r1]
-    strex   r12, r0, [r1]
-    cmp     r12, #0
-    bne     1b
-    bx      lr
+    str     r0, [r1]
+    bx      lr;
 
 /*
  * ----------------------------------------------------------------------------
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index 17f52e2..b235429 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -22,6 +22,10 @@
 #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";
@@ -35,10 +39,19 @@
     }
 
     // We never free the old name. Someone else could be using it.
-    char* copy = (char*) malloc(strlen(new_name) + 1);
+    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;
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
new file mode 100644
index 0000000..64d9bb7
--- /dev/null
+++ b/libcutils/sched_policy.c
@@ -0,0 +1,221 @@
+
+/* 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
+
+#include <sched.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 int __sys_supports_schedgroups = -1;
+
+static int add_tid_to_cgroup(int tid, const char *grp_name)
+{
+    int fd;
+    char path[255];
+    char text[64];
+
+    sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
+
+    if ((fd = open(path, O_WRONLY)) < 0) {
+        LOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", path, strerror(errno));
+        return -1;
+    }
+
+    sprintf(text, "%d", tid);
+    if (write(fd, text, strlen(text)) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    close(fd);
+    return 0;
+}
+
+static inline void initialize()
+{
+    if (__sys_supports_schedgroups < 0) {
+        if (!access("/dev/cpuctl/tasks", F_OK)) {
+            __sys_supports_schedgroups = 1;
+        } else {
+            __sys_supports_schedgroups = 0;
+        }
+    }
+}
+
+/*
+ * Try to get the scheduler group.
+ *
+ * The data from /proc/<pid>/cgroup looks like:
+ *  2:cpu:/bg_non_interactive
+ *
+ * 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 readBuf[256];
+    ssize_t count;
+    int fd;
+
+    snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
+    if ((fd = open(pathBuf, O_RDONLY)) < 0) {
+        return -1;
+    }
+
+    count = read(fd, readBuf, sizeof(readBuf));
+    if (count <= 0) {
+        close(fd);
+        errno = ENODATA;
+        return -1;
+    }
+    close(fd);
+
+    readBuf[--count] = '\0';    /* remove the '\n', now count==strlen */
+
+    char* cp = strchr(readBuf, '/');
+    if (cp == NULL) {
+        readBuf[sizeof(readBuf)-1] = '\0';
+        errno = ENODATA;
+        return -1;
+    }
+
+    memcpy(buf, cp+1, count);   /* count-1 for cp+1, count+1 for NUL */
+    return 0;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int get_sched_policy(int tid, SchedPolicy *policy)
+{
+    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)
+{
+    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) {
+        LOGD("vvv tid %d (%s)", tid, thread_name);
+    } else if (policy == SP_FOREGROUND) {
+        LOGD("^^^ tid %d (%s)", tid, thread_name);
+    } else {
+        LOGD("??? tid %d (%s)", tid, thread_name);
+    }
+#endif
+
+    if (__sys_supports_schedgroups) {
+        const char *grp = "";
+
+        if (policy == SP_BACKGROUND) {
+            grp = "bg_non_interactive";
+        }
+
+        if (add_tid_to_cgroup(tid, grp)) {
+            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_SCHED_H */
diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.c
index fadaabe..1a8ba86 100644
--- a/libcutils/strdup16to8.c
+++ b/libcutils/strdup16to8.c
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#include <limits.h>  /* for SIZE_MAX */
+
 #include <cutils/jstring.h>
 #include <assert.h>
 #include <stdlib.h>
@@ -26,19 +28,67 @@
  */
 extern size_t strnlen16to8(const char16_t* utf16Str, size_t len)
 {
-   size_t utf8Len = 0;
+    size_t utf8Len = 0;
 
-   while (len--) {
-       unsigned int uic = *utf16Str++;
+    /* 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.
+     */
 
-       if (uic > 0x07ff)
-           utf8Len += 3;
-       else if (uic > 0x7f || uic == 0)
-           utf8Len += 2;
-       else
-           utf8Len++;
-   }
-   return utf8Len;
+    /* 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;
 }
 
 
@@ -50,7 +100,7 @@
  *
  * 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.
  */
@@ -58,6 +108,10 @@
 {
     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++;
 
@@ -73,8 +127,8 @@
 
             if (uic == 0) {
                 break;
-            }           
-        }       
+            }
+        }
     }
 
    *utf8cur = '\0';
@@ -85,20 +139,30 @@
 /**
  * Convert a UTF-16 string to UTF-8.
  *
- * Make sure you allocate "dest" with the result of strblen16to8(),
- * not just "strlen16()".
  */
 char * strndup16to8 (const char16_t* s, size_t n)
 {
-    char *ret;
+    char*   ret;
+    size_t  len;
 
     if (s == NULL) {
         return NULL;
     }
 
-    ret = malloc(strnlen16to8(s, n) + 1);
+    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;    
+
+    return ret;
 }
diff --git a/libcutils/tztime.c b/libcutils/tztime.c
index 93bbb29..d6448a1 100644
--- a/libcutils/tztime.c
+++ b/libcutils/tztime.c
@@ -53,6 +53,31 @@
 #define OPEN_MODE	O_RDONLY
 #endif /* !defined O_BINARY */
 
+/* Complex computations to determine the min/max of time_t depending
+ * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
+ * These macros cannot be used in pre-processor directives, so we
+ * let the C compiler do the work, which makes things a bit funky.
+ */
+static const time_t TIME_T_MAX =
+    TYPE_INTEGRAL(time_t) ?
+        ( TYPE_SIGNED(time_t) ?
+            ~((time_t)1 << (TYPE_BIT(time_t)-1))
+        :
+            ~(time_t)0
+        )
+    : /* if time_t is a floating point number */
+        ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );
+
+static const time_t TIME_T_MIN =
+    TYPE_INTEGRAL(time_t) ?
+        ( TYPE_SIGNED(time_t) ?
+            ((time_t)1 << (TYPE_BIT(time_t)-1))
+        :
+            0
+        )
+    :
+        ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN );
+
 #ifndef WILDABBR
 /*
 ** Someone might make incorrect use of a time zone abbreviation:
@@ -158,7 +183,7 @@
 static struct tm *	gmtsub P((const time_t * timep, long offset,
 				struct tm * tmp));
 static struct tm *	localsub P((const time_t * timep, long offset,
-				struct tm * tmp, struct state *sp));
+				struct tm * tmp, const struct state *sp));
 static int		increment_overflow P((int * number, int delta));
 static int		leaps_thru_end_of P((int y));
 static int		long_increment_overflow P((long * number, int delta));
@@ -1157,7 +1182,7 @@
 const time_t * const	timep;
 const long		offset;
 struct tm * const	tmp;
-struct state *		sp;
+const struct state *		sp;
 {
 	register const struct ttinfo *	ttisp;
 	register int			i;
@@ -1553,26 +1578,36 @@
 
 static int
 increment_overflow(number, delta)
-int *	number;
-int	delta;
+int *   number;
+int delta;
 {
-	int	number0;
+    unsigned  number0 = (unsigned)*number;
+    unsigned  number1 = (unsigned)(number0 + delta);
 
-	number0 = *number;
-	*number += delta;
-	return (*number < number0) != (delta < 0);
+    *number = (int)number1;
+
+    if (delta >= 0) {
+        return ((int)number1 < (int)number0);
+    } else {
+        return ((int)number1 > (int)number0);
+    }
 }
 
 static int
 long_increment_overflow(number, delta)
-long *	number;
-int	delta;
+long *  number;
+int delta;
 {
-	long	number0;
+    unsigned long  number0 = (unsigned long)*number;
+    unsigned long  number1 = (unsigned long)(number0 + delta);
 
-	number0 = *number;
-	*number += delta;
-	return (*number < number0) != (delta < 0);
+    *number = (long)number1;
+
+    if (delta >= 0) {
+        return ((long)number1 < (long)number0);
+    } else {
+        return ((long)number1 > (long)number0);
+    }
 }
 
 static int
@@ -1741,14 +1776,14 @@
 		} else	dir = tmcomp(&mytm, &yourtm);
 		if (dir != 0) {
 			if (t == lo) {
+			        if (t == TIME_T_MAX)
+			             return WRONG;
 				++t;
-				if (t <= lo)
-					return WRONG;
 				++lo;
 			} else if (t == hi) {
+			        if (t == TIME_T_MIN)
+			             return WRONG;
 				--t;
-				if (t >= hi)
-					return WRONG;
 				--hi;
 			}
 			if (lo > hi)