Merge "stdint.h header is not fully compatible with C99(ISO9899:1999)"
diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c
index 0587430..5197ef3 100644
--- a/libc/bionic/system_properties.c
+++ b/libc/bionic/system_properties.c
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <stddef.h>
@@ -49,6 +50,25 @@
 
 #include <sys/atomics.h>
 
+struct prop_area {
+    unsigned volatile count;
+    unsigned volatile serial;
+    unsigned magic;
+    unsigned version;
+    unsigned reserved[4];
+    unsigned toc[1];
+};
+
+typedef struct prop_area prop_area;
+
+struct prop_info {
+    char name[PROP_NAME_MAX];
+    unsigned volatile serial;
+    char value[PROP_VALUE_MAX];
+};
+
+typedef struct prop_info prop_info;
+
 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
 
 static unsigned dummy_props = 0;
@@ -66,6 +86,17 @@
     return atoi(env);
 }
 
+void __system_property_area_init(void *data)
+{
+    prop_area *pa = data;
+    memset(pa, 0, PA_SIZE);
+    pa->magic = PROP_AREA_MAGIC;
+    pa->version = PROP_AREA_VERSION;
+
+    /* plug into the lib property services */
+    __system_property_area__ = pa;
+}
+
 int __system_properties_init(void)
 {
     bool fromFile = true;
@@ -128,6 +159,22 @@
     return result;
 }
 
+int __system_property_foreach(
+        void (*propfn)(const prop_info *pi, void *cookie),
+        void *cookie)
+{
+    prop_area *pa = __system_property_area__;
+    unsigned i;
+
+    for (i = 0; i < pa->count; i++) {
+        unsigned entry = pa->toc[i];
+        prop_info *pi = TOC_TO_INFO(pa, entry);
+        propfn(pi, cookie);
+    }
+
+    return 0;
+}
+
 const prop_info *__system_property_find_nth(unsigned n)
 {
     prop_area *pa = __system_property_area__;
@@ -147,6 +194,11 @@
     unsigned len = strlen(name);
     prop_info *pi;
 
+    if (len >= PROP_NAME_MAX)
+        return 0;
+    if (len < 1)
+        return 0;
+
     while(count--) {
         unsigned entry = *toc++;
         if(TOC_NAME_LEN(entry) != len) continue;
@@ -294,3 +346,68 @@
     }
     return 0;
 }
+
+int __system_property_update(prop_info *pi, const char *value, unsigned int len)
+{
+    prop_area *pa = __system_property_area__;
+
+    if (len >= PROP_VALUE_MAX)
+        return -1;
+
+    pi->serial = pi->serial | 1;
+    memcpy(pi->value, value, len + 1);
+    pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
+    __futex_wake(&pi->serial, INT32_MAX);
+
+    pa->serial++;
+    __futex_wake(&pa->serial, INT32_MAX);
+
+    return 0;
+}
+
+int __system_property_add(const char *name, unsigned int namelen,
+            const char *value, unsigned int valuelen)
+{
+    prop_area *pa = __system_property_area__;
+    prop_info *pa_info_array = (void*) (((char*) pa) + PA_INFO_START);
+    prop_info *pi;
+
+    if (pa->count == PA_COUNT_MAX)
+        return -1;
+    if (namelen >= PROP_NAME_MAX)
+        return -1;
+    if (valuelen >= PROP_VALUE_MAX)
+        return -1;
+    if (namelen < 1)
+        return -1;
+
+    pi = pa_info_array + pa->count;
+    pi->serial = (valuelen << 24);
+    memcpy(pi->name, name, namelen + 1);
+    memcpy(pi->value, value, valuelen + 1);
+
+    pa->toc[pa->count] =
+        (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
+
+    pa->count++;
+    pa->serial++;
+    __futex_wake(&pa->serial, INT32_MAX);
+
+    return 0;
+}
+
+unsigned int __system_property_serial(const prop_info *pi)
+{
+    return pi->serial;
+}
+
+unsigned int __system_property_wait_any(unsigned int serial)
+{
+    prop_area *pa = __system_property_area__;
+
+    do {
+        __futex_wait(&pa->serial, serial, 0);
+    } while(pa->serial == serial);
+
+    return pa->serial;
+}
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index de2e3e3..3cb3d8a 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -49,12 +49,9 @@
 extern int  fcntl(int   fd, int   command, ...);
 extern int  creat(const char*  path, mode_t  mode);
 
-#if defined(__BIONIC_FORTIFY)
-
-extern void __creat_error()
-    __attribute__((__error__ ("called with O_CREAT, but missing mode")));
-extern void __too_many_args_error()
-    __attribute__((__error__ ("too many arguments")));
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
+__errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
+__errordecl(__creat_too_many_args, "too many arguments");
 extern int __open_real(const char *pathname, int flags, ...)
     __asm__(__USER_LABEL_PREFIX__ "open");
 extern int __open_2(const char *, int);
@@ -63,12 +60,12 @@
 int open(const char *pathname, int flags, ...) {
     if (__builtin_constant_p(flags)) {
         if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
-            __creat_error();  // compile time error
+            __creat_missing_mode();  // compile time error
         }
     }
 
     if (__builtin_va_arg_pack_len() > 1) {
-        __too_many_args_error();  // compile time error
+        __creat_too_many_args();  // compile time error
     }
 
     if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
@@ -86,12 +83,12 @@
 int openat(int dirfd, const char *pathname, int flags, ...) {
     if (__builtin_constant_p(flags)) {
         if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
-            __creat_error();  // compile time error
+            __creat_missing_mode();  // compile time error
         }
     }
 
     if (__builtin_va_arg_pack_len() > 1) {
-        __too_many_args_error();  // compile time error
+        __creat_too_many_args();  // compile time error
     }
 
     if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
@@ -101,7 +98,7 @@
     return __openat_real(dirfd, pathname, flags, __builtin_va_arg_pack());
 }
 
-#endif /* defined(__BIONIC_FORTIFY) */
+#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
 
 __END_DECLS
 
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index aca6d9f..511bcd2 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -450,7 +450,7 @@
 __END_DECLS
 #endif /* _GNU_SOURCE */
 
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
 
 __BEGIN_DECLS
 
@@ -486,10 +486,8 @@
 
 extern char *__fgets_real(char *, int, FILE *)
     __asm__(__USER_LABEL_PREFIX__ "fgets");
-extern void __fgets_too_big_error()
-    __attribute__((__error__("fgets called with size bigger than buffer")));
-extern void __fgets_too_small_error()
-    __attribute__((__error__("fgets called with size less than zero")));
+__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
+__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
 extern char *__fgets_chk(char *, int, FILE *, size_t);
 
 __BIONIC_FORTIFY_INLINE
@@ -525,6 +523,6 @@
 
 __END_DECLS
 
-#endif /* defined(__BIONIC_FORTIFY) */
+#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
 
 #endif /* _STDIO_H_ */
diff --git a/libc/include/string.h b/libc/include/string.h
index 1691b16..ac31f7d 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -87,13 +87,11 @@
 
 #if defined(__BIONIC_FORTIFY)
 
-extern void __memcpy_dest_size_error()
-    __attribute__((__error__("memcpy called with size bigger than destination")));
-extern void __memcpy_src_size_error()
-    __attribute__((__error__("memcpy called with size bigger than source")));
+__errordecl(__memcpy_dest_size_error, "memcpy called with size bigger than destination");
+__errordecl(__memcpy_src_size_error, "memcpy called with size bigger than source");
 
 __BIONIC_FORTIFY_INLINE
-void *memcpy (void* __restrict dest, const void* __restrict src, size_t copy_amount) {
+void* memcpy(void* __restrict dest, const void* __restrict src, size_t copy_amount) {
     char *d = (char *) dest;
     const char *s = (const char *) src;
     size_t s_len = __builtin_object_size(s, 0);
@@ -111,20 +109,19 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-void *memmove (void *dest, const void *src, size_t len) {
+void* memmove(void *dest, const void *src, size_t len) {
     return __builtin___memmove_chk(dest, src, len, __builtin_object_size (dest, 0));
 }
 
 __BIONIC_FORTIFY_INLINE
-char *strcpy(char* __restrict dest, const char* __restrict src) {
+char* strcpy(char* __restrict dest, const char* __restrict src) {
     return __builtin___strcpy_chk(dest, src, __bos(dest));
 }
 
-extern void __strncpy_error()
-    __attribute__((__error__("strncpy called with size bigger than buffer")));
+__errordecl(__strncpy_error, "strncpy called with size bigger than buffer");
 
 __BIONIC_FORTIFY_INLINE
-char *strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
+char* strncpy(char* __restrict dest, const char* __restrict src, size_t n) {
     size_t bos = __bos(dest);
     if (__builtin_constant_p(n) && (n > bos)) {
         __strncpy_error();
@@ -133,7 +130,7 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-char *strcat(char* __restrict dest, const char* __restrict src) {
+char* strcat(char* __restrict dest, const char* __restrict src) {
     return __builtin___strcat_chk(dest, src, __bos(dest));
 }
 
@@ -143,14 +140,14 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-void *memset (void *s, int c, size_t n) {
+void* memset(void *s, int c, size_t n) {
     return __builtin___memset_chk(s, c, n, __builtin_object_size (s, 0));
 }
 
+#if !defined(__clang__)
 extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t)
     __asm__(__USER_LABEL_PREFIX__ "strlcpy");
-extern void __strlcpy_error()
-    __attribute__((__error__("strlcpy called with size bigger than buffer")));
+__errordecl(__strlcpy_error, "strlcpy called with size bigger than buffer");
 extern size_t __strlcpy_chk(char *, const char *, size_t, size_t);
 
 __BIONIC_FORTIFY_INLINE
@@ -176,11 +173,12 @@
 
     return __strlcpy_chk(dest, src, size, bos);
 }
+#endif /* !defined(__clang__) */
 
+#if !defined(__clang__)
 extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t)
     __asm__(__USER_LABEL_PREFIX__ "strlcat");
-extern void __strlcat_error()
-    __attribute__((__error__("strlcat called with size bigger than buffer")));
+__errordecl(__strlcat_error, "strlcat called with size bigger than buffer");
 extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t);
 
 
@@ -207,11 +205,13 @@
 
     return __strlcat_chk(dest, src, size, bos);
 }
+#endif /* !defined(__clang__) */
 
 __BIONIC_FORTIFY_INLINE
 size_t strlen(const char *s) {
     size_t bos = __bos(s);
 
+#if !defined(__clang__)
     // Compiler doesn't know destination size. Don't call __strlen_chk
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
         return __builtin_strlen(s);
@@ -221,6 +221,7 @@
     if (__builtin_constant_p(slen)) {
         return slen;
     }
+#endif /* !defined(__clang__) */
 
     return __strlen_chk(s, bos);
 }
@@ -231,6 +232,7 @@
 char* strchr(const char *s, int c) {
     size_t bos = __bos(s);
 
+#if !defined(__clang__)
     // Compiler doesn't know destination size. Don't call __strchr_chk
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
         return __builtin_strchr(s, c);
@@ -240,6 +242,7 @@
     if (__builtin_constant_p(slen) && (slen < bos)) {
         return __builtin_strchr(s, c);
     }
+#endif /* !defined(__clang__) */
 
     return __strchr_chk(s, c, bos);
 }
@@ -250,6 +253,7 @@
 char* strrchr(const char *s, int c) {
     size_t bos = __bos(s);
 
+#if !defined(__clang__)
     // Compiler doesn't know destination size. Don't call __strrchr_chk
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
         return __builtin_strrchr(s, c);
@@ -259,6 +263,7 @@
     if (__builtin_constant_p(slen) && (slen < bos)) {
         return __builtin_strrchr(s, c);
     }
+#endif /* !defined(__clang__) */
 
     return __strrchr_chk(s, c, bos);
 }
diff --git a/libc/include/strings.h b/libc/include/strings.h
index e72798b..faa12a4 100644
--- a/libc/include/strings.h
+++ b/libc/include/strings.h
@@ -50,12 +50,12 @@
 int	 strcasecmp(const char *, const char *);
 int	 strncasecmp(const char *, const char *, size_t);
 
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
 __BIONIC_FORTIFY_INLINE
 void bzero (void *s, size_t n) {
     __builtin___memset_chk(s, '\0', n, __builtin_object_size (s, 0));
 }
-#endif /* defined(__BIONIC_FORTIFY) */
+#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
 
 __END_DECLS
 
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index 5d2043d..c5bc223 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -34,7 +34,6 @@
 #else
 #include <sys/system_properties.h>
 
-typedef struct prop_area prop_area;
 typedef struct prop_msg prop_msg;
 
 #define PROP_AREA_MAGIC   0x504f5250
@@ -43,29 +42,20 @@
 #define PROP_SERVICE_NAME "property_service"
 #define PROP_FILENAME "/dev/__properties__"
 
-/* #define PROP_MAX_ENTRIES 247 */
-/* 247 -> 32620 bytes (<32768) */
+/* (8 header words + 247 toc words) = 1020 bytes */
+/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
+
+#define PA_COUNT_MAX  247
+#define PA_INFO_START 1024
+#define PA_SIZE       32768
 
 #define TOC_NAME_LEN(toc)       ((toc) >> 24)
 #define TOC_TO_INFO(area, toc)  ((prop_info*) (((char*) area) + ((toc) & 0xFFFFFF)))
 
-struct prop_area {
-    unsigned volatile count;
-    unsigned volatile serial;
-    unsigned magic;
-    unsigned version;
-    unsigned reserved[4];
-    unsigned toc[1];
-};
-
 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
 #define SERIAL_DIRTY(serial) ((serial) & 1)
 
-struct prop_info {
-    char name[PROP_NAME_MAX];
-    unsigned volatile serial;
-    char value[PROP_VALUE_MAX];
-};
+__BEGIN_DECLS
 
 struct prop_msg 
 {
@@ -106,5 +96,47 @@
 #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"
 #define PROP_PATH_FACTORY          "/factory/factory.prop"
 
+/*
+** Initialize the area to be used to store properties.  Can
+** only be done by a single process that has write access to
+** the property area.
+*/
+void __system_property_area_init(void *data);
+
+/* Add a new system property.  Can only be done by a single
+** process that has write access to the property area, and
+** that process must handle sequencing to ensure the property
+** does not already exist and that only one property is added
+** or updated at a time.
+**
+** Returns 0 on success, -1 if the property area is full.
+*/
+int __system_property_add(const char *name, unsigned int namelen,
+			const char *value, unsigned int valuelen);
+
+/* Update the value of a system property returned by
+** __system_property_find.  Can only be done by a single process
+** that has write access to the property area, and that process
+** must handle sequencing to ensure that only one property is
+** updated at a time.
+**
+** Returns 0 on success, -1 if the parameters are incorrect.
+*/
+int __system_property_update(prop_info *pi, const char *value, unsigned int len);
+
+/* Read the serial number of a system property returned by
+** __system_property_find.
+**
+** Returns the serial number on success, -1 on error.
+*/
+unsigned int __system_property_serial(const prop_info *pi);
+
+/* Wait for any system property to be updated.  Caller must pass
+** in 0 the first time, and the previous return value on each
+** successive call. */
+unsigned int __system_property_wait_any(unsigned int serial);
+
+__END_DECLS
+
 #endif
 #endif
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index c710356..c7fb9de 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -330,6 +330,12 @@
 #define __wur
 #endif
 
+#if __GNUC_PREREQ__(4, 3)
+#define __errordecl(name, msg) extern void name(void) __attribute__((__error__(msg)))
+#else
+#define __errordecl(name, msg) extern void name(void)
+#endif
+
 /*
  * Macros for manipulating "link sets".  Link sets are arrays of pointers
  * to objects, which are gathered up by the linker.
@@ -518,7 +524,7 @@
 #define  __BIONIC__   1
 #include <android/api-level.h>
 
-#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0 && !defined(__clang__)
+#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
 #define __BIONIC_FORTIFY 1
 #if _FORTIFY_SOURCE == 2
 #define __bos(s) __builtin_object_size((s), 1)
@@ -529,8 +535,7 @@
 #define __BIONIC_FORTIFY_INLINE \
     extern inline \
     __attribute__ ((always_inline)) \
-    __attribute__ ((gnu_inline)) \
-    __attribute__ ((artificial))
+    __attribute__ ((gnu_inline))
 #endif
 #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
 
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 4e8beb6..c9ad23d 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -129,25 +129,24 @@
 extern int    mknod(const char *, mode_t, dev_t);
 extern mode_t umask(mode_t);
 
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
 
 extern mode_t __umask_chk(mode_t);
 extern mode_t __umask_real(mode_t)
     __asm__(__USER_LABEL_PREFIX__ "umask");
-extern void __umask_error()
-    __attribute__((__error__("umask called with invalid mode")));
+__errordecl(__umask_invalid_mode, "umask called with invalid mode");
 
 __BIONIC_FORTIFY_INLINE
 mode_t umask(mode_t mode) {
   if (__builtin_constant_p(mode)) {
     if ((mode & 0777) != mode) {
-      __umask_error();
+      __umask_invalid_mode();
     }
     return __umask_real(mode);
   }
   return __umask_chk(mode);
 }
-#endif /* defined(__BIONIC_FORTIFY) */
+#endif /* defined(__BIONIC_FORTIFY) && !defined(__clang__) */
 
 
 #define  stat64    stat
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index 85915b2..01c3db3 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -76,13 +76,26 @@
 ** there is no nth property.  Use __system_property_read() to
 ** read the value of this property.
 **
-** This method is for inspecting and debugging the property 
+** Please do not call this method.  It only exists to provide
+** backwards compatibility to NDK apps.  Its implementation
+** is inefficient and order of results may change from call
+** to call.
+*/ 
+const prop_info *__system_property_find_nth(unsigned n);
+
+/* Pass a prop_info for each system property to the provided
+** callback.  Use __system_property_read() to read the value
+** of this property.
+**
+** This method is for inspecting and debugging the property
 ** system.  Please use __system_property_find() instead.
 **
 ** Order of results may change from call to call.  This is
 ** not a bug.
-*/ 
-const prop_info *__system_property_find_nth(unsigned n);
+*/
+int __system_property_foreach(
+        void (*propfn)(const prop_info *pi, void *cookie),
+        void *cookie);
 
 __END_DECLS
 
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
index 8ec7353..0478e93 100644
--- a/libc/kernel/tools/utils.py
+++ b/libc/kernel/tools/utils.py
@@ -47,32 +47,6 @@
 def find_program_dir():
     return os.path.dirname(sys.argv[0])
 
-def find_file_from_upwards(from_path,target_file):
-    """find a file in the current directory or its parents. if 'from_path' is None,
-       seach from the current program's directory"""
-    path = from_path
-    if path == None:
-        path = os.path.realpath(sys.argv[0])
-        path = os.path.dirname(path)
-        D("this script seems to be located in: %s" % path)
-
-    while 1:
-        D("probing "+path)
-        if path == "":
-            file = target_file
-        else:
-            file = path + "/" + target_file
-
-        if os.path.isfile(file):
-            D("found %s in %s" % (target_file, path))
-            return file
-
-        if path == "":
-            return None
-
-        path = os.path.dirname(path)
-
-
 class StringOutput:
     def __init__(self):
         self.line = ""
@@ -143,35 +117,6 @@
             for name in dirs:
                 os.rmdir(os.path.join(root, name))
 
-def update_file( path, newdata ):
-    """update a file on disk, only if its content has changed"""
-    if os.path.exists( path ):
-        try:
-            f = open( path, "r" )
-            olddata = f.read()
-            f.close()
-        except:
-            D("update_file: cannot read existing file '%s'" % path)
-            return 0
-
-        if oldata == newdata:
-            D2("update_file: no change to file '%s'" % path )
-            return 0
-
-        update = 1
-    else:
-        try:
-            create_file_path(path)
-        except:
-            D("update_file: cannot create path to '%s'" % path)
-            return 0
-
-    f = open( path, "w" )
-    f.write( newdata )
-    f.close()
-
-    return 1
-
 
 class BatchFileUpdater:
     """a class used to edit several files at once"""
diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c
index 3e1f67b..2b34867 100644
--- a/libc/netbsd/resolv/res_state.c
+++ b/libc/netbsd/resolv/res_state.c
@@ -71,7 +71,7 @@
         rt->_serial = 0;
         rt->_pi = (struct prop_info*) __system_property_find("net.change");
         if (rt->_pi) {
-            rt->_serial = rt->_pi->serial;
+            rt->_serial = __system_property_serial(rt->_pi);
         }
         memset(rt->_rstatic, 0, sizeof rt->_rstatic);
     }
@@ -135,14 +135,14 @@
                 return rt;
             }
         }
-        if (rt->_serial == rt->_pi->serial) {
+        if (rt->_serial == __system_property_serial(rt->_pi)) {
             /* Nothing changed, so return the current state */
             D("%s: tid=%d rt=%p nothing changed, returning",
               __FUNCTION__, gettid(), rt);
             return rt;
         }
         /* Update the recorded serial number, and go reset the state */
-        rt->_serial = rt->_pi->serial;
+        rt->_serial = __system_property_serial(rt->_pi);
         goto RESET_STATE;
     }
 
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 56a0ac2..61b894f 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -84,20 +84,18 @@
 /* get the TLS */
 #if defined(__arm__)
 # define __get_tls() \
-    ({ register unsigned int __val asm("r0"); \
-       asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \
-       (volatile void*)__val; })
+    ({ register unsigned int __val; \
+       asm ("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); \
+       (volatile void*) __val; })
 #elif defined(__mips__)
 # define __get_tls() \
-    ({ register unsigned int __val asm("v1");   \
-        asm (                                   \
-            "   .set    push\n"                 \
-            "   .set    mips32r2\n"             \
-            "   rdhwr   %0,$29\n"               \
-            "   .set    pop\n"                  \
-            : "=r"(__val)                       \
-            );                                  \
-        (volatile void*)__val; })
+    /* On mips32r1, this goes via a kernel illegal instruction trap that's optimized for v1. */ \
+    ({ register unsigned int __val asm("v1"); \
+       asm ("   .set    push\n" \
+            "   .set    mips32r2\n" \
+            "   rdhwr   %0,$29\n" \
+            "   .set    pop\n" : "=r"(__val)); \
+       (volatile void*) __val; })
 #elif defined(__i386__)
 # define __get_tls() \
     ({ register void* __val; \
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
index bbfff7d..dccf9e3 100644
--- a/libc/tools/bionic_utils.py
+++ b/libc/tools/bionic_utils.py
@@ -37,140 +37,6 @@
     verbose = level
 
 
-def find_dir_of(path):
-    '''return the directory name of 'path', or "." if there is none'''
-    # remove trailing slash
-    if len(path) > 1 and path[-1] == '/':
-        path = path[:-1]
-
-    # find parent directory name
-    d = os.path.dirname(path)
-    if d == "":
-        return "."
-    else:
-        return d
-
-#  other stuff
-#
-#
-def find_file_from_upwards(from_path,target_file):
-    """find a file in the current directory or its parents. if 'from_path' is None,
-       seach from the current program's directory"""
-    path = from_path
-    if path == None:
-        path = find_dir_of(sys.argv[0])
-        D("this script seems to be located in: %s" % path)
-
-    while 1:
-        if path == "":
-            path = "."
-
-        file = path + "/" + target_file
-        D("probing "+file)
-
-        if os.path.isfile(file):
-            D("found %s in %s" % (target_file, path))
-            return file
-
-        if path == ".":
-            break
-
-        path = os.path.dirname(path)
-
-    path = ""
-    while 1:
-        path = "../" + path
-        file = path + target_file
-        D("probing "+file)
-
-        if os.path.isfile(file):
-            D("found %s in %s" % (target_file, path))
-            return file
-
-
-    return None
-
-def find_bionic_root():
-    '''find the root of the Bionic source tree. we check for the SYSCALLS.TXT file
-       from the location of the current program's directory.'''
-
-    # note that we can't use find_file_from_upwards() since we can't use os.path.abspath
-    # that's because in some cases the p4 client is in a symlinked directory, and this
-    # function will return the real path instead, which later creates problems when
-    # p4 commands are issued
-    #
-    file = find_file_from_upwards(None, "SYSCALLS.TXT")
-    if file:
-        return os.path.dirname(file)
-    else:
-        return None
-
-def find_original_kernel_headers():
-    """try to find the directory containing the original kernel headers"""
-    bionic_root = find_bionic_root()
-    if not bionic_root:
-        D("Could not find Bionic root !!")
-        return None
-
-    path = os.path.normpath(bionic_root + "/../../external/kernel-headers/original")
-    if not os.path.isdir(path):
-        D("Could not find %s" % (path))
-        return None
-
-    return path
-
-def find_kernel_headers():
-    """try to find the directory containing the kernel headers for this machine"""
-
-    # First try to find the original kernel headers.
-    ret = find_original_kernel_headers()
-    if ret:
-        D("found original kernel headers in: %s" % (ret))
-        return ret
-
-    status, version = commands.getstatusoutput( "uname -r" )  # get Linux kernel version
-    if status != 0:
-        D("could not execute 'uname -r' command properly")
-        return None
-
-    # get rid of the "-xenU" suffix that is found in Xen virtual machines
-    if len(version) > 5 and version[-5:] == "-xenU":
-        version = version[:-5]
-
-    path = "/usr/src/linux-headers-" + version + "/include"
-    D("probing %s for kernel headers" % (path))
-    ret = os.path.isdir( path )
-    if ret:
-        D("found kernel headers in: %s" % (path))
-        return path
-    return None
-
-def find_arch_header(kernel_headers,arch,header):
-    # First, try in <root>/arch/<arm>/include/<header>
-    # corresponding to the location in the kernel source tree for
-    # certain architectures (e.g. arm).
-    path = "%s/arch/%s/include/asm/%s" % (kernel_headers, arch, header)
-    D("Probing for %s" % path)
-    if os.path.exists(path):
-        return path
-
-    # Try <root>/asm-<arch>/include/<header> corresponding to the location
-    # in the kernel source tree for other architectures (e.g. x86).
-    path = "%s/include/asm-%s/%s" % (kernel_headers, arch, header)
-    D("Probing for %s" % path)
-    if os.path.exists(path):
-        return path
-
-    # Otherwise, look under <root>/asm-<arch>/<header> corresponding
-    # the original kernel headers directory
-    path = "%s/asm-%s/%s" % (kernel_headers, arch, header)
-    D("Probing for %s" % path)
-    if os.path.exists(path):
-        return path
-
-
-    return None
-
 # parser for the SYSCALLS.TXT file
 #
 class SysCallsTxtParser:
@@ -312,52 +178,3 @@
 
     def get(self):
         return self.line
-
-
-def create_file_path(path):
-    dirs = []
-    while 1:
-        parent = os.path.dirname(path)
-        if parent == "/":
-            break
-        dirs.append(parent)
-        path = parent
-
-    dirs.reverse()
-    for dir in dirs:
-        #print "dir %s" % dir
-        if os.path.isdir(dir):
-            continue
-        os.mkdir(dir)
-
-def walk_source_files(paths,callback,args,excludes=[]):
-    """recursively walk a list of paths and files, only keeping the source files in directories"""
-    for path in paths:
-        if not os.path.isdir(path):
-            callback(path,args)
-        else:
-            for root, dirs, files in os.walk(path):
-                #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
-                if len(excludes):
-                    for d in dirs[:]:
-                        if d in excludes:
-                            dirs.remove(d)
-                for f in files:
-                    r, ext = os.path.splitext(f)
-                    if ext in [ ".h", ".c", ".cpp", ".S" ]:
-                        callback( "%s/%s" % (root,f), args )
-
-def cleanup_dir(path):
-    """create a directory if needed, and ensure that it is totally empty
-       by removing any existing content in it"""
-    if not os.path.exists(path):
-        os.mkdir(path)
-    else:
-        for root, dirs, files in os.walk(path, topdown=False):
-            if root.endswith("kernel_headers/"):
-                # skip 'kernel_headers'
-                continue
-            for name in files:
-                os.remove(os.path.join(root, name))
-            for name in dirs:
-                os.rmdir(os.path.join(root, name))
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index ed1b3dc..4894f2d 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -10,17 +10,7 @@
 
 from bionic_utils import *
 
-# get the root Bionic directory, simply this script's dirname
-#
-bionic_root = find_bionic_root()
-if not bionic_root:
-    print "could not find the Bionic root directory. aborting"
-    sys.exit(1)
-
-if bionic_root[-1] != '/':
-    bionic_root += "/"
-
-print "bionic_root is %s" % bionic_root
+bionic_libc_root = os.environ["ANDROID_BUILD_TOP"] + "/bionic/libc/"
 
 # temp directory where we store all intermediate files
 bionic_temp = "/tmp/bionic_gensyscalls/"
@@ -334,11 +324,11 @@
         glibc_fp.write("#define _BIONIC_GLIBC_SYSCALLS_H_\n")
 
         glibc_fp.write("#if defined(__arm__)\n")
-        self.scan_linux_unistd_h(glibc_fp, "libc/kernel/arch-arm/asm/unistd.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-arm/asm/unistd.h")
         glibc_fp.write("#elif defined(__mips__)\n")
-        self.scan_linux_unistd_h(glibc_fp, "libc/kernel/arch-mips/asm/unistd.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-mips/asm/unistd.h")
         glibc_fp.write("#elif defined(__i386__)\n")
-        self.scan_linux_unistd_h(glibc_fp, "libc/kernel/arch-x86/asm/unistd_32.h")
+        self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/arch-x86/asm/unistd_32.h")
         glibc_fp.write("#endif\n")
 
         glibc_fp.write("#endif /* _BIONIC_GLIBC_SYSCALLS_H_ */\n")
@@ -397,14 +387,14 @@
     def  regenerate(self):
         D( "scanning for existing architecture-specific stub files" )
 
-        bionic_root_len = len(bionic_root)
+        bionic_libc_root_len = len(bionic_libc_root)
 
         for arch in all_archs:
-            arch_path = bionic_root + "arch-" + arch
+            arch_path = bionic_libc_root + "arch-" + arch
             D( "scanning " + arch_path )
             files = glob.glob( arch_path + "/syscalls/*.S" )
             for f in files:
-                self.old_stubs.append( f[bionic_root_len:] )
+                self.old_stubs.append( f[bionic_libc_root_len:] )
 
         D( "found %d stub files" % len(self.old_stubs) )
 
@@ -424,13 +414,13 @@
         edits   = []
 
         for stub in self.new_stubs + self.other_files:
-            if not os.path.exists( bionic_root + stub ):
+            if not os.path.exists( bionic_libc_root + stub ):
                 # new file, git add it
                 D( "new file:     " + stub)
-                adds.append( bionic_root + stub )
-                shutil.copyfile( bionic_temp + stub, bionic_root + stub )
+                adds.append( bionic_libc_root + stub )
+                shutil.copyfile( bionic_temp + stub, bionic_libc_root + stub )
 
-            elif not filecmp.cmp( bionic_temp + stub, bionic_root + stub ):
+            elif not filecmp.cmp( bionic_temp + stub, bionic_libc_root + stub ):
                 D( "changed file: " + stub)
                 edits.append( stub )
 
@@ -438,7 +428,7 @@
         for stub in self.old_stubs:
             if not stub in self.new_stubs:
                 D( "deleted file: " + stub)
-                deletes.append( bionic_root + stub )
+                deletes.append( bionic_libc_root + stub )
 
 
         if adds:
@@ -447,11 +437,11 @@
             commands.getoutput("git rm " + " ".join(deletes))
         if edits:
             for file in edits:
-                shutil.copyfile( bionic_temp + file, bionic_root + file )
+                shutil.copyfile( bionic_temp + file, bionic_libc_root + file )
             commands.getoutput("git add " +
-                               " ".join((bionic_root + file) for file in edits))
+                               " ".join((bionic_libc_root + file) for file in edits))
 
-        commands.getoutput("git add %s%s" % (bionic_root,"SYSCALLS.TXT"))
+        commands.getoutput("git add %s%s" % (bionic_libc_root,"SYSCALLS.TXT"))
 
         if (not adds) and (not deletes) and (not edits):
             D("no changes detected!")
@@ -461,5 +451,5 @@
 D_setlevel(1)
 
 state = State()
-state.process_file(bionic_root+"SYSCALLS.TXT")
+state.process_file(bionic_libc_root+"SYSCALLS.TXT")
 state.regenerate()
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 80dc624..c53d52f 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1492,18 +1492,19 @@
         return false;
     }
 
-    /* if this is the main executable, then load all of the preloads now */
+    // If this is the main executable, then load all of the libraries from LD_PRELOAD now.
     if (si->flags & FLAG_EXE) {
         memset(gLdPreloads, 0, sizeof(gLdPreloads));
+        size_t preload_count = 0;
         for (size_t i = 0; gLdPreloadNames[i] != NULL; i++) {
             soinfo* lsi = find_library(gLdPreloadNames[i]);
-            if (lsi == NULL) {
-                strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
-                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
-                       gLdPreloadNames[i], si->name, tmp_err_buf);
-                return false;
+            if (lsi != NULL) {
+                gLdPreloads[preload_count++] = lsi;
+            } else {
+                // As with glibc, failure to load an LD_PRELOAD library is just a warning.
+                DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s",
+                        gLdPreloadNames[i], si->name, linker_get_error_buffer());
             }
-            gLdPreloads[i] = lsi;
         }
     }
 
diff --git a/linker/linker.h b/linker/linker.h
index 61d623a..200a682 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -43,7 +43,16 @@
       __libc_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
       /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
       DEBUG("%s\n", linker_get_error_buffer()); \
-    } while(0)
+    } while (false)
+
+#define DL_WARN(fmt, x...) \
+    do { \
+      __libc_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
+      __libc_format_fd(2, "WARNING: linker: "); \
+      __libc_format_fd(2, fmt, ##x); \
+      __libc_format_fd(2, "\n"); \
+    } while (false)
+
 
 // Returns the address of the page containing address 'x'.
 #define PAGE_START(x)  ((x) & PAGE_MASK)
diff --git a/tests/Android.mk b/tests/Android.mk
index 875746d..fe794c4 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -31,6 +31,7 @@
 benchmark_src_files = \
     benchmark_main.cpp \
     math_benchmark.cpp \
+    property_benchmark.cpp \
     string_benchmark.cpp \
     time_benchmark.cpp \
 
@@ -78,6 +79,7 @@
     string_test.cpp \
     strings_test.cpp \
     stubs_test.cpp \
+    system_properties_test.cpp \
     time_test.cpp \
     unistd_test.cpp \
 
@@ -94,6 +96,7 @@
 LOCAL_LDFLAGS += $(test_dynamic_ldflags)
 LOCAL_SHARED_LIBRARIES += libdl
 LOCAL_SRC_FILES := $(test_src_files) $(test_dynamic_src_files)
+LOCAL_WHOLE_STATIC_LIBRARIES := bionic-unit-tests-clang
 include $(BUILD_NATIVE_TEST)
 
 # Build tests for the device (with bionic's .a). Run with:
@@ -105,6 +108,7 @@
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SRC_FILES := $(test_src_files)
 LOCAL_STATIC_LIBRARIES += libstlport_static libstdc++ libm libc
+LOCAL_WHOLE_STATIC_LIBRARIES := bionic-unit-tests-clang
 include $(BUILD_NATIVE_TEST)
 
 # -----------------------------------------------------------------------------
@@ -141,4 +145,26 @@
 include $(BUILD_HOST_NATIVE_TEST)
 endif
 
+# -----------------------------------------------------------------------------
+# Unit tests which depend on clang as the compiler
+# -----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := fortify1_test_clang.cpp fortify2_test_clang.cpp
+LOCAL_MODULE := bionic-unit-tests-clang
+LOCAL_CLANG := true
+
+# -Wno-error=unused-parameter needed as
+# external/stlport/stlport/stl/_threads.c (included from
+# external/gtest/include/gtest/gtest.h) does not compile cleanly under
+# clang. TODO: fix this.
+LOCAL_CFLAGS += $(test_c_flags) -Wno-error=unused-parameter
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_C_INCLUDES += bionic \
+                    bionic/libstdc++/include \
+                    external/stlport/stlport \
+                    external/gtest/include
+
+include $(BUILD_STATIC_LIBRARY)
+
 endif # !BUILD_TINY_ANDROID
diff --git a/tests/fortify1_test.cpp b/tests/fortify1_test.cpp
index bbff000..be59a18 100644
--- a/tests/fortify1_test.cpp
+++ b/tests/fortify1_test.cpp
@@ -115,6 +115,32 @@
   ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
 }
 
+TEST(Fortify1_DeathTest, memmove_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[20];
+  strcpy(buf, "0123456789");
+  size_t n = atoi("10");
+  ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_DeathTest, memcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[10];
+  char bufb[10];
+  strcpy(bufa, "012345678");
+  size_t n = atoi("11");
+  ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_DeathTest, strncpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[15];
+  char bufb[10];
+  strcpy(bufa, "01234567890123");
+  size_t n = strlen(bufa);
+  ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
 extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
 extern "C" char* __strcat_chk(char*, const char*, size_t);
 
diff --git a/tests/fortify1_test_clang.cpp b/tests/fortify1_test_clang.cpp
new file mode 100644
index 0000000..0c0fb2b
--- /dev/null
+++ b/tests/fortify1_test_clang.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 1
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#if __BIONIC__
+// We have to say "DeathTest" here so gtest knows to run this test (which exits)
+// in its own process.
+
+// multibyte target where we over fill (should fail)
+TEST(Fortify1_Clang_DeathTest, strcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  char *orig = strdup("0123456789");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// zero sized target with "\0" source (should fail)
+TEST(Fortify1_Clang_DeathTest, strcpy2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify1_Clang_DeathTest, strcpy3_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("1");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify1_Clang_DeathTest, strcpy4_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[1];
+  char *orig = strdup("12");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+TEST(Fortify1_Clang_DeathTest, strlen_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%d", strlen(buf)), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, strchr_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%s", strchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, strrchr_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%s", strrchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
+}
+#endif
+
+TEST(Fortify1_Clang_DeathTest, strncat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  size_t n = atoi("10"); // avoid compiler optimizations
+  strncpy(buf, "012345678", n);
+  ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, strncat2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  buf[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, strcat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char src[11];
+  strcpy(src, "0123456789");
+  char buf[10];
+  buf[0] = '\0';
+  ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, memmove_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[20];
+  strcpy(buf, "0123456789");
+  size_t n = atoi("10");
+  ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, memcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[10];
+  char bufb[10];
+  strcpy(bufa, "012345678");
+  size_t n = atoi("11");
+  ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify1_Clang_DeathTest, strncpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[15];
+  char bufb[10];
+  strcpy(bufa, "01234567890123");
+  size_t n = strlen(bufa);
+  ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+extern "C" char* __strncat_chk(char*, const char*, size_t, size_t);
+extern "C" char* __strcat_chk(char*, const char*, size_t);
+
+TEST(Fortify1_Clang, strncat) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234", sizeof(buf) - strlen(buf) - 1, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1_Clang, strncat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1_Clang, strncat3) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = '\0';
+  char* res = __strncat_chk(buf, "0123456789", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('0',  buf[0]);
+  ASSERT_EQ('1',  buf[1]);
+  ASSERT_EQ('2',  buf[2]);
+  ASSERT_EQ('3',  buf[3]);
+  ASSERT_EQ('4',  buf[4]);
+  ASSERT_EQ('\0', buf[5]);
+  ASSERT_EQ('A',  buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1_Clang, strncat4) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[9] = '\0';
+  char* res = __strncat_chk(buf, "", 5, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('A',  buf[0]);
+  ASSERT_EQ('A',  buf[1]);
+  ASSERT_EQ('A',  buf[2]);
+  ASSERT_EQ('A',  buf[3]);
+  ASSERT_EQ('A',  buf[4]);
+  ASSERT_EQ('A',  buf[5]);
+  ASSERT_EQ('A',  buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+}
+
+TEST(Fortify1_Clang, strncat5) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234567", 8, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+TEST(Fortify1_Clang, strncat6) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strncat_chk(buf, "01234567", 9, sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+
+TEST(Fortify1_Clang, strcat) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strcat_chk(buf, "01234", sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('\0', buf[6]);
+  ASSERT_EQ('A',  buf[7]);
+  ASSERT_EQ('A',  buf[8]);
+  ASSERT_EQ('A',  buf[9]);
+}
+
+TEST(Fortify1_Clang, strcat2) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strcat_chk(buf, "01234567", sizeof(buf));
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5', buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0',  buf[9]);
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t test_fortify_inline(char* buf) {
+  return __bos(buf);
+}
+
+TEST(Fortify1_Clang, fortify_inline) {
+  char buf[1024];
+  // no-op. Prints nothing. Needed to prevent the compiler
+  // from optimizing out buf.
+  buf[0] = '\0';
+  printf("%s", buf);
+  ASSERT_EQ(sizeof(buf), test_fortify_inline(buf));
+}
diff --git a/tests/fortify2_test.cpp b/tests/fortify2_test.cpp
index 874eb1d..b48a077 100644
--- a/tests/fortify2_test.cpp
+++ b/tests/fortify2_test.cpp
@@ -233,3 +233,29 @@
   buf[0] = '\0';
   ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
 }
+
+TEST(Fortify2_DeathTest, memmove_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[20];
+  strcpy(buf, "0123456789");
+  size_t n = atoi("10");
+  ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_DeathTest, memcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[10];
+  char bufb[10];
+  strcpy(bufa, "012345678");
+  size_t n = atoi("11");
+  ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_DeathTest, strncpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[15];
+  char bufb[10];
+  strcpy(bufa, "01234567890123");
+  size_t n = strlen(bufa);
+  ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
diff --git a/tests/fortify2_test_clang.cpp b/tests/fortify2_test_clang.cpp
new file mode 100644
index 0000000..d8a0ba6
--- /dev/null
+++ b/tests/fortify2_test_clang.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 2
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+struct foo {
+  char empty[0];
+  char one[1];
+  char a[10];
+  char b[10];
+};
+
+// We have to say "DeathTest" here so gtest knows to run this test (which exits)
+// in its own process.
+TEST(Fortify2_Clang_DeathTest, strncat3_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+  myfoo.b[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(myfoo.b, myfoo.a, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strcat2_fortified2) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  foo myfoo;
+  memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); // unterminated string
+  myfoo.b[0] = '\0';
+  ASSERT_EXIT(strcat(myfoo.b, myfoo.a), testing::KilledBySignal(SIGABRT), "");
+}
+
+/*****************************************************************/
+/* TESTS BELOW HERE DUPLICATE TESTS FROM fortify1_test_clang.cpp */
+/*****************************************************************/
+
+#if __BIONIC__
+// multibyte target where we over fill (should fail)
+TEST(Fortify2_Clang_DeathTest, strcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  char *orig = strdup("0123456789");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// zero sized target with "\0" source (should fail)
+TEST(Fortify2_Clang_DeathTest, strcpy2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// zero sized target with longer source (should fail)
+TEST(Fortify2_Clang_DeathTest, strcpy3_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[0];
+  char *orig = strdup("1");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+// one byte target with longer source (should fail)
+TEST(Fortify2_Clang_DeathTest, strcpy4_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[1];
+  char *orig = strdup("12");
+  ASSERT_EXIT(strcpy(buf, orig), testing::KilledBySignal(SIGABRT), "");
+  free(orig);
+}
+
+TEST(Fortify2_Clang_DeathTest, strlen_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%d", strlen(buf)), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strchr_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%s", strchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strrchr_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  memcpy(buf, "0123456789", sizeof(buf));
+  ASSERT_EXIT(printf("%s", strrchr(buf, 'a')), testing::KilledBySignal(SIGABRT), "");
+}
+#endif
+
+TEST(Fortify2_Clang_DeathTest, strncat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  size_t n = atoi("10"); // avoid compiler optimizations
+  strncpy(buf, "012345678", n);
+  ASSERT_EXIT(strncat(buf, "9", n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strncat2_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[10];
+  buf[0] = '\0';
+  size_t n = atoi("10"); // avoid compiler optimizations
+  ASSERT_EXIT(strncat(buf, "0123456789", n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strcat_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char src[11];
+  strcpy(src, "0123456789");
+  char buf[10];
+  buf[0] = '\0';
+  ASSERT_EXIT(strcat(buf, src), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, memmove_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char buf[20];
+  strcpy(buf, "0123456789");
+  size_t n = atoi("10");
+  ASSERT_EXIT(memmove(buf + 11, buf, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, memcpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[10];
+  char bufb[10];
+  strcpy(bufa, "012345678");
+  size_t n = atoi("11");
+  ASSERT_EXIT(memcpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+TEST(Fortify2_Clang_DeathTest, strncpy_fortified) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  char bufa[15];
+  char bufb[10];
+  strcpy(bufa, "01234567890123");
+  size_t n = strlen(bufa);
+  ASSERT_EXIT(strncpy(bufb, bufa, n), testing::KilledBySignal(SIGABRT), "");
+}
+
+__BIONIC_FORTIFY_INLINE
+size_t test_fortify2_inline(char* buf) {
+  return __bos(buf);
+}
+
+TEST(Fortify2_Clang, fortify_inline) {
+  char buf[1024];
+  // no-op. Prints nothing. Needed to prevent the compiler
+  // from optimizing out buf.
+  buf[0] = '\0';
+  printf("%s", buf);
+  ASSERT_EQ(sizeof(buf), test_fortify2_inline(buf));
+}
diff --git a/tests/property_benchmark.cpp b/tests/property_benchmark.cpp
new file mode 100644
index 0000000..2c8e2a1
--- /dev/null
+++ b/tests/property_benchmark.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark.h"
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#include <vector>
+
+extern void *__system_property_area__;
+
+#define TEST_NUM_PROPS \
+    Arg(1)->Arg(4)->Arg(16)->Arg(64)->Arg(128)->Arg(247)
+
+struct LocalPropertyTestState {
+    LocalPropertyTestState(int nprops) : nprops(nprops) {
+        static const char prop_name_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_";
+        old_pa = __system_property_area__;
+        pa = malloc(PA_SIZE);
+        __system_property_area_init(pa);
+
+        names = new char* [nprops];
+        name_lens = new int[nprops];
+        values = new char* [nprops];
+        value_lens = new int[nprops];
+
+        srandom(nprops);
+
+        for (int i = 0; i < nprops; i++) {
+            name_lens[i] = random() % PROP_NAME_MAX;
+            names[i] = new char[PROP_NAME_MAX + 1];
+            for (int j = 0; j < name_lens[i]; j++) {
+                names[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)];
+            }
+            names[i][name_lens[i]] = 0;
+            value_lens[i] = random() % PROP_VALUE_MAX;
+            values[i] = new char[PROP_VALUE_MAX];
+            for (int j = 0; j < value_lens[i]; j++) {
+                values[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)];
+            }
+            __system_property_add(names[i], name_lens[i], values[i], value_lens[i]);
+        }
+    }
+
+    ~LocalPropertyTestState() {
+        __system_property_area__ = old_pa;
+        for (int i = 0; i < nprops; i++) {
+            delete names[i];
+            delete values[i];
+        }
+        delete[] names;
+        delete[] name_lens;
+        delete[] values;
+        delete[] value_lens;
+        free(pa);
+    }
+public:
+    const int nprops;
+    char **names;
+    int *name_lens;
+    char **values;
+    int *value_lens;
+
+private:
+    void *pa;
+    void *old_pa;
+};
+
+static void BM_property_get(int iters, int nprops)
+{
+    StopBenchmarkTiming();
+
+    LocalPropertyTestState pa(nprops);
+    char value[PROP_VALUE_MAX];
+
+    srandom(iters * nprops);
+
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; i++) {
+        __system_property_get(pa.names[random() % nprops], value);
+    }
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_property_get)->TEST_NUM_PROPS;
+
+static void BM_property_find(int iters, int nprops)
+{
+    StopBenchmarkTiming();
+
+    LocalPropertyTestState pa(nprops);
+
+    srandom(iters * nprops);
+
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; i++) {
+        __system_property_find(pa.names[random() % nprops]);
+    }
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_property_find)->TEST_NUM_PROPS;
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
new file mode 100644
index 0000000..70ff1d6
--- /dev/null
+++ b/tests/system_properties_test.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2013 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 <gtest/gtest.h>
+#include <sys/wait.h>
+
+#if __BIONIC__
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+extern void *__system_property_area__;
+
+struct LocalPropertyTestState {
+    LocalPropertyTestState() {
+        old_pa = __system_property_area__;
+        pa = malloc(PA_SIZE);
+        __system_property_area_init(pa);
+    }
+
+    ~LocalPropertyTestState() {
+        __system_property_area__ = old_pa;
+        free(pa);
+    }
+private:
+    void *pa;
+    void *old_pa;
+};
+
+TEST(properties, add) {
+    LocalPropertyTestState pa;
+
+    char propvalue[PROP_VALUE_MAX];
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
+    ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
+
+    ASSERT_EQ(6, __system_property_get("property", propvalue));
+    ASSERT_STREQ(propvalue, "value1");
+
+    ASSERT_EQ(6, __system_property_get("other_property", propvalue));
+    ASSERT_STREQ(propvalue, "value2");
+
+    ASSERT_EQ(6, __system_property_get("property_other", propvalue));
+    ASSERT_STREQ(propvalue, "value3");
+}
+
+TEST(properties, update) {
+    LocalPropertyTestState pa;
+
+    char propvalue[PROP_VALUE_MAX];
+    prop_info *pi;
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "oldvalue1", 9));
+    ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
+    ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
+
+    pi = (prop_info *)__system_property_find("property");
+    ASSERT_NE((prop_info *)NULL, pi);
+    __system_property_update(pi, "value4", 6);
+
+    pi = (prop_info *)__system_property_find("other_property");
+    ASSERT_NE((prop_info *)NULL, pi);
+    __system_property_update(pi, "newvalue5", 9);
+
+    pi = (prop_info *)__system_property_find("property_other");
+    ASSERT_NE((prop_info *)NULL, pi);
+    __system_property_update(pi, "value6", 6);
+
+    ASSERT_EQ(6, __system_property_get("property", propvalue));
+    ASSERT_STREQ(propvalue, "value4");
+
+    ASSERT_EQ(9, __system_property_get("other_property", propvalue));
+    ASSERT_STREQ(propvalue, "newvalue5");
+
+    ASSERT_EQ(6, __system_property_get("property_other", propvalue));
+    ASSERT_STREQ(propvalue, "value6");
+}
+
+// 247 = max # of properties supported by current implementation
+// (this should never go down)
+TEST(properties, fill_247) {
+    LocalPropertyTestState pa;
+    char prop_name[PROP_NAME_MAX];
+    char prop_value[PROP_VALUE_MAX];
+    char prop_value_ret[PROP_VALUE_MAX];
+    int ret;
+
+    for (int i = 0; i < 247; i++) {
+        ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i);
+        memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
+        ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i);
+        memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
+        prop_name[PROP_NAME_MAX - 1] = 0;
+        prop_value[PROP_VALUE_MAX - 1] = 0;
+
+        ASSERT_EQ(0, __system_property_add(prop_name, PROP_NAME_MAX - 1, prop_value, PROP_VALUE_MAX - 1));
+    }
+
+    for (int i = 0; i < 247; i++) {
+        ret = snprintf(prop_name, PROP_NAME_MAX - 1, "property_%d", i);
+        memset(prop_name + ret, 'a', PROP_NAME_MAX - 1 - ret);
+        ret = snprintf(prop_value, PROP_VALUE_MAX - 1, "value_%d", i);
+        memset(prop_value + ret, 'b', PROP_VALUE_MAX - 1 - ret);
+        prop_name[PROP_NAME_MAX - 1] = 0;
+        prop_value[PROP_VALUE_MAX - 1] = 0;
+        memset(prop_value_ret, '\0', PROP_VALUE_MAX);
+
+        ASSERT_EQ(PROP_VALUE_MAX - 1, __system_property_get(prop_name, prop_value_ret));
+        ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
+    }
+}
+
+static void foreach_test_callback(const prop_info *pi, void* cookie) {
+    size_t *count = static_cast<size_t *>(cookie);
+
+    ASSERT_NE((prop_info *)NULL, pi);
+    (*count)++;
+}
+
+TEST(properties, foreach) {
+    LocalPropertyTestState pa;
+    size_t count = 0;
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
+    ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
+
+    ASSERT_EQ(0, __system_property_foreach(foreach_test_callback, &count));
+    ASSERT_EQ(3U, count);
+}
+
+TEST(properties, find_nth) {
+    LocalPropertyTestState pa;
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
+    ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
+
+    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(0));
+    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(1));
+    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(2));
+
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(3));
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(4));
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(5));
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(100));
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(200));
+    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(247));
+}
+
+TEST(properties, errors) {
+    LocalPropertyTestState pa;
+    char prop_value[PROP_NAME_MAX];
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
+    ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
+
+    ASSERT_EQ(0, __system_property_find("property1"));
+    ASSERT_EQ(0, __system_property_get("property1", prop_value));
+
+    ASSERT_EQ(-1, __system_property_add("name", PROP_NAME_MAX, "value", 5));
+    ASSERT_EQ(-1, __system_property_add("name", 4, "value", PROP_VALUE_MAX));
+    ASSERT_EQ(-1, __system_property_update(NULL, "value", PROP_VALUE_MAX));
+}
+
+TEST(properties, serial) {
+    LocalPropertyTestState pa;
+    const prop_info *pi;
+    unsigned int serial;
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    ASSERT_NE((const prop_info *)NULL, pi = __system_property_find("property"));
+    serial = __system_property_serial(pi);
+    ASSERT_EQ(0, __system_property_update((prop_info *)pi, "value2", 6));
+    ASSERT_NE(serial, __system_property_serial(pi));
+}
+
+static void *PropertyWaitHelperFn(void *arg)
+{
+    int *flag = (int *)arg;
+    prop_info *pi;
+    pi = (prop_info *)__system_property_find("property");
+    usleep(100000);
+
+    *flag = 1;
+    __system_property_update(pi, "value3", 6);
+
+    return NULL;
+}
+
+TEST(properties, wait) {
+    LocalPropertyTestState pa;
+    unsigned int serial;
+    prop_info *pi;
+    pthread_t t;
+    int flag = 0;
+
+    ASSERT_EQ(0, __system_property_add("property", 8, "value1", 6));
+    serial = __system_property_wait_any(0);
+    pi = (prop_info *)__system_property_find("property");
+    ASSERT_NE((prop_info *)NULL, pi);
+    __system_property_update(pi, "value2", 6);
+    serial = __system_property_wait_any(serial);
+
+    ASSERT_EQ(0, pthread_create(&t, NULL, PropertyWaitHelperFn, &flag));
+    ASSERT_EQ(flag, 0);
+    serial = __system_property_wait_any(serial);
+    ASSERT_EQ(flag, 1);
+
+    void* result;
+    ASSERT_EQ(0, pthread_join(t, &result));
+}
+
+class KilledByFault {
+    public:
+        explicit KilledByFault() {};
+        bool operator()(int exit_status) const;
+};
+
+bool KilledByFault::operator()(int exit_status) const {
+    return WIFSIGNALED(exit_status) &&
+        (WTERMSIG(exit_status) == SIGSEGV ||
+         WTERMSIG(exit_status) == SIGBUS ||
+         WTERMSIG(exit_status) == SIGABRT);
+}
+
+TEST(properties_DeathTest, read_only) {
+      ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+      ASSERT_EXIT(__system_property_add("property", 8, "value", 5),
+                  KilledByFault(), "");
+}
+#endif