Merge "Revert "Add /odm/lib to shared lib search path""
diff --git a/benchmarks/Benchmark.cpp b/benchmarks/Benchmark.cpp
index ea6000f..a7ab682 100644
--- a/benchmarks/Benchmark.cpp
+++ b/benchmarks/Benchmark.cpp
@@ -24,7 +24,7 @@
 #include <string>
 #include <vector>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 #include <benchmark/Benchmark.h>
 
diff --git a/benchmarks/utils.cpp b/benchmarks/utils.cpp
index cf17edb..8bbd20a 100644
--- a/benchmarks/utils.cpp
+++ b/benchmarks/utils.cpp
@@ -23,7 +23,7 @@
 
 #include <string>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 int Round(int n) {
   int base = 1;
diff --git a/libc/Android.bp b/libc/Android.bp
index d1228af..74fd22b 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -177,6 +177,7 @@
         "-DALL_STATE",
         // Include tzsetwall, timelocal, timegm, time2posix, and posix2time.
         "-DSTD_INSPIRED",
+        // Obviously, we want to be thread-safe.
         "-DTHREAD_SAFE",
         // The name of the tm_gmtoff field in our struct tm.
         "-DTM_GMTOFF=tm_gmtoff",
@@ -184,6 +185,9 @@
         "-DTZDIR=\\\"/system/usr/share/zoneinfo\\\"",
         // Include timezone and daylight globals.
         "-DUSG_COMPAT=1",
+        // Use the empty string (instead of "   ") as the timezone abbreviation
+        // fallback.
+        "-DWILDABBR=\\\"\\\"",
         "-DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU",
         "-Dlint",
     ],
@@ -307,22 +311,22 @@
                 "upstream-freebsd/lib/libc/string/wcslen.c",
                 "upstream-freebsd/lib/libc/string/wcsrchr.c",
             ],
-        },
-        atom: {
-            exclude_srcs: [
-                "upstream-freebsd/lib/libc/string/wmemcmp.c",
-            ],
-        },
-        x86_ssse3: {
-            exclude_srcs: [
-                "upstream-freebsd/lib/libc/string/wcscat.c",
-                "upstream-freebsd/lib/libc/string/wcscpy.c",
-            ],
-        },
-        x86_sse4: {
-            exclude_srcs: [
-                "upstream-freebsd/lib/libc/string/wmemcmp.c",
-            ],
+            atom: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wmemcmp.c",
+                ],
+            },
+            ssse3: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wcscat.c",
+                    "upstream-freebsd/lib/libc/string/wcscpy.c",
+                ],
+            },
+            sse4: {
+                exclude_srcs: [
+                    "upstream-freebsd/lib/libc/string/wmemcmp.c",
+                ],
+            },
         },
     },
 
@@ -647,64 +651,63 @@
             exclude_srcs: [
                 "upstream-openbsd/lib/libc/string/strcpy.c",
             ],
+            cortex_a7: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a53: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a53_a57: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a8: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a9: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            cortex_a15: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            denver: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
+            krait: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/memmove.c",
+                    "upstream-openbsd/lib/libc/string/stpcpy.c",
+                    "upstream-openbsd/lib/libc/string/strcat.c",
+                ],
+            },
         },
-        cortex_a7: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        cortex_a53: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        cortex_a53_a57: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        cortex_a8: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        cortex_a9: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        cortex_a15: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        denver: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-        krait: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memmove.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-            ],
-        },
-
         arm64: {
             exclude_srcs: [
                 "upstream-openbsd/lib/libc/string/memchr.c",
@@ -716,39 +719,39 @@
         },
 
         x86: {
-             exclude_srcs: [
-                 "upstream-openbsd/lib/libc/string/memchr.c",
-                 "upstream-openbsd/lib/libc/string/memmove.c",
-                 "upstream-openbsd/lib/libc/string/memrchr.c",
-                 "upstream-openbsd/lib/libc/string/stpcpy.c",
-                 "upstream-openbsd/lib/libc/string/stpncpy.c",
-                 "upstream-openbsd/lib/libc/string/strcat.c",
-                 "upstream-openbsd/lib/libc/string/strcpy.c",
-                 "upstream-openbsd/lib/libc/string/strncmp.c",
-                 "upstream-openbsd/lib/libc/string/strncpy.c",
-             ],
-        },
-        x86_ssse3: {
-             exclude_srcs: [
-                 "upstream-openbsd/lib/libc/string/strlcat.c",
-                 "upstream-openbsd/lib/libc/string/strlcpy.c",
-                 "upstream-openbsd/lib/libc/string/strncat.c",
-             ],
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memchr.c",
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/memrchr.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
+            ],
+            ssse3: {
+                exclude_srcs: [
+                    "upstream-openbsd/lib/libc/string/strlcat.c",
+                    "upstream-openbsd/lib/libc/string/strlcpy.c",
+                    "upstream-openbsd/lib/libc/string/strncat.c",
+                ],
+            },
         },
 
         x86_64: {
-             exclude_srcs: [
-                 "upstream-openbsd/lib/libc/string/memmove.c",
-                 "upstream-openbsd/lib/libc/string/stpcpy.c",
-                 "upstream-openbsd/lib/libc/string/stpncpy.c",
-                 "upstream-openbsd/lib/libc/string/strcat.c",
-                 "upstream-openbsd/lib/libc/string/strcpy.c",
-                 "upstream-openbsd/lib/libc/string/strlcat.c",
-                 "upstream-openbsd/lib/libc/string/strlcpy.c",
-                 "upstream-openbsd/lib/libc/string/strncat.c",
-                 "upstream-openbsd/lib/libc/string/strncmp.c",
-                 "upstream-openbsd/lib/libc/string/strncpy.c",
-             ],
+            exclude_srcs: [
+                "upstream-openbsd/lib/libc/string/memmove.c",
+                "upstream-openbsd/lib/libc/string/stpcpy.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+                "upstream-openbsd/lib/libc/string/strcpy.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
+                "upstream-openbsd/lib/libc/string/strncat.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
+            ],
         },
     },
 
@@ -801,7 +804,7 @@
     ],
     multilib: {
         lib64: {
-            srcs: ["upstream-openbsd/lib/libc/gdtoa/strtorQ.c"]
+            srcs: ["upstream-openbsd/lib/libc/gdtoa/strtorQ.c"],
         },
     },
 
@@ -828,8 +831,9 @@
 cc_library_static {
     defaults: ["libc_defaults"],
     srcs: [
-        // The fork implementation depends on pthread data, so we can't include
-        // it in libc_ndk.a.
+        // The following implementations depend on pthread data, so we can't
+        // include them in libc_ndk.a.
+        "bionic/__cxa_thread_atexit_impl.cpp",
         "bionic/fork.cpp",
 
         // The data that backs getauxval is initialized in the libc init
@@ -880,206 +884,206 @@
                 "bionic/__memcpy_chk.cpp",
                 "bionic/__memset_chk.cpp",
             ],
+            cortex_a7: {
+                srcs: [
+                    "arch-arm/cortex-a7/bionic/memset.S",
+
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a53: {
+                srcs: [
+                    "arch-arm/cortex-a53/bionic/memcpy.S",
+                    "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+
+                    "arch-arm/cortex-a7/bionic/memset.S",
+
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a53_a57: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a8: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a9: {
+                srcs: [
+                    "arch-arm/cortex-a9/bionic/memcpy.S",
+                    "arch-arm/cortex-a9/bionic/memset.S",
+                    "arch-arm/cortex-a9/bionic/stpcpy.S",
+                    "arch-arm/cortex-a9/bionic/strcat.S",
+                    "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a9/bionic/strcmp.S",
+                    "arch-arm/cortex-a9/bionic/strcpy.S",
+                    "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a9/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            cortex_a15: {
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            denver: {
+                srcs: [
+                    "arch-arm/denver/bionic/memcpy.S",
+                    "arch-arm/denver/bionic/memmove.S",
+                    "arch-arm/denver/bionic/memset.S",
+                    "arch-arm/denver/bionic/__strcat_chk.S",
+                    "arch-arm/denver/bionic/__strcpy_chk.S",
+
+                    // Use cortex-a15 versions of strcat/strcpy/strlen.
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+            krait: {
+                srcs: [
+                    "arch-arm/krait/bionic/memcpy.S",
+                    "arch-arm/krait/bionic/memset.S",
+                    "arch-arm/krait/bionic/strcmp.S",
+                    "arch-arm/krait/bionic/__strcat_chk.S",
+                    "arch-arm/krait/bionic/__strcpy_chk.S",
+
+                    // Use cortex-a15 versions of strcat/strcpy/strlen.
+                    "arch-arm/cortex-a15/bionic/stpcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcat.S",
+                    "arch-arm/cortex-a15/bionic/strcpy.S",
+                    "arch-arm/cortex-a15/bionic/strlen.S",
+
+                    "arch-arm/denver/bionic/memmove.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/generic/bionic/memcpy.S",
+                    "arch-arm/generic/bionic/memset.S",
+                    "arch-arm/generic/bionic/strcmp.S",
+                    "arch-arm/generic/bionic/strcpy.S",
+                    "arch-arm/generic/bionic/strlen.c",
+                    "bionic/__strcat_chk.cpp",
+                    "bionic/__strcpy_chk.cpp",
+                ],
+            },
+
         },
-        cortex_a7: {
-            srcs: [
-                "arch-arm/cortex-a7/bionic/memset.S",
-
-                "arch-arm/cortex-a15/bionic/memcpy.S",
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        cortex_a53: {
-            srcs: [
-                "arch-arm/cortex-a53/bionic/memcpy.S",
-                "arch-arm/cortex-a53/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
-
-                "arch-arm/cortex-a7/bionic/memset.S",
-
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        cortex_a53_a57: {
-            srcs: [
-                "arch-arm/cortex-a15/bionic/memcpy.S",
-                "arch-arm/cortex-a15/bionic/memset.S",
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        cortex_a8: {
-            srcs: [
-                "arch-arm/cortex-a15/bionic/memcpy.S",
-                "arch-arm/cortex-a15/bionic/memset.S",
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        cortex_a9: {
-            srcs: [
-                "arch-arm/cortex-a9/bionic/memcpy.S",
-                "arch-arm/cortex-a9/bionic/memset.S",
-                "arch-arm/cortex-a9/bionic/stpcpy.S",
-                "arch-arm/cortex-a9/bionic/strcat.S",
-                "arch-arm/cortex-a9/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a9/bionic/strcmp.S",
-                "arch-arm/cortex-a9/bionic/strcpy.S",
-                "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
-                "arch-arm/cortex-a9/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        cortex_a15: {
-            srcs: [
-                "arch-arm/cortex-a15/bionic/memcpy.S",
-                "arch-arm/cortex-a15/bionic/memset.S",
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/__strcat_chk.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        denver: {
-            srcs: [
-                "arch-arm/denver/bionic/memcpy.S",
-                "arch-arm/denver/bionic/memmove.S",
-                "arch-arm/denver/bionic/memset.S",
-                "arch-arm/denver/bionic/__strcat_chk.S",
-                "arch-arm/denver/bionic/__strcpy_chk.S",
-
-                // Use cortex-a15 versions of strcat/strcpy/strlen.
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/strcmp.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-        krait: {
-            srcs: [
-                "arch-arm/krait/bionic/memcpy.S",
-                "arch-arm/krait/bionic/memset.S",
-                "arch-arm/krait/bionic/strcmp.S",
-                "arch-arm/krait/bionic/__strcat_chk.S",
-                "arch-arm/krait/bionic/__strcpy_chk.S",
-
-                // Use cortex-a15 versions of strcat/strcpy/strlen.
-                "arch-arm/cortex-a15/bionic/stpcpy.S",
-                "arch-arm/cortex-a15/bionic/strcat.S",
-                "arch-arm/cortex-a15/bionic/strcpy.S",
-                "arch-arm/cortex-a15/bionic/strlen.S",
-
-                "arch-arm/denver/bionic/memmove.S",
-            ],
-            exclude_srcs: [
-                "arch-arm/generic/bionic/memcpy.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-                "bionic/__strcat_chk.cpp",
-                "bionic/__strcpy_chk.cpp",
-            ],
-        },
-
         arm64: {
             srcs: [
                 "arch-arm64/bionic/__bionic_clone.S",
@@ -1108,16 +1112,16 @@
                 "bionic/strchr.cpp",
                 "bionic/strnlen.c",
             ],
-        },
-        denver64: {
-            srcs: [
-                "arch-arm64/denver64/bionic/memcpy.S",
-                "arch-arm64/denver64/bionic/memset.S",
-            ],
-            exclude_srcs: [
-                "arch-arm64/generic/bionic/memcpy.S",
-                "arch-arm64/generic/bionic/memset.S",
-            ],
+            denver64: {
+                srcs: [
+                    "arch-arm64/denver64/bionic/memcpy.S",
+                    "arch-arm64/denver64/bionic/memset.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm64/generic/bionic/memcpy.S",
+                    "arch-arm64/generic/bionic/memset.S",
+                ],
+            },
         },
 
         mips: {
@@ -1136,16 +1140,15 @@
                 "arch-mips/string/strcmp.S",
                 "arch-mips/string/strlen.c",
             ],
+            rev6: {
+                srcs: [
+                    "arch-mips/string/mips_strlen.c",
+                ],
+                exclude_srcs: [
+                    "arch-mips/string/strlen.c",
+                ],
+            },
         },
-        mips_rev6: {
-            srcs: [
-                "arch-mips/string/mips_strlen.c"
-            ],
-            exclude_srcs: [
-                "arch-mips/string/strlen.c"
-            ],
-        },
-
         mips64: {
             srcs: [
                 "arch-mips64/bionic/__bionic_clone.S",
@@ -1204,57 +1207,56 @@
                 "bionic/strnlen.c",
                 "bionic/strrchr.cpp",
             ],
+            atom: {
+                srcs: [
+                    "arch-x86/atom/string/sse2-bzero-atom.S",
+                    "arch-x86/atom/string/sse2-memset-atom.S",
+                    "arch-x86/atom/string/sse2-strlen-atom.S",
+                    "arch-x86/atom/string/ssse3-bcopy-atom.S",
+                    "arch-x86/atom/string/ssse3-memcmp-atom.S",
+                    "arch-x86/atom/string/ssse3-memmove-atom.S",
+                    "arch-x86/atom/string/ssse3-strncpy-atom.S",
+                    "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/memcmp.S",
+                    "arch-x86/silvermont/string/sse2-bcopy-slm.S",
+                    "arch-x86/silvermont/string/sse2-bzero-slm.S",
+                    "arch-x86/silvermont/string/sse2-memcpy-slm.S",
+                    "arch-x86/silvermont/string/sse2-memmove-slm.S",
+                    "arch-x86/silvermont/string/sse2-memset-slm.S",
+                    "arch-x86/silvermont/string/sse2-strcpy-slm.S",
+                    "arch-x86/silvermont/string/sse2-strlen-slm.S",
+                    "arch-x86/silvermont/string/sse2-strncpy-slm.S",
+                ],
+            },
+            ssse3: {
+                srcs: [
+                    "arch-x86/atom/string/ssse3-strncat-atom.S",
+                    "arch-x86/atom/string/ssse3-strlcat-atom.S",
+                    "arch-x86/atom/string/ssse3-strlcpy-atom.S",
+                    "arch-x86/atom/string/ssse3-strcat-atom.S",
+                    "arch-x86/atom/string/ssse3-strcmp-atom.S",
+                    "arch-x86/atom/string/ssse3-strncmp-atom.S",
+                    "arch-x86/atom/string/ssse3-wcscat-atom.S",
+                    "arch-x86/atom/string/ssse3-wcscpy-atom.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/strcmp.S",
+                    "arch-x86/generic/string/strncmp.S",
+                    "arch-x86/generic/string/strcat.S",
+                ],
+            },
+            sse4: {
+                srcs: [
+                    "arch-x86/silvermont/string/sse4-memcmp-slm.S",
+                    "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
+                ],
+                exclude_srcs: [
+                    "arch-x86/generic/string/memcmp.S",
+                ],
+            },
         },
-        atom: {
-            srcs: [
-                "arch-x86/atom/string/sse2-bzero-atom.S",
-                "arch-x86/atom/string/sse2-memset-atom.S",
-                "arch-x86/atom/string/sse2-strlen-atom.S",
-                "arch-x86/atom/string/ssse3-bcopy-atom.S",
-                "arch-x86/atom/string/ssse3-memcmp-atom.S",
-                "arch-x86/atom/string/ssse3-memmove-atom.S",
-                "arch-x86/atom/string/ssse3-strncpy-atom.S",
-                "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
-            ],
-            exclude_srcs: [
-                "arch-x86/generic/string/memcmp.S",
-                "arch-x86/silvermont/string/sse2-bcopy-slm.S",
-                "arch-x86/silvermont/string/sse2-bzero-slm.S",
-                "arch-x86/silvermont/string/sse2-memcpy-slm.S",
-                "arch-x86/silvermont/string/sse2-memmove-slm.S",
-                "arch-x86/silvermont/string/sse2-memset-slm.S",
-                "arch-x86/silvermont/string/sse2-strcpy-slm.S",
-                "arch-x86/silvermont/string/sse2-strlen-slm.S",
-                "arch-x86/silvermont/string/sse2-strncpy-slm.S",
-            ],
-        },
-        x86_ssse3: {
-            srcs: [
-                "arch-x86/atom/string/ssse3-strncat-atom.S",
-                "arch-x86/atom/string/ssse3-strlcat-atom.S",
-                "arch-x86/atom/string/ssse3-strlcpy-atom.S",
-                "arch-x86/atom/string/ssse3-strcat-atom.S",
-                "arch-x86/atom/string/ssse3-strcmp-atom.S",
-                "arch-x86/atom/string/ssse3-strncmp-atom.S",
-                "arch-x86/atom/string/ssse3-wcscat-atom.S",
-                "arch-x86/atom/string/ssse3-wcscpy-atom.S",
-            ],
-            exclude_srcs: [
-                "arch-x86/generic/string/strcmp.S",
-                "arch-x86/generic/string/strncmp.S",
-                "arch-x86/generic/string/strcat.S",
-            ],
-        },
-        x86_sse4: {
-            srcs: [
-                "arch-x86/silvermont/string/sse4-memcmp-slm.S",
-                "arch-x86/silvermont/string/sse4-wmemcmp-slm.S",
-            ],
-            exclude_srcs: [
-                "arch-x86/generic/string/memcmp.S",
-            ],
-        },
-
         x86_64: {
             srcs: [
                 "arch-x86_64/bionic/__bionic_clone.S",
@@ -1443,7 +1445,7 @@
     multilib: {
         lib32: {
             // LP32 cruft
-            srcs: ["bionic/mmap.cpp"]
+            srcs: ["bionic/mmap.cpp"],
         },
     },
 
@@ -1453,18 +1455,6 @@
     name: "libc_bionic_ndk",
 }
 
-cc_library_static {
-    name: "libc_thread_atexit_impl",
-    defaults: ["libc_defaults"],
-    srcs: ["bionic/__cxa_thread_atexit_impl.cpp"],
-    cflags: ["-Wframe-larger-than=2048"],
-    cppflags: ["-Wold-style-cast"],
-    include_dirs: ["bionic/libstdc++/include"],
-    // TODO: Clang tries to use __tls_get_addr which is not supported yet
-    // remove after it is implemented.
-    clang: false,
-}
-
 // ========================================================
 // libc_pthread.a - pthreads parts that previously lived in
 // libc_bionic.a. Relocated to their own library because
@@ -1478,6 +1468,7 @@
     srcs: [
         "bionic/pthread_atfork.cpp",
         "bionic/pthread_attr.cpp",
+        "bionic/pthread_barrier.cpp",
         "bionic/pthread_cond.cpp",
         "bionic/pthread_create.cpp",
         "bionic/pthread_detach.cpp",
@@ -1497,6 +1488,7 @@
         "bionic/pthread_setname_np.cpp",
         "bionic/pthread_setschedparam.cpp",
         "bionic/pthread_sigmask.cpp",
+        "bionic/pthread_spinlock.cpp",
     ],
     cflags: ["-Wframe-larger-than=2048"],
 
@@ -1658,7 +1650,6 @@
         "libc_pthread",
         "libc_stack_protector",
         "libc_syscalls",
-        "libc_thread_atexit_impl",
         "libc_tzcode",
     ],
 
@@ -1939,30 +1930,24 @@
     arch: {
         arm: {
             local_include_dirs: ["arch-arm/include"],
-            cflags: ["-mthumb-interwork"],
         },
         arm64: {
             local_include_dirs: ["arch-arm64/include"],
         },
         mips: {
             local_include_dirs: ["arch-mips/include"],
-            ldflags: ["-melf32ltsmip"],
         },
         mips64: {
             local_include_dirs: ["arch-mips64/include"],
-            ldflags: ["-melf64ltsmip"],
         },
         x86: {
-            cflags: ["-m32"],
-            ldflags: ["-melf_i386"],
             local_include_dirs: ["arch-x86/include"],
         },
         x86_64: {
-            cflags: ["-m64"],
-            ldflags: ["-melf_x86_64"],
             local_include_dirs: ["arch-x86_64/include"],
         },
     },
+    clang: false,
 }
 
 cc_defaults {
@@ -2014,7 +1999,10 @@
     },
     srcs: ["arch-common/bionic/crtbrand.S"],
 
-    defaults: ["crt_defaults", "crt_so_defaults"],
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
 }
 
 // Android.mk:ignore
@@ -2023,14 +2011,20 @@
     local_include_dirs: ["include"],
     srcs: ["arch-common/bionic/crtbegin_so.c"],
 
-    defaults: ["crt_defaults", "crt_so_defaults"],
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
 }
 
 // Android.mk:ignore
 cc_object {
     name: "crtbegin_so",
 
-    defaults: ["crt_defaults", "crt_so_defaults"],
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
     deps: [
         "crtbegin_so1",
         "crtbrand",
@@ -2043,7 +2037,10 @@
     local_include_dirs: ["include"],
     srcs: ["arch-common/bionic/crtend_so.S"],
 
-    defaults: ["crt_defaults", "crt_so_defaults"],
+    defaults: [
+        "crt_defaults",
+        "crt_so_defaults",
+    ],
 }
 
 // Android.mk:ignore
diff --git a/libc/Android.mk b/libc/Android.mk
index 2849591..456527a 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -243,9 +243,11 @@
 
 libc_bionic_src_files :=
 
-# The fork implementation depends on pthread data, so we can't include it in
-# libc_ndk.a.
-libc_bionic_src_files += bionic/fork.cpp
+# The following implementations depend on pthread data, so we can't include
+# them in libc_ndk.a.
+libc_bionic_src_files += \
+    bionic/__cxa_thread_atexit_impl.cpp \
+    bionic/fork.cpp \
 
 # The data that backs getauxval is initialized in the libc init functions which
 # are invoked by the linker. If this file is included in libc_ndk.a, only one of
@@ -584,9 +586,7 @@
     bionic/pthread_setname_np.cpp \
     bionic/pthread_setschedparam.cpp \
     bionic/pthread_sigmask.cpp \
-
-libc_thread_atexit_impl_src_files := \
-    bionic/__cxa_thread_atexit_impl.cpp \
+    bionic/pthread_spinlock.cpp \
 
 libc_arch_static_src_files := \
     bionic/dl_iterate_phdr_static.cpp \
@@ -624,6 +624,11 @@
   use_clang := false
 endif
 
+# b/25291096, Clang/llvm compiled libc.so for mips/mips64 failed to boot.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),mips mips64))
+  use_clang := false
+endif
+
 ifeq ($(use_clang),)
   use_clang := false
 endif
@@ -692,6 +697,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := bionic/__stack_chk_fail.cpp
+# On x86, the __set_tls implementation is complex enough that
+# -fstack-protector-strong inserts a check.
+LOCAL_SRC_FILES_x86 := arch-x86/bionic/__set_tls.c
 LOCAL_CFLAGS := $(libc_common_cflags) -fno-stack-protector
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
@@ -944,6 +952,7 @@
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 
 $(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_openbsd_src_files))
 $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES_EXCLUDE,libc_openbsd_src_files_exclude))
 include $(BUILD_STATIC_LIBRARY)
 
@@ -1039,24 +1048,6 @@
 $(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_ndk_src_files))
 include $(BUILD_STATIC_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libc_thread_atexit_impl_src_files)
-LOCAL_CFLAGS := $(libc_common_cflags) -Wframe-larger-than=2048
-
-LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
-LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
-LOCAL_C_INCLUDES := $(libc_common_c_includes)
-LOCAL_MODULE := libc_thread_atexit_impl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_CXX_STL := none
-LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_SANITIZE := never
-LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
-
-# b/25662915, clang compiled __cxa_thread_atexit_impl.cpp still failed.
-LOCAL_CLANG_arm64 := false
-
-include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
 # libc_pthread.a - pthreads parts that previously lived in
@@ -1254,7 +1245,6 @@
     libc_pthread \
     libc_stack_protector \
     libc_syscalls \
-    libc_thread_atexit_impl \
     libc_tzcode \
 
 LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk
index b4056bb..1d717aa 100644
--- a/libc/arch-x86/x86.mk
+++ b/libc/arch-x86/x86.mk
@@ -109,7 +109,6 @@
     arch-x86/bionic/libgcc_compat.c \
     arch-x86/bionic/__restore.S \
     arch-x86/bionic/setjmp.S \
-    arch-x86/bionic/__set_tls.c \
     arch-x86/bionic/syscall.S \
     arch-x86/bionic/vfork.S \
 
diff --git a/libc/bionic/__cxa_guard.cpp b/libc/bionic/__cxa_guard.cpp
index 5b34b58..97284d5 100644
--- a/libc/bionic/__cxa_guard.cpp
+++ b/libc/bionic/__cxa_guard.cpp
@@ -109,7 +109,7 @@
       }
     }
 
-    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, NULL);
+    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, false, nullptr);
     old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
   }
 }
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 0e427d3..0e903b9 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -15,6 +15,8 @@
  */
 #include <sys/cdefs.h>
 
+#include "pthread_internal.h"
+
 struct thread_local_dtor {
   void (*func) (void *);
   void *arg;
@@ -22,25 +24,24 @@
   thread_local_dtor* next;
 };
 
-static __thread thread_local_dtor* thread_local_dtors = nullptr;
-
 extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
   thread_local_dtor* dtor = new thread_local_dtor();
 
   dtor->func = func;
   dtor->arg = arg;
   dtor->dso_handle = dso_handle;
-  dtor->next = thread_local_dtors;
 
-  thread_local_dtors = dtor;
-
+  pthread_internal_t* thread = __get_thread();
+  dtor->next = thread->thread_local_dtors;
+  thread->thread_local_dtors = dtor;
   return 0;
 }
 
 extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() {
-  while (thread_local_dtors != nullptr) {
-    thread_local_dtor* current = thread_local_dtors;
-    thread_local_dtors = current->next;
+  pthread_internal_t* thread = __get_thread();
+  while (thread->thread_local_dtors != nullptr) {
+    thread_local_dtor* current = thread->thread_local_dtors;
+    thread->thread_local_dtors = current->next;
 
     current->func(current->arg);
     delete current;
diff --git a/libc/bionic/bionic_time_conversions.cpp b/libc/bionic/bionic_time_conversions.cpp
index 75e8d49..f3ca46a 100644
--- a/libc/bionic/bionic_time_conversions.cpp
+++ b/libc/bionic/bionic_time_conversions.cpp
@@ -52,18 +52,12 @@
   tv.tv_usec = ts.tv_nsec / 1000;
 }
 
-// Initializes 'ts' with the difference between 'abs_ts' and the current time
-// according to 'clock'. Returns false if abstime already expired, true otherwise.
-bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
-  clock_gettime(clock, &ts);
-  ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
-  ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
-  if (ts.tv_nsec < 0) {
-    ts.tv_sec--;
-    ts.tv_nsec += NS_PER_S;
+void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts, clockid_t clock) {
+  clock_gettime(clock, &abs_ts);
+  abs_ts.tv_sec += ts.tv_sec;
+  abs_ts.tv_nsec += ts.tv_nsec;
+  if (abs_ts.tv_nsec >= NS_PER_S) {
+    abs_ts.tv_nsec -= NS_PER_S;
+    abs_ts.tv_sec++;
   }
-  if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
-    return false;
-  }
-  return true;
 }
diff --git a/libc/bionic/flockfile.cpp b/libc/bionic/flockfile.cpp
index b73907cb..db53828 100644
--- a/libc/bionic/flockfile.cpp
+++ b/libc/bionic/flockfile.cpp
@@ -36,23 +36,15 @@
 // struct __sfileext (see fileext.h).
 
 void flockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_lock(&_FLOCK(fp));
   }
 }
 
 int ftrylockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
   // The specification for ftrylockfile() says it returns 0 on success,
   // or non-zero on error. So return an errno code directly on error.
-  if (fp == NULL) {
+  if (fp == nullptr) {
     return EINVAL;
   }
 
@@ -60,11 +52,7 @@
 }
 
 void funlockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_unlock(&_FLOCK(fp));
   }
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index a683748..b0c62d6 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -79,6 +79,10 @@
 
   static pthread_internal_t main_thread;
 
+  // The x86 -fstack-protector implementation uses TLS, so make sure that's
+  // set up before we call any function that might get a stack check inserted.
+  __set_tls(main_thread.tls);
+
   // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
   // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
   main_thread.tid = __set_tid_address(&main_thread.tid);
@@ -97,7 +101,6 @@
 
   __init_thread(&main_thread);
   __init_tls(&main_thread);
-  __set_tls(main_thread.tls);
 
   // Store a pointer to the kernel argument block in a TLS slot to be
   // picked up by the libc constructor.
@@ -110,6 +113,7 @@
   // Initialize libc globals that are needed in both the linker and in libc.
   // In dynamic binaries, this is run at least twice for different copies of the
   // globals, once for the linker's copy and once for the one in libc.so.
+  __libc_auxv = args.auxv;
   __libc_globals.initialize();
   __libc_globals.mutate([&args](libc_globals* globals) {
     __libc_init_vdso(globals, args);
@@ -121,7 +125,6 @@
   // Initialize various globals.
   environ = args.envp;
   errno = 0;
-  __libc_auxv = args.auxv;
   __progname = args.argv[0] ? args.argv[0] : "<unknown>";
   __abort_message_ptr = args.abort_message_ptr;
 
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 2a987b9..67bb052 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -31,6 +31,7 @@
 
 #include <android/set_abort_message.h>
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
@@ -46,6 +47,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 static pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
 
 __LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
@@ -481,6 +485,64 @@
   return log_fd;
 }
 
+struct cache {
+  const prop_info* pinfo;
+  uint32_t serial;
+  char c;
+};
+
+static void refresh_cache(struct cache *cache, const char *key)
+{
+  if (!cache->pinfo) {
+    cache->pinfo = __system_property_find(key);
+    if (!cache->pinfo) {
+      return;
+    }
+  }
+  uint32_t serial = __system_property_serial(cache->pinfo);
+  if (serial == cache->serial) {
+    return;
+  }
+  cache->serial = serial;
+
+  char buf[PROP_VALUE_MAX];
+  __system_property_read(cache->pinfo, 0, buf);
+  cache->c = buf[0];
+}
+
+// Timestamp state generally remains constant, since a change is
+// rare, we can accept a trylock failure gracefully.
+static pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER;
+
+static clockid_t __android_log_clockid()
+{
+  static struct cache r_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
+  static struct cache p_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
+  char c;
+
+  if (pthread_mutex_trylock(&lock_clockid)) {
+    // We are willing to accept some race in this context
+    if (!(c = p_time_cache.c)) {
+      c = r_time_cache.c;
+    }
+  } else {
+    static uint32_t serial;
+    uint32_t current_serial = __system_property_area_serial();
+    if (current_serial != serial) {
+      refresh_cache(&r_time_cache, "ro.logd.timestamp");
+      refresh_cache(&p_time_cache, "persist.logd.timestamp");
+      serial = current_serial;
+    }
+    if (!(c = p_time_cache.c)) {
+      c = r_time_cache.c;
+    }
+
+    pthread_mutex_unlock(&lock_clockid);
+  }
+
+  return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+}
+
 struct log_time { // Wire format
   uint32_t tv_sec;
   uint32_t tv_nsec;
@@ -501,7 +563,7 @@
   vec[1].iov_base = &tid;
   vec[1].iov_len = sizeof(tid);
   timespec ts;
-  clock_gettime(CLOCK_REALTIME, &ts);
+  clock_gettime(__android_log_clockid(), &ts);
   log_time realtime_ts;
   realtime_ts.tv_sec = ts.tv_sec;
   realtime_ts.tv_nsec = ts.tv_nsec;
@@ -544,7 +606,7 @@
   vec[1].iov_base = &tid;
   vec[1].iov_len = sizeof(tid);
   timespec ts;
-  clock_gettime(CLOCK_REALTIME, &ts);
+  clock_gettime(__android_log_clockid(), &ts);
   log_time realtime_ts;
   realtime_ts.tv_sec = ts.tv_sec;
   realtime_ts.tv_nsec = ts.tv_nsec;
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index 9bc80a2..57a8cdf 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -27,6 +27,7 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
@@ -53,10 +54,14 @@
     return MAP_FAILED;
   }
 
-  bool is_private_anonymous = (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) != 0;
+  bool is_private_anonymous =
+      (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
+  bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
+
   void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
 
-  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE && is_private_anonymous) {
+  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
+      is_private_anonymous && !is_stack_or_grows_down) {
     ErrnoRestorer errno_restorer;
     int rc = madvise(result, size, MADV_MERGEABLE);
     if (rc == -1 && errno == EINVAL) {
diff --git a/libc/bionic/mremap.cpp b/libc/bionic/mremap.cpp
index 4892b1d..6653d43 100644
--- a/libc/bionic/mremap.cpp
+++ b/libc/bionic/mremap.cpp
@@ -26,12 +26,24 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <sys/mman.h>
 #include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "private/bionic_macros.h"
 
 extern "C" void* ___mremap(void*, size_t, size_t, int, void*);
 
 void* mremap(void* old_address, size_t old_size, size_t new_size, int flags, ...) {
+  // prevent allocations large enough for `end - start` to overflow
+  size_t rounded = BIONIC_ALIGN(new_size, PAGE_SIZE);
+  if (rounded < new_size || rounded > PTRDIFF_MAX) {
+    errno = ENOMEM;
+    return MAP_FAILED;
+  }
+
   void* new_address = nullptr;
   // The optional argument is only valid if the MREMAP_FIXED flag is set,
   // so we assume it's not present otherwise.
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index d6b8e8f..0429430 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -47,6 +47,8 @@
 
 #include "private/libc_logging.h"
 
+extern "C" {
+
 // Brillo doesn't need to support any legacy cruft.
 #if !defined(__BRILLO__)
 
@@ -55,29 +57,27 @@
 
 // These were accidentally declared in <unistd.h> because we stupidly used to inline
 // getpagesize() and __getpageshift(). Needed for backwards compatibility with old NDK apps.
-extern "C" {
-  unsigned int __page_size = PAGE_SIZE;
-  unsigned int __page_shift = 12;
-}
+unsigned int __page_size = PAGE_SIZE;
+unsigned int __page_shift = 12;
 
 // TODO: remove this backward compatibility hack (for jb-mr1 strace binaries).
-extern "C" pid_t __wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
+pid_t __wait4(pid_t pid, int* status, int options, struct rusage* rusage) {
   return wait4(pid, status, options, rusage);
 }
 
 // TODO: does anything still need this?
-extern "C" int __open() {
+int __open() {
   abort();
 }
 
 // TODO: does anything still need this?
-extern "C" void** __get_tls() {
+void** __get_tls() {
 #include "private/__get_tls.h"
   return __get_tls();
 }
 
 // This non-standard function was in our <string.h> for some reason.
-extern "C" void memswap(void* m1, void* m2, size_t n) {
+void memswap(void* m1, void* m2, size_t n) {
   char* p = reinterpret_cast<char*>(m1);
   char* p_end = p + n;
   char* q = reinterpret_cast<char*>(m2);
@@ -90,13 +90,13 @@
   }
 }
 
-extern "C" int pthread_attr_setstackaddr(pthread_attr_t*, void*) {
+int pthread_attr_setstackaddr(pthread_attr_t*, void*) {
   // This was removed from POSIX.1-2008, and is not implemented on bionic.
   // Needed for ABI compatibility with the NDK.
   return ENOSYS;
 }
 
-extern "C" int pthread_attr_getstackaddr(const pthread_attr_t* attr, void** stack_addr) {
+int pthread_attr_getstackaddr(const pthread_attr_t* attr, void** stack_addr) {
   // This was removed from POSIX.1-2008.
   // Needed for ABI compatibility with the NDK.
   *stack_addr = (char*)attr->stack_base + attr->stack_size;
@@ -104,7 +104,7 @@
 }
 
 // Non-standard cruft that should only ever have been in system/core/toolbox.
-extern "C" char* strtotimeval(const char* str, struct timeval* ts) {
+char* strtotimeval(const char* str, struct timeval* ts) {
   char* s;
   ts->tv_sec = strtoumax(str, &s, 10);
 
@@ -146,7 +146,7 @@
 }
 
 // This non-standard function was in our <inttypes.h> for some reason.
-extern "C" uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) {
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) {
   const unsigned char*  p   = (const unsigned char *)nptr;
   const unsigned char*  end = p + n;
   int                   minus = 0;
@@ -194,12 +194,12 @@
 }
 
 // This non-standard function was in our <inttypes.h> for some reason.
-extern "C" intmax_t strntoimax(const char* nptr, char** endptr, int base, size_t n) {
+intmax_t strntoimax(const char* nptr, char** endptr, int base, size_t n) {
   return (intmax_t) strntoumax(nptr, endptr, base, n);
 }
 
 // POSIX calls this dprintf, but LP32 Android had fdprintf instead.
-extern "C" int fdprintf(int fd, const char* fmt, ...) {
+int fdprintf(int fd, const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   int rc = vdprintf(fd, fmt, ap);
@@ -208,7 +208,7 @@
 }
 
 // POSIX calls this vdprintf, but LP32 Android had fdprintf instead.
-extern "C" int vfdprintf(int fd, const char* fmt, va_list ap) {
+int vfdprintf(int fd, const char* fmt, va_list ap) {
   return vdprintf(fd, fmt, ap);
 }
 
@@ -219,64 +219,64 @@
 #undef __futex_wait
 
 // This used to be in <sys/atomics.h>.
-extern "C" int __futex_wake(volatile void* ftx, int count) {
+int __futex_wake(volatile void* ftx, int count) {
   return __real_futex_wake(ftx, count);
 }
 
 // This used to be in <sys/atomics.h>.
-extern "C" int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
+int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
   return __real_futex_wait(ftx, value, timeout);
 }
 
 // Unity's libmono uses this.
-extern "C" int tkill(pid_t tid, int sig) {
+int tkill(pid_t tid, int sig) {
   return syscall(__NR_tkill, tid, sig);
 }
 
 // This was removed from POSIX 2008.
-extern "C" wchar_t* wcswcs(wchar_t* haystack, wchar_t* needle) {
+wchar_t* wcswcs(wchar_t* haystack, wchar_t* needle) {
   return wcsstr(haystack, needle);
 }
 
 // This was removed from POSIX 2008.
-extern "C" sighandler_t bsd_signal(int signum, sighandler_t handler) {
+sighandler_t bsd_signal(int signum, sighandler_t handler) {
   return signal(signum, handler);
 }
 
 #if !defined(__i386__)
 // This was removed from POSIX 2008.
 #undef bcopy
-extern "C" void bcopy(const void* src, void* dst, size_t n) {
-  memcpy(dst, src, n);
+void bcopy(const void* src, void* dst, size_t n) {
+  memmove(dst, src, n);
 }
 #else
 // x86 has an assembler implementation.
 #endif
 
 // sysv_signal() was never in POSIX.
-extern sighandler_t _signal(int signum, sighandler_t handler, int flags);
-extern "C" sighandler_t sysv_signal(int signum, sighandler_t handler) {
+extern "C++" sighandler_t _signal(int signum, sighandler_t handler, int flags);
+sighandler_t sysv_signal(int signum, sighandler_t handler) {
   return _signal(signum, handler, SA_RESETHAND);
 }
 
 // This is a system call that was never in POSIX. Use readdir(3) instead.
-extern "C" int __getdents64(unsigned int, dirent*, unsigned int);
-extern "C" int getdents(unsigned int fd, dirent* dirp, unsigned int count) {
+int __getdents64(unsigned int, dirent*, unsigned int);
+int getdents(unsigned int fd, dirent* dirp, unsigned int count) {
   return __getdents64(fd, dirp, count);
 }
 
 // This is a BSDism that we never implemented correctly. Used by Firefox.
-extern "C" int issetugid() {
+int issetugid() {
   return 0;
 }
 
 // This was removed from POSIX 2004.
-extern "C" pid_t wait3(int* status, int options, struct rusage* rusage) {
+pid_t wait3(int* status, int options, struct rusage* rusage) {
   return wait4(-1, status, options, rusage);
 }
 
 // This was removed from POSIX 2004.
-extern "C" int getdtablesize() {
+int getdtablesize() {
   struct rlimit r;
 
   if (getrlimit(RLIMIT_NOFILE, &r) < 0) {
@@ -286,6 +286,10 @@
   return r.rlim_cur;
 }
 
+// A leaked BSD stdio implementation detail that's now a no-op.
+void __sinit() {}
+int __sdidinit = 1;
+
 // Only used by ftime, which was removed from POSIX 2008.
 struct timeb {
   time_t          time;
@@ -295,7 +299,7 @@
 };
 
 // This was removed from POSIX 2008.
-extern "C" int ftime(struct timeb* tb) {
+int ftime(struct timeb* tb) {
   struct timeval  tv;
   struct timezone tz;
 
@@ -317,35 +321,35 @@
 }
 
 // This was removed from POSIX 2008.
-extern "C" char* index(const char* str, int ch) {
+char* index(const char* str, int ch) {
   return strchr(str, ch);
 }
 
 // This was removed from BSD.
-extern "C" void arc4random_stir(void) {
+void arc4random_stir(void) {
   // The current implementation stirs itself as needed.
 }
 
 // This was removed from BSD.
-extern "C" void arc4random_addrandom(unsigned char*, int) {
+void arc4random_addrandom(unsigned char*, int) {
   // The current implementation adds randomness as needed.
 }
 
 // Old versions of the NDK did not export malloc_usable_size, but did
 // export dlmalloc_usable_size. We are moving away from dlmalloc in L
 // so make this call malloc_usable_size.
-extern "C" size_t dlmalloc_usable_size(void* ptr) {
+size_t dlmalloc_usable_size(void* ptr) {
   return malloc_usable_size(ptr);
 }
 
 // In L we added a public pthread_gettid_np, but some apps were using the private API.
-extern "C" pid_t __pthread_gettid(pthread_t t) {
+pid_t __pthread_gettid(pthread_t t) {
   return pthread_gettid_np(t);
 }
 
 // Older versions of apportable used dlmalloc directly instead of malloc,
 // so export this compatibility shim that simply calls malloc.
-extern "C" void* dlmalloc(size_t size) {
+void* dlmalloc(size_t size) {
   return malloc(size);
 }
 
@@ -353,13 +357,13 @@
 #include "pthread_internal.h"
 #undef __get_thread
 // Various third-party apps contain a backport of our pthread_rwlock implementation that uses this.
-extern "C" pthread_internal_t* __get_thread() {
+pthread_internal_t* __get_thread() {
   return __real_get_thread();
 }
 
 // This one exists only for the LP32 NDK and is not present anywhere else.
-extern "C" long __set_errno_internal(int);
-extern "C" long __set_errno(int n) {
+extern long __set_errno_internal(int);
+long __set_errno(int n) {
   return __set_errno_internal(n);
 }
 
@@ -367,25 +371,27 @@
 
 // This was never implemented in bionic, only needed for ABI compatibility with the NDK.
 // In the M time frame, over 1000 apps have a reference to this!
-extern "C" void endpwent() { }
+void endpwent() { }
 
 // Since dlmalloc_inspect_all and dlmalloc_trim are exported for systems
 // that use dlmalloc, be consistent and export them everywhere.
 #if defined(USE_JEMALLOC)
-extern "C" void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
+void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
 }
-extern "C" int dlmalloc_trim(size_t) {
+int dlmalloc_trim(size_t) {
     return 0;
 }
 #else
-extern "C" void dlmalloc_inspect_all_real(void (*)(void*, void*, size_t, void*), void*);
-extern "C" void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void* arg) {
+void dlmalloc_inspect_all_real(void (*)(void*, void*, size_t, void*), void*);
+void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void* arg) {
   dlmalloc_inspect_all_real(handler, arg);
 }
-extern "C" int dlmalloc_trim_real(size_t);
-extern "C" int dlmalloc_trim(size_t pad) {
+int dlmalloc_trim_real(size_t);
+int dlmalloc_trim(size_t pad) {
   return dlmalloc_trim_real(pad);
 }
 #endif
 
 #endif // !defined(__BRILLO__)
+
+} // extern "C"
diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
index 093ffd2..2200a6c 100644
--- a/libc/bionic/pthread_atfork.cpp
+++ b/libc/bionic/pthread_atfork.cpp
@@ -45,7 +45,7 @@
 
 class atfork_list_t {
  public:
-  atfork_list_t() : first_(nullptr), last_(nullptr) {}
+  constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
 
   template<typename F>
   void walk_forward(F f) {
diff --git a/libc/bionic/pthread_barrier.cpp b/libc/bionic/pthread_barrier.cpp
index 3227daf..1bcd12a 100644
--- a/libc/bionic/pthread_barrier.cpp
+++ b/libc/bionic/pthread_barrier.cpp
@@ -118,7 +118,7 @@
   // threads have left the barrier. Use acquire operation here to synchronize with
   // the last thread leaving the previous cycle, so we can read correct wait_count below.
   while(atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
-    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, nullptr);
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
   }
 
   uint32_t prev_wait_count = atomic_load_explicit(&barrier->wait_count, memory_order_relaxed);
@@ -152,7 +152,7 @@
     // Use acquire operation here to synchronize between the last thread entering the
     // barrier with all threads leaving the barrier.
     while (atomic_load_explicit(&barrier->state, memory_order_acquire) == WAIT) {
-      __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, nullptr);
+      __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, false, nullptr);
     }
   }
   // Use release operation here to make it not reordered with previous operations.
@@ -173,7 +173,7 @@
   // Use acquire operation here to synchronize with the last thread leaving the barrier.
   // So we can read correct wait_count below.
   while (atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
-    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, nullptr);
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
   }
   if (atomic_load_explicit(&barrier->wait_count, memory_order_relaxed) != 0) {
     return EBUSY;
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index 4a69da5..adbce07 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -111,8 +111,8 @@
     return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed));
   }
 
-  int get_clock() {
-    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed));
+  bool use_realtime_clock() {
+    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed)) == CLOCK_REALTIME;
   }
 
 #if defined(__LP64__)
@@ -170,12 +170,17 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                             const timespec* rel_timeout_or_null) {
-  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
+                                    bool use_realtime_clock, const timespec* abs_timeout_or_null) {
+  int result = check_timespec(abs_timeout_or_null);
+  if (result != 0) {
+    return result;
+  }
 
+  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
   pthread_mutex_unlock(mutex);
-  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, rel_timeout_or_null);
+  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
+                               use_realtime_clock, abs_timeout_or_null);
   pthread_mutex_lock(mutex);
 
   if (status == -ETIMEDOUT) {
@@ -184,21 +189,6 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                    const timespec* abs_timeout_or_null, clockid_t clock) {
-  timespec ts;
-  timespec* rel_timeout = NULL;
-
-  if (abs_timeout_or_null != NULL) {
-    rel_timeout = &ts;
-    if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-      return ETIMEDOUT;
-    }
-  }
-
-  return __pthread_cond_timedwait_relative(cond, mutex, rel_timeout);
-}
-
 int pthread_cond_broadcast(pthread_cond_t* cond_interface) {
   return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX);
 }
@@ -209,14 +199,14 @@
 
 int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) {
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, NULL, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, false, nullptr);
 }
 
 int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex,
                            const timespec *abstime) {
 
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, abstime, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
 }
 
 #if !defined(__LP64__)
@@ -225,8 +215,7 @@
                                                 pthread_mutex_t* mutex,
                                                 const timespec* abs_timeout) {
 
-  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, abs_timeout,
-                                  CLOCK_MONOTONIC);
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
 }
 
 extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
@@ -238,8 +227,13 @@
 extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
                                                   pthread_mutex_t* mutex,
                                                   const timespec* rel_timeout) {
-
-  return __pthread_cond_timedwait_relative(__get_internal_cond(cond_interface), mutex, rel_timeout);
+  timespec ts;
+  timespec* abs_timeout = nullptr;
+  if (rel_timeout != nullptr) {
+    absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_REALTIME);
+    abs_timeout = &ts;
+  }
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout);
 }
 
 extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index ce43009..34826db 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -53,13 +53,6 @@
 
 // This code is used both by each new pthread and the code that initializes the main thread.
 void __init_tls(pthread_internal_t* thread) {
-  if (thread->mmap_size == 0) {
-    // If the TLS area was not allocated by mmap(), it may not have been cleared to zero.
-    // So assume the worst and zero the TLS area.
-    memset(thread->tls, 0, sizeof(thread->tls));
-    memset(thread->key_data, 0, sizeof(thread->key_data));
-  }
-
   // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
   thread->tls[TLS_SLOT_SELF] = thread->tls;
   thread->tls[TLS_SLOT_THREAD_ID] = thread;
@@ -175,6 +168,11 @@
                 (reinterpret_cast<uintptr_t>(stack_top) - sizeof(pthread_internal_t)) & ~0xf);
 
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
+  if (mmap_size == 0) {
+    // If thread was not allocated by mmap(), it may not have been cleared to zero.
+    // So assume the worst and zero it.
+    memset(thread, 0, sizeof(pthread_internal_t));
+  }
   attr->stack_size = stack_top - reinterpret_cast<uint8_t*>(attr->stack_base);
 
   thread->mmap_size = mmap_size;
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index d5d62a7..f96e9d2 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -52,6 +52,8 @@
   THREAD_DETACHED
 };
 
+struct thread_local_dtor;
+
 struct pthread_internal_t {
   struct pthread_internal_t* next;
   struct pthread_internal_t* prev;
@@ -94,6 +96,8 @@
 
   size_t mmap_size;
 
+  thread_local_dtor* thread_local_dtors;
+
   void* tls[BIONIC_TLS_SLOTS];
 
   pthread_key_data_t key_data[BIONIC_PTHREAD_KEY_COUNT];
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 851fc3d..cad138c 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -166,11 +166,14 @@
 #define  MUTEX_STATE_BITS_LOCKED_UNCONTENDED  MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_UNCONTENDED)
 #define  MUTEX_STATE_BITS_LOCKED_CONTENDED    MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_CONTENDED)
 
-/* return true iff the mutex if locked with no waiters */
-#define  MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v)  (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED)
+// Return true iff the mutex is unlocked.
+#define MUTEX_STATE_BITS_IS_UNLOCKED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_UNLOCKED)
 
-/* return true iff the mutex if locked with maybe waiters */
-#define  MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v)   (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED)
+// Return true iff the mutex is locked with no waiters.
+#define MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v)  (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED)
+
+// return true iff the mutex is locked with maybe waiters.
+#define MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v)   (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED)
 
 /* used to flip from LOCKED_UNCONTENDED to LOCKED_CONTENDED */
 #define  MUTEX_STATE_BITS_FLIP_CONTENTION(v)      ((v) ^ (MUTEX_STATE_BITS_LOCKED_CONTENDED ^ MUTEX_STATE_BITS_LOCKED_UNCONTENDED))
@@ -296,11 +299,15 @@
  */
 static inline __always_inline int __pthread_normal_mutex_lock(pthread_mutex_internal_t* mutex,
                                                               uint16_t shared,
-                                                              const timespec* abs_timeout_or_null,
-                                                              clockid_t clock) {
+                                                              bool use_realtime_clock,
+                                                              const timespec* abs_timeout_or_null) {
     if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) {
         return 0;
     }
+    int result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+        return result;
+    }
 
     ScopedTrace trace("Contending for pthread mutex");
 
@@ -317,15 +324,8 @@
     // made by other threads visible to the current CPU.
     while (atomic_exchange_explicit(&mutex->state, locked_contended,
                                     memory_order_acquire) != unlocked) {
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
-        }
-        if (__futex_wait_ex(&mutex->state, shared, locked_contended, rel_timeout) == -ETIMEDOUT) {
+        if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,
+                            abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
     }
@@ -396,14 +396,15 @@
                                                       pthread_mutex_internal_t* mutex,
                                                       uint16_t shared,
                                                       uint16_t old_state,
-                                                      const timespec* rel_timeout) {
+                                                      bool use_realtime_clock,
+                                                      const timespec* abs_timeout) {
 // __futex_wait always waits on a 32-bit value. But state is 16-bit. For a normal mutex, the owner_tid
 // field in mutex is not used. On 64-bit devices, the __pad field in mutex is not used.
 // But when a recursive or errorcheck mutex is used on 32-bit devices, we need to add the
 // owner_tid value in the value argument for __futex_wait, otherwise we may always get EAGAIN error.
 
 #if defined(__LP64__)
-  return __futex_wait_ex(&mutex->state, shared, old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, old_state, use_realtime_clock, abs_timeout);
 
 #else
   // This implementation works only when the layout of pthread_mutex_internal_t matches below expectation.
@@ -412,19 +413,21 @@
   static_assert(offsetof(pthread_mutex_internal_t, owner_tid) == 2, "");
 
   uint32_t owner_tid = atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed);
-  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state,
+                         use_realtime_clock, abs_timeout);
 #endif
 }
 
 static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,
-                                           const timespec* abs_timeout_or_null, clockid_t clock) {
+                                             bool use_realtime_clock,
+                                             const timespec* abs_timeout_or_null) {
     uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
     uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
     uint16_t shared = (old_state & MUTEX_SHARED_MASK);
 
     // Handle common case first.
     if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) {
-        return __pthread_normal_mutex_lock(mutex, shared, abs_timeout_or_null, clock);
+        return __pthread_normal_mutex_lock(mutex, shared, use_realtime_clock, abs_timeout_or_null);
     }
 
     // Do we already own this recursive or error-check mutex?
@@ -484,16 +487,13 @@
             old_state = new_state;
         }
 
-        // We are in locked_contended state, sleep until someone wakes us up.
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
+        int result = check_timespec(abs_timeout_or_null);
+        if (result != 0) {
+            return result;
         }
-        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, rel_timeout) == -ETIMEDOUT) {
+        // We are in locked_contended state, sleep until someone wakes us up.
+        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, use_realtime_clock,
+                                                 abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
         old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
@@ -518,7 +518,7 @@
         return 0;
       }
     }
-    return __pthread_mutex_lock_with_timeout(mutex, NULL, 0);
+    return __pthread_mutex_lock_with_timeout(mutex, false, nullptr);
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
@@ -613,17 +613,12 @@
 
 #if !defined(__LP64__)
 extern "C" int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex_interface, unsigned ms) {
+    timespec ts;
+    timespec_from_ms(ts, ms);
     timespec abs_timeout;
-    clock_gettime(CLOCK_MONOTONIC, &abs_timeout);
-    abs_timeout.tv_sec  += ms / 1000;
-    abs_timeout.tv_nsec += (ms % 1000) * 1000000;
-    if (abs_timeout.tv_nsec >= NS_PER_S) {
-        abs_timeout.tv_sec++;
-        abs_timeout.tv_nsec -= NS_PER_S;
-    }
-
+    absolute_timespec_from_timespec(abs_timeout, ts, CLOCK_MONOTONIC);
     int error = __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                                  &abs_timeout, CLOCK_MONOTONIC);
+                                                  false, &abs_timeout);
     if (error == ETIMEDOUT) {
         error = EBUSY;
     }
@@ -633,14 +628,18 @@
 
 int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const timespec* abs_timeout) {
     return __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                             abs_timeout, CLOCK_REALTIME);
+                                             true, abs_timeout);
 }
 
 int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
-    // Use trylock to ensure that the mutex is valid and not already locked.
-    int error = pthread_mutex_trylock(mutex_interface);
-    if (error != 0) {
-        return error;
+    pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
+    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
+    // Store 0xffff to make the mutex unusable. Although POSIX standard says it is undefined
+    // behavior to destroy a locked mutex, we prefer not to change mutex->state in that situation.
+    if (MUTEX_STATE_BITS_IS_UNLOCKED(old_state) &&
+        atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, 0xffff,
+                                                memory_order_relaxed, memory_order_relaxed)) {
+      return 0;
     }
-    return 0;
+    return EBUSY;
 }
diff --git a/libc/bionic/pthread_once.cpp b/libc/bionic/pthread_once.cpp
index 7688a23..f48eadc 100644
--- a/libc/bionic/pthread_once.cpp
+++ b/libc/bionic/pthread_once.cpp
@@ -79,7 +79,7 @@
     }
 
     // The initialization is underway, wait for its finish.
-    __futex_wait_ex(once_control_ptr, 0, old_value, NULL);
+    __futex_wait_ex(once_control_ptr, 0, old_value, false, nullptr);
     old_value = atomic_load_explicit(once_control_ptr, memory_order_acquire);
   }
 }
diff --git a/libc/bionic/pthread_rwlock.cpp b/libc/bionic/pthread_rwlock.cpp
index 934210e..b1c48c8 100644
--- a/libc/bionic/pthread_rwlock.cpp
+++ b/libc/bionic/pthread_rwlock.cpp
@@ -294,9 +294,13 @@
   }
 
   while (true) {
-    int ret = __pthread_rwlock_tryrdlock(rwlock);
-    if (ret == 0 || ret == EAGAIN) {
-      return ret;
+    int result = __pthread_rwlock_tryrdlock(rwlock);
+    if (result == 0 || result == EAGAIN) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -304,16 +308,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_reader_count++;
 
@@ -327,10 +321,10 @@
     int old_serial = rwlock->pending_reader_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -341,7 +335,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -372,9 +366,13 @@
     return EDEADLK;
   }
   while (true) {
-    int ret = __pthread_rwlock_trywrlock(rwlock);
-    if (ret == 0) {
-      return ret;
+    int result = __pthread_rwlock_trywrlock(rwlock);
+    if (result == 0) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -382,16 +380,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_writer_count++;
 
@@ -401,10 +389,10 @@
     int old_serial = rwlock->pending_writer_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_write_lock(old_state)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -415,7 +403,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -427,7 +415,7 @@
   if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedrdlock(rwlock, NULL);
+  return __pthread_rwlock_timedrdlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
@@ -446,7 +434,7 @@
   if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedwrlock(rwlock, NULL);
+  return __pthread_rwlock_timedwrlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
diff --git a/libc/bionic/pthread_spinlock.cpp b/libc/bionic/pthread_spinlock.cpp
new file mode 100644
index 0000000..f26f283
--- /dev/null
+++ b/libc/bionic/pthread_spinlock.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <pthread.h>
+
+#include "private/bionic_lock.h"
+
+// User-level spinlocks can be hazardous to battery life on Android.
+// We implement a simple compromise that behaves mostly like a spinlock,
+// but prevents excessively long spinning.
+
+struct pthread_spinlock_internal_t {
+  Lock lock;
+};
+
+static_assert(sizeof(pthread_spinlock_t) == sizeof(pthread_spinlock_internal_t),
+              "pthread_spinlock_t should actually be pthread_spinlock_internal_t.");
+
+static_assert(alignof(pthread_spinlock_t) >= 4,
+              "pthread_spinlock_t should fulfill the alignment of pthread_spinlock_internal_t.");
+
+static inline pthread_spinlock_internal_t* __get_internal_spinlock(pthread_spinlock_t* lock) {
+  return reinterpret_cast<pthread_spinlock_internal_t*>(lock);
+}
+
+int pthread_spin_init(pthread_spinlock_t* lock_interface, int pshared) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  lock->lock.init(pshared);
+  return 0;
+}
+
+int pthread_spin_destroy(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  return lock->lock.trylock() ? 0 : EBUSY;
+}
+
+int pthread_spin_trylock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  return lock->lock.trylock() ? 0 : EBUSY;
+}
+
+int pthread_spin_lock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  for (int i = 0; i < 10000; ++i) {
+    if (lock->lock.trylock()) {
+      return 0;
+    }
+  }
+  lock->lock.lock();
+  return 0;
+}
+
+int pthread_spin_unlock(pthread_spinlock_t* lock_interface) {
+  pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface);
+  lock->lock.unlock();
+  return 0;
+}
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index ff84443..79b5d63 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -220,7 +220,7 @@
       return 0;
     }
 
-    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, NULL);
+    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
   }
 }
 
@@ -235,36 +235,29 @@
   }
 
   // Check it as per POSIX.
-  if (abs_timeout == NULL || abs_timeout->tv_sec < 0 || abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= NS_PER_S) {
-    errno = EINVAL;
+  int result = check_timespec(abs_timeout);
+  if (result != 0) {
+    errno = result;
     return -1;
   }
 
   unsigned int shared = SEM_GET_SHARED(sem_count_ptr);
 
   while (true) {
-    // POSIX mandates CLOCK_REALTIME here.
-    timespec ts;
-    if (!timespec_from_absolute_timespec(ts, *abs_timeout, CLOCK_REALTIME)) {
-      errno = ETIMEDOUT;
-      return -1;
-    }
-
     // Try to grab the semaphore. If the value was 0, this will also change it to -1.
     if (__sem_dec(sem_count_ptr) > 0) {
-      break;
+      return 0;
     }
 
     // Contention detected. Wait for a wakeup event.
-    int ret = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, &ts);
+    int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, true, abs_timeout);
 
     // Return in case of timeout or interrupt.
-    if (ret == -ETIMEDOUT || ret == -EINTR) {
-      errno = -ret;
+    if (result == -ETIMEDOUT || result == -EINTR) {
+      errno = -result;
       return -1;
     }
   }
-  return 0;
 }
 
 int sem_post(sem_t* sem) {
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 9fe982a..b9a373e 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -25,34 +25,38 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <new>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
+#include <ctype.h>
 #include <errno.h>
-#include <poll.h>
 #include <fcntl.h>
+#include <poll.h>
+#include <stdatomic.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <new>
 
+#include <linux/xattr.h>
+#include <netinet/in.h>
 #include <sys/mman.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <sys/select.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/xattr.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 #include <sys/system_properties.h>
 
 #include "private/bionic_futex.h"
+#include "private/bionic_lock.h"
 #include "private/bionic_macros.h"
+#include "private/libc_logging.h"
 
 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
 
@@ -192,7 +196,7 @@
     }
 };
 
-static char property_filename[PATH_MAX] = PROP_FILENAME;
+static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
 static bool compat_mode = false;
 static size_t pa_data_size;
 static size_t pa_size;
@@ -216,13 +220,12 @@
     return atoi(env);
 }
 
-static int map_prop_area_rw()
-{
+static prop_area* map_prop_area_rw(const char* filename, const char* context,
+                                   bool* fsetxattr_failed) {
     /* dev is a tmpfs that we can use to carve a shared workspace
      * out of, so let's do that...
      */
-    const int fd = open(property_filename,
-                        O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
+    const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
 
     if (fd < 0) {
         if (errno == EACCES) {
@@ -231,12 +234,31 @@
              */
             abort();
         }
-        return -1;
+        return nullptr;
+    }
+
+    if (context) {
+        if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
+            __libc_format_log(ANDROID_LOG_ERROR, "libc",
+                              "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
+            /*
+             * fsetxattr() will fail during system properties tests due to selinux policy.
+             * We do not want to create a custom policy for the tester, so we will continue in
+             * this function but set a flag that an error has occurred.
+             * Init, which is the only daemon that should ever call this function will abort
+             * when this error occurs.
+             * Otherwise, the tester will ignore it and continue, albeit without any selinux
+             * property separation.
+             */
+            if (fsetxattr_failed) {
+                *fsetxattr_failed = true;
+            }
+        }
     }
 
     if (ftruncate(fd, PA_SIZE) < 0) {
         close(fd);
-        return -1;
+        return nullptr;
     }
 
     pa_size = PA_SIZE;
@@ -246,29 +268,26 @@
     void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     if (memory_area == MAP_FAILED) {
         close(fd);
-        return -1;
+        return nullptr;
     }
 
     prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
 
-    /* plug into the lib property services */
-    __system_property_area__ = pa;
-
     close(fd);
-    return 0;
+    return pa;
 }
 
-static int map_fd_ro(const int fd) {
+static prop_area* map_fd_ro(const int fd) {
     struct stat fd_stat;
     if (fstat(fd, &fd_stat) < 0) {
-        return -1;
+        return nullptr;
     }
 
     if ((fd_stat.st_uid != 0)
             || (fd_stat.st_gid != 0)
             || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
             || (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area))) ) {
-        return -1;
+        return nullptr;
     }
 
     pa_size = fd_stat.st_size;
@@ -276,7 +295,7 @@
 
     void* const map_result = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);
     if (map_result == MAP_FAILED) {
-        return -1;
+        return nullptr;
     }
 
     prop_area* pa = reinterpret_cast<prop_area*>(map_result);
@@ -284,22 +303,20 @@
         (pa->version() != PROP_AREA_VERSION &&
          pa->version() != PROP_AREA_VERSION_COMPAT)) {
         munmap(pa, pa_size);
-        return -1;
+        return nullptr;
     }
 
     if (pa->version() == PROP_AREA_VERSION_COMPAT) {
         compat_mode = true;
     }
 
-    __system_property_area__ = pa;
-    return 0;
+    return pa;
 }
 
-static int map_prop_area()
-{
-    int fd = open(property_filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
+static prop_area* map_prop_area(const char* filename, bool is_legacy) {
+    int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
     bool close_fd = true;
-    if (fd == -1 && errno == ENOENT) {
+    if (fd == -1 && errno == ENOENT && is_legacy) {
         /*
          * For backwards compatibility, if the file doesn't
          * exist, we use the environment to get the file descriptor.
@@ -308,16 +325,18 @@
          * returns other errors such as ENOMEM or ENFILE, since it
          * might be possible for an external program to trigger this
          * condition.
+         * Only do this for the legacy prop file, secured prop files
+         * do not have a backup
          */
         fd = get_fd_from_env();
         close_fd = false;
     }
 
     if (fd < 0) {
-        return -1;
+        return nullptr;
     }
 
-    const int map_result = map_fd_ro(fd);
+    prop_area* map_result = map_fd_ro(fd);
     if (close_fd) {
         close(fd);
     }
@@ -623,9 +642,335 @@
     return foreach_property(root_node(), propfn, cookie);
 }
 
+struct context_node {
+    context_node(struct context_node* next, const char* context, prop_area* pa)
+        : context(strdup(context)), pa(pa), checked_access(false), next(next) {
+        lock.init(false);
+    }
+    ~context_node() {
+        if (pa) {
+            munmap(pa, pa_size);
+        }
+        free(context);
+    }
+    Lock lock;
+    char* context;
+    prop_area* pa;
+    bool checked_access;
+    struct context_node* next;
+};
+
+struct prefix_node {
+    prefix_node(struct prefix_node* next, const char* prefix, context_node* context)
+        : prefix(strdup(prefix)), prefix_len(strlen(prefix)), context(context), next(next) {
+    }
+    ~prefix_node() {
+        free(prefix);
+    }
+    char* prefix;
+    const size_t prefix_len;
+    context_node* context;
+    struct prefix_node* next;
+};
+
+template <typename List, typename... Args>
+static inline void list_add(List** list, Args... args) {
+    *list = new List(*list, args...);
+}
+
+static void list_add_after_len(prefix_node** list, const char* prefix, context_node* context) {
+    size_t prefix_len = strlen(prefix);
+
+    auto next_list = list;
+
+    while (*next_list) {
+        if ((*next_list)->prefix_len < prefix_len || (*next_list)->prefix[0] == '*') {
+            list_add(next_list, prefix, context);
+            return;
+        }
+        next_list = &(*next_list)->next;
+    }
+    list_add(next_list, prefix, context);
+}
+
+template <typename List, typename Func>
+static void list_foreach(List* list, Func func) {
+    while (list) {
+        func(list);
+        list = list->next;
+    }
+}
+
+template <typename List, typename Func>
+static List* list_find(List* list, Func func) {
+    while (list) {
+        if (func(list)) {
+            return list;
+        }
+        list = list->next;
+    }
+    return nullptr;
+}
+
+template <typename List>
+static void list_free(List** list) {
+    while (*list) {
+        auto old_list = *list;
+        *list = old_list->next;
+        delete old_list;
+    }
+}
+
+static prefix_node* prefixes = nullptr;
+static context_node* contexts = nullptr;
+
+/*
+ * pthread_mutex_lock() calls into system_properties in the case of contention.
+ * This creates a risk of dead lock if any system_properties functions
+ * use pthread locks after system_property initialization.
+ *
+ * For this reason, the below three functions use a bionic Lock and static
+ * allocation of memory for each filename.
+ */
+
+static bool open_prop_file(context_node* cnode, bool access_rw, bool* fsetxattr_failed) {
+    cnode->lock.lock();
+    if (cnode->pa) {
+        cnode->lock.unlock();
+        return true;
+    }
+
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        cnode->lock.unlock();
+        return false;
+    }
+
+    if (access_rw) {
+        cnode->pa = map_prop_area_rw(filename, cnode->context, fsetxattr_failed);
+    } else {
+        cnode->pa = map_prop_area(filename, false);
+    }
+    cnode->lock.unlock();
+    return cnode->pa;
+}
+
+static bool check_access(context_node* cnode) {
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, cnode->context);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        return false;
+    }
+
+    return access(filename, R_OK) == 0;
+}
+
+static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
+    char filename[PROP_FILENAME_MAX];
+    int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
+    if (len < 0 || len > PROP_FILENAME_MAX) {
+        __system_property_area__ = nullptr;
+        return false;
+    }
+
+    if (access_rw) {
+        __system_property_area__ =
+            map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
+    } else {
+        __system_property_area__ = map_prop_area(filename, false);
+    }
+    return __system_property_area__;
+}
+
+static prop_area* get_prop_area_for_name(const char* name) {
+    auto entry = list_find(prefixes, [name](prefix_node* l) {
+        return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
+    });
+    if (!entry) {
+        return nullptr;
+    }
+
+    auto cnode = entry->context;
+    if (!cnode->pa) {
+        open_prop_file(cnode, false, nullptr);
+    }
+    return cnode->pa;
+}
+
+/*
+ * The below two functions are duplicated from label_support.c in libselinux.
+ * TODO: Find a location suitable for these functions such that both libc and
+ * libselinux can share a common source file.
+ */
+
+/*
+ * The read_spec_entries and read_spec_entry functions may be used to
+ * replace sscanf to read entries from spec files. The file and
+ * property services now use these.
+ */
+
+/* Read an entry from a spec file (e.g. file_contexts) */
+static inline int read_spec_entry(char **entry, char **ptr, int *len)
+{
+    *entry = NULL;
+    char *tmp_buf = NULL;
+
+    while (isspace(**ptr) && **ptr != '\0')
+        (*ptr)++;
+
+    tmp_buf = *ptr;
+    *len = 0;
+
+    while (!isspace(**ptr) && **ptr != '\0') {
+        (*ptr)++;
+        (*len)++;
+    }
+
+    if (*len) {
+        *entry = strndup(tmp_buf, *len);
+        if (!*entry)
+            return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * line_buf - Buffer containing the spec entries .
+ * num_args - The number of spec parameter entries to process.
+ * ...      - A 'char **spec_entry' for each parameter.
+ * returns  - The number of items processed.
+ *
+ * This function calls read_spec_entry() to do the actual string processing.
+ */
+static int read_spec_entries(char *line_buf, int num_args, ...)
+{
+    char **spec_entry, *buf_p;
+    int len, rc, items, entry_len = 0;
+    va_list ap;
+
+    len = strlen(line_buf);
+    if (line_buf[len - 1] == '\n')
+        line_buf[len - 1] = '\0';
+    else
+        /* Handle case if line not \n terminated by bumping
+         * the len for the check below (as the line is NUL
+         * terminated by getline(3)) */
+        len++;
+
+    buf_p = line_buf;
+    while (isspace(*buf_p))
+        buf_p++;
+
+    /* Skip comment lines and empty lines. */
+    if (*buf_p == '#' || *buf_p == '\0')
+        return 0;
+
+    /* Process the spec file entries */
+    va_start(ap, num_args);
+
+    items = 0;
+    while (items < num_args) {
+        spec_entry = va_arg(ap, char **);
+
+        if (len - 1 == buf_p - line_buf) {
+            va_end(ap);
+            return items;
+        }
+
+        rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
+        if (rc < 0) {
+            va_end(ap);
+            return rc;
+        }
+        if (entry_len)
+            items++;
+    }
+    va_end(ap);
+    return items;
+}
+
+static bool initialize_properties() {
+    list_free(&prefixes);
+    list_free(&contexts);
+
+    FILE* file = fopen("/property_contexts", "re");
+
+    if (!file) {
+        return false;
+    }
+
+    char* buffer = nullptr;
+    size_t line_len;
+    char* prop_prefix = nullptr;
+    char* context = nullptr;
+
+    while (getline(&buffer, &line_len, file) > 0) {
+        int items = read_spec_entries(buffer, 2, &prop_prefix, &context);
+        if (items <= 0) {
+            continue;
+        }
+        if (items == 1) {
+            free(prop_prefix);
+            continue;
+        }
+        /*
+         * init uses ctl.* properties as an IPC mechanism and does not write them
+         * to a property file, therefore we do not need to create property files
+         * to store them.
+         */
+        if (!strncmp(prop_prefix, "ctl.", 4)) {
+            free(prop_prefix);
+            free(context);
+            continue;
+        }
+
+        auto old_context = list_find(
+            contexts, [context](context_node* l) { return !strcmp(l->context, context); });
+        if (old_context) {
+            list_add_after_len(&prefixes, prop_prefix, old_context);
+        } else {
+            list_add(&contexts, context, nullptr);
+            list_add_after_len(&prefixes, prop_prefix, contexts);
+        }
+        free(prop_prefix);
+        free(context);
+    }
+
+    free(buffer);
+    fclose(file);
+    return true;
+}
+
+static bool is_dir(const char* pathname) {
+    struct stat info;
+    if (stat(pathname, &info) == -1) {
+        return false;
+    }
+    return S_ISDIR(info.st_mode);
+}
+
 int __system_properties_init()
 {
-    return map_prop_area();
+    if (is_dir(property_filename)) {
+        if (!initialize_properties()) {
+            return -1;
+        }
+        if (!map_system_property_area(false, nullptr)) {
+            list_free(&prefixes);
+            list_free(&contexts);
+            return -1;
+        }
+    } else {
+        __system_property_area__ = map_prop_area(property_filename, true);
+        if (!__system_property_area__) {
+            return -1;
+        }
+        list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
+        list_add_after_len(&prefixes, "*", contexts);
+    }
+    return 0;
 }
 
 int __system_property_set_filename(const char *filename)
@@ -640,7 +985,23 @@
 
 int __system_property_area_init()
 {
-    return map_prop_area_rw();
+    mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+    if (!initialize_properties()) {
+        return -1;
+    }
+    bool open_prop_file_failed = false;
+    bool fsetxattr_failed = false;
+    list_foreach(contexts, [&fsetxattr_failed, &open_prop_file_failed](context_node* l) {
+        if (!open_prop_file(l, true, &fsetxattr_failed)) {
+            open_prop_file_failed = true;
+        }
+    });
+    if (open_prop_file_failed || !map_system_property_area(true, &fsetxattr_failed)) {
+        list_free(&prefixes);
+        list_free(&contexts);
+        return -1;
+    }
+    return fsetxattr_failed ? -2 : 0;
 }
 
 unsigned int __system_property_area_serial()
@@ -655,15 +1016,21 @@
 
 const prop_info *__system_property_find(const char *name)
 {
-    if (__predict_false(compat_mode)) {
-        return __system_property_find_compat(name);
-    }
-
     if (!__system_property_area__) {
         return nullptr;
     }
 
-    return __system_property_area__->find(name);
+    if (__predict_false(compat_mode)) {
+        return __system_property_find_compat(name);
+    }
+
+    prop_area* pa = get_prop_area_for_name(name);
+    if (!pa) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
+        return nullptr;
+    }
+
+    return pa->find(name);
 }
 
 // The C11 standard doesn't allow atomic loads from const fields,
@@ -738,11 +1105,15 @@
 
 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;
 
+    prop_area* pa = __system_property_area__;
+
+    if (!pa) {
+        return -1;
+    }
+
     uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
     serial |= 1;
     atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
@@ -769,8 +1140,6 @@
 int __system_property_add(const char *name, unsigned int namelen,
             const char *value, unsigned int valuelen)
 {
-    prop_area *pa = __system_property_area__;
-
     if (namelen >= PROP_NAME_MAX)
         return -1;
     if (valuelen >= PROP_VALUE_MAX)
@@ -782,17 +1151,24 @@
         return -1;
     }
 
-    bool ret = __system_property_area__->add(name, namelen, value, valuelen);
+    prop_area* pa = get_prop_area_for_name(name);
+
+    if (!pa) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
+        return -1;
+    }
+
+    bool ret = pa->add(name, namelen, value, valuelen);
     if (!ret)
         return -1;
 
     // There is only a single mutator, but we want to make sure that
     // updates are visible to a reader waiting for the update.
     atomic_store_explicit(
-        pa->serial(),
-        atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
+        __system_property_area__->serial(),
+        atomic_load_explicit(__system_property_area__->serial(), memory_order_relaxed) + 1,
         memory_order_release);
-    __futex_wake(pa->serial(), INT32_MAX);
+    __futex_wake(__system_property_area__->serial(), INT32_MAX);
     return 0;
 }
 
@@ -814,6 +1190,10 @@
     prop_area *pa = __system_property_area__;
     uint32_t my_serial;
 
+    if (!pa) {
+        return 0;
+    }
+
     do {
         __futex_wait(pa->serial(), serial, NULL);
         my_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
@@ -837,13 +1217,24 @@
 int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
         void *cookie)
 {
-    if (__predict_false(compat_mode)) {
-        return __system_property_foreach_compat(propfn, cookie);
-    }
-
     if (!__system_property_area__) {
         return -1;
     }
 
-    return __system_property_area__->foreach(propfn, cookie) ? 0 : -1;
+    if (__predict_false(compat_mode)) {
+        return __system_property_foreach_compat(propfn, cookie);
+    }
+
+    list_foreach(contexts, [propfn, cookie](context_node* l) {
+        if (!l->pa && !l->checked_access) {
+            if (check_access(l)) {
+                open_prop_file(l, false, nullptr);
+            }
+            l->checked_access = true;
+        }
+        if (l->pa) {
+            l->pa->foreach(propfn, cookie);
+        }
+    });
+    return 0;
 }
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index d59de29..7979c43 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -131,12 +131,16 @@
 extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
 
 /*
- * Initializes public namespace. The path is the list of sonames
- * separated by colon. Example: "libc.so:libm.so:libdl.so".
- *
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
  * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
  */
-extern bool android_init_public_namespace(const char* path);
+extern bool android_init_namespaces(const char* public_ns_sonames,
+                                    const char* anon_ns_library_path);
 
 /*
  * Creates new linker namespace.
@@ -148,16 +152,20 @@
  * 2. In directories specified by DT_RUNPATH of the "needed by" binary.
  * 3. deault_library_path (This of this as namespace-local default library path)
  *
- * When is_isolated is true the resulted namespace requires all of the libraries
- * to be on the search path; the search_path is ld_library_path:default_library_path.
+ * When is_isolated is true the resulting namespace requires all of the libraries
+ * to be on the search path or under the permitted_when_isolated_path; the search_path is
+ * ld_library_path:default_library_path. Note that the permitted_when_isolated_path path
+ * is not part of the search_path and does not affect the search order. It is a way
+ * to allow loading libraries from specific locations when using absolute path.
  *
- * If a library or any of its dependencies are outside of the search path and not
- * part of the public namespace dlopen will fail.
+ * If a library or any of its dependencies are outside of the permitted_when_isolated_path
+ * and search_path, and it is not part of the public namespace dlopen will fail.
  */
 extern struct android_namespace_t* android_create_namespace(const char* name,
                                                             const char* ld_library_path,
                                                             const char* default_library_path,
-                                                            bool is_isolated);
+                                                            bool is_isolated,
+                                                            const char* permitted_when_isolated_path);
 
 __END_DECLS
 
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 48b2bca..21d34fb 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -108,6 +108,14 @@
 
 #define PTHREAD_BARRIER_SERIAL_THREAD -1
 
+typedef struct {
+#if defined(__LP64__)
+  int64_t __private;
+#else
+  int32_t __private[2];
+#endif
+} pthread_spinlock_t;
+
 #if defined(__LP64__)
 #define PTHREAD_STACK_MIN (4 * PAGE_SIZE)
 #else
@@ -229,6 +237,12 @@
 int pthread_barrier_destroy(pthread_barrier_t*) __nonnull((1));
 int pthread_barrier_wait(pthread_barrier_t*) __nonnull((1));
 
+int pthread_spin_destroy(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_init(pthread_spinlock_t*, int) __nonnull((1));
+int pthread_spin_lock(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_trylock(pthread_spinlock_t*) __nonnull((1));
+int pthread_spin_unlock(pthread_spinlock_t*) __nonnull((1));
+
 pthread_t pthread_self(void) __pure2;
 
 int pthread_setname_np(pthread_t, const char*) __nonnull((2));
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index a0315b5..3b1f7d0 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -41,6 +41,7 @@
 #define PROP_AREA_VERSION_COMPAT 0x45434f76
 
 #define PROP_SERVICE_NAME "property_service"
+#define PROP_FILENAME_MAX 1024
 #define PROP_FILENAME "/dev/__properties__"
 
 #define PA_SIZE         (128 * 1024)
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index f7805fe..69aa272 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1323,6 +1323,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index d5fe262..763f77e 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1168,6 +1168,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 738836c..76cb168 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1350,6 +1350,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 2121ba7..e268bad 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1286,6 +1286,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index d5fe262..763f77e 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1168,6 +1168,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index fdee2c6..6578370 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1284,6 +1284,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index d5fe262..763f77e 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1168,6 +1168,11 @@
     pthread_barrier_destroy;
     pthread_barrier_init;
     pthread_barrier_wait;
+    pthread_spin_destroy;
+    pthread_spin_init;
+    pthread_spin_lock;
+    pthread_spin_trylock;
+    pthread_spin_unlock;
     pwritev;
     pwritev64;
     scandirat;
diff --git a/libc/private/ScopedPthreadMutexLocker.h b/libc/private/ScopedPthreadMutexLocker.h
index 43dbdc1..58462e3 100644
--- a/libc/private/ScopedPthreadMutexLocker.h
+++ b/libc/private/ScopedPthreadMutexLocker.h
@@ -34,7 +34,7 @@
  private:
   pthread_mutex_t* mu_;
 
-  DISALLOW_COPY_AND_ASSIGN(ScopedPthreadMutexLocker);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPthreadMutexLocker);
 };
 
 #endif // SCOPED_PTHREAD_MUTEX_LOCKER_H
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 401577a..946d9dd 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -40,10 +40,12 @@
 
 struct timespec;
 
-static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) {
+static inline __always_inline int __futex(volatile void* ftx, int op, int value,
+                                          const struct timespec* timeout,
+                                          int bitset) {
   // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
   int saved_errno = errno;
-  int result = syscall(__NR_futex, ftx, op, value, timeout);
+  int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
   if (__predict_false(result == -1)) {
     result = -errno;
     errno = saved_errno;
@@ -52,19 +54,22 @@
 }
 
 static inline int __futex_wake(volatile void* ftx, int count) {
-  return __futex(ftx, FUTEX_WAKE, count, NULL);
+  return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
 }
 
 static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
-  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL);
+  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
 }
 
 static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
-  return __futex(ftx, FUTEX_WAIT, value, timeout);
+  return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
 }
 
-static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) {
-  return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout);
+static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
+                                  bool use_realtime_clock, const struct timespec* abs_timeout) {
+  return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
+                 (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
+                 FUTEX_BITSET_MATCH_ANY);
 }
 
 __END_DECLS
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index a36d1ed..3dbafe0 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -30,6 +30,7 @@
 
 #include <stdatomic.h>
 #include "private/bionic_futex.h"
+#include "private/bionic_macros.h"
 
 // Lock is used in places like pthread_rwlock_t, which can be initialized without calling
 // an initialization function. So make sure Lock can be initialized by setting its memory to 0.
@@ -49,6 +50,12 @@
     this->process_shared = process_shared;
   }
 
+  bool trylock() {
+    LockState old_state = Unlocked;
+    return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
+                        LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
+  }
+
   void lock() {
     LockState old_state = Unlocked;
     if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
@@ -57,7 +64,7 @@
     }
     while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
       // TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
-      __futex_wait_ex(&state, process_shared, LockedWithWaiter, NULL);
+      __futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
     }
     return;
   }
diff --git a/libc/private/bionic_time_conversions.h b/libc/private/bionic_time_conversions.h
index cf0046a..294c29a 100644
--- a/libc/private/bionic_time_conversions.h
+++ b/libc/private/bionic_time_conversions.h
@@ -29,9 +29,12 @@
 #ifndef _BIONIC_TIME_CONVERSIONS_H
 #define _BIONIC_TIME_CONVERSIONS_H
 
+#include <errno.h>
 #include <time.h>
 #include <sys/cdefs.h>
 
+#include "private/bionic_constants.h"
+
 __BEGIN_DECLS
 
 __LIBC_HIDDEN__ bool timespec_from_timeval(timespec& ts, const timeval& tv);
@@ -39,8 +42,21 @@
 
 __LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
 
-__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
+__LIBC_HIDDEN__ void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts,
+                                                     clockid_t clock);
 
 __END_DECLS
 
+static inline int check_timespec(const timespec* ts) {
+  if (ts != nullptr) {
+    if (ts->tv_nsec < 0 || ts->tv_nsec >= NS_PER_S) {
+      return EINVAL;
+    }
+    if (ts->tv_sec < 0) {
+      return ETIMEDOUT;
+    }
+  }
+  return 0;
+}
+
 #endif
diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c
index 2696cfd..6e20562 100644
--- a/libc/stdio/findfp.c
+++ b/libc/stdio/findfp.c
@@ -44,37 +44,44 @@
 #define ALIGNBYTES (sizeof(uintptr_t) - 1)
 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
 
-int	__sdidinit;
-
 #define	NDYNAMIC 10		/* add ten more whenever necessary */
 
 #define	std(flags, file) \
 	{0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
 	    {(unsigned char *)(__sFext+file), 0},NULL,0,{0},{0},{0,0},0,0}
 
-				/* the usual - (stdin + stdout + stderr) */
-static FILE usual[FOPEN_MAX - 3];
-static struct __sfileext usualext[FOPEN_MAX - 3];
-static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
-static struct glue *lastglue = &uglue;
 _THREAD_PRIVATE_MUTEX(__sfp_mutex);
 
-static struct __sfileext __sFext[3];
+// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
+#define SBUF_INIT {0,0}
+#if defined(__LP64__)
+#define MBSTATE_T_INIT {{0},{0}}
+#else
+#define MBSTATE_T_INIT {{0}}
+#endif
+#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
+
+static struct __sfileext __sFext[3] = {
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
+  { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
+};
 
 // __sF is exported for backwards compatibility. Until M, we didn't have symbols
 // for stdin/stdout/stderr; they were macros accessing __sF.
 FILE __sF[3] = {
-	std(__SRD, STDIN_FILENO),		/* stdin */
-	std(__SWR, STDOUT_FILENO),		/* stdout */
-	std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */
+  std(__SRD, STDIN_FILENO),
+  std(__SWR, STDOUT_FILENO),
+  std(__SWR|__SNBF, STDERR_FILENO),
 };
 
-struct glue __sglue = { &uglue, 3, __sF };
-
 FILE* stdin = &__sF[0];
 FILE* stdout = &__sF[1];
 FILE* stderr = &__sF[2];
 
+struct glue __sglue = { NULL, 3, __sF };
+static struct glue* lastglue = &__sglue;
+
 static struct glue *
 moreglue(int n)
 {
@@ -114,9 +121,6 @@
 	int n;
 	struct glue *g;
 
-	if (!__sdidinit)
-		__sinit();
-
 	_THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
 	for (g = &__sglue; g != NULL; g = g->next) {
 		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
@@ -149,48 +153,7 @@
 	return (fp);
 }
 
-/*
- * exit() and abort() call _cleanup() through the callback registered
- * with __atexit_register_cleanup(), set whenever we open or buffer a
- * file. This chicanery is done so that programs that do not use stdio
- * need not link it all in.
- *
- * The name `_cleanup' is, alas, fairly well known outside stdio.
- */
-void
-_cleanup(void)
-{
+__LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
 	/* (void) _fwalk(fclose); */
 	(void) _fwalk(__sflush);		/* `cheating' */
 }
-
-/*
- * __sinit() is called whenever stdio's internal variables must be set up.
- */
-void
-__sinit(void)
-{
-	_THREAD_PRIVATE_MUTEX(__sinit_mutex);
-
-	_THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex);
-	if (__sdidinit) {
-		/* bail out if caller lost the race */
-		_THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
-		return;
-	}
-
-	/* Initialize stdin/stdout/stderr (for the recursive mutex). http://b/18208568. */
-	for (size_t i = 0; i < 3; ++i) {
-		_FILEEXT_SETUP(__sF+i, __sFext+i);
-	}
-	/* Initialize the pre-allocated (but initially unused) streams. */
-	for (size_t i = 0; i < FOPEN_MAX - 3; ++i) {
-		_FILEEXT_SETUP(usual+i, usualext+i);
-	}
-
-	/* make sure we clean up on exit */
-	__atexit_register_cleanup(_cleanup); /* conservative */
-	__sdidinit = 1;
-
-	_THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex);
-}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index ced94e3..6dcd3ae 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -109,7 +109,7 @@
   pthread_mutex_t _lock;
 
   /* __fsetlocking support */
-  bool _stdio_handles_locking;
+  bool _caller_handles_locking;
 };
 
 #if defined(__cplusplus)
@@ -131,7 +131,7 @@
 	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
 	pthread_mutex_init(&_FLOCK(fp), &attr); \
 	pthread_mutexattr_destroy(&attr); \
-	_EXT(fp)->_stdio_handles_locking = true; \
+	_EXT(fp)->_caller_handles_locking = false; \
 } while (0)
 
 #define _FILEEXT_SETUP(f, fext) \
@@ -153,10 +153,8 @@
 __LIBC32_LEGACY_PUBLIC__ int __swsetup(FILE*);
 
 /* These were referenced by a couple of different pieces of middleware and the Crystax NDK. */
-__LIBC32_LEGACY_PUBLIC__ extern int __sdidinit;
 __LIBC32_LEGACY_PUBLIC__ int __sflags(const char*, int*);
 __LIBC32_LEGACY_PUBLIC__ FILE* __sfp(void);
-__LIBC32_LEGACY_PUBLIC__ void __sinit(void);
 __LIBC32_LEGACY_PUBLIC__ void __smakebuf(FILE*);
 
 /* These are referenced by the Greed for Glory franchise. */
@@ -170,7 +168,6 @@
 #pragma GCC visibility push(hidden)
 
 int	__sflush_locked(FILE *);
-void	_cleanup(void);
 int	__swhatbuf(FILE *, size_t *, int *);
 wint_t __fgetwc_unlock(FILE *);
 wint_t	__ungetwc(wint_t, FILE *);
@@ -179,8 +176,6 @@
 int	__vfwprintf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 int	__vfwscanf(FILE * __restrict, const wchar_t * __restrict, __va_list);
 
-extern void __atexit_register_cleanup(void (*)(void));
-
 /*
  * Return true if the given FILE cannot be written now.
  */
@@ -208,8 +203,8 @@
 	(fp)->_lb._base = NULL; \
 }
 
-#define FLOCKFILE(fp)   if (_EXT(fp)->_stdio_handles_locking) flockfile(fp)
-#define FUNLOCKFILE(fp) if (_EXT(fp)->_stdio_handles_locking) funlockfile(fp)
+#define FLOCKFILE(fp)   if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
+#define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
 
 #define FLOATING_POINT
 #define PRINTF_WIDE_CHAR
@@ -237,6 +232,10 @@
 extern int __sfvwrite(FILE *, struct __suio *);
 wint_t __fputwc_unlock(wchar_t wc, FILE *fp);
 
+/* Remove the if (!__sdidinit) __sinit() idiom from untouched upstream stdio code. */
+extern void __sinit(void); // Not actually implemented.
+#define __sdidinit 1
+
 #pragma GCC visibility pop
 
 __END_DECLS
diff --git a/libc/stdio/refill.c b/libc/stdio/refill.c
index e87c7b9..5b0811f 100644
--- a/libc/stdio/refill.c
+++ b/libc/stdio/refill.c
@@ -51,11 +51,6 @@
 int
 __srefill(FILE *fp)
 {
-
-	/* make sure stdio is set up */
-	if (!__sdidinit)
-		__sinit();
-
 	fp->_r = 0;		/* largely a convenience for callers */
 
 #if !defined(__ANDROID__)
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index 310076a..f273d45 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -74,7 +74,7 @@
 }
 
 int __fsetlocking(FILE* fp, int type) {
-  int old_state = _EXT(fp)->_stdio_handles_locking ? FSETLOCKING_INTERNAL : FSETLOCKING_BYCALLER;
+  int old_state = _EXT(fp)->_caller_handles_locking ? FSETLOCKING_BYCALLER : FSETLOCKING_INTERNAL;
   if (type == FSETLOCKING_QUERY) {
     return old_state;
   }
@@ -84,7 +84,7 @@
     __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
   }
 
-  _EXT(fp)->_stdio_handles_locking = (type == FSETLOCKING_INTERNAL);
+  _EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
   return old_state;
 }
 
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index 34a4db1..c817b63 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -185,51 +185,12 @@
 	}
 	_ATEXIT_UNLOCK();
 
+  extern void __libc_stdio_cleanup(void);
+  __libc_stdio_cleanup();
+
   /* BEGIN android-changed: call __unregister_atfork if dso is not null */
   if (dso != NULL) {
     __unregister_atfork(dso);
   }
   /* END android-changed */
 }
-
-/*
- * Register the cleanup function
- */
-void
-__atexit_register_cleanup(void (*func)(void))
-{
-	struct atexit *p;
-	size_t pgsize = getpagesize();
-
-	if (pgsize < sizeof(*p))
-		return;
-	_ATEXIT_LOCK();
-	p = __atexit;
-	while (p != NULL && p->next != NULL)
-		p = p->next;
-	if (p == NULL) {
-		p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
-		    MAP_ANON | MAP_PRIVATE, -1, 0);
-		if (p == MAP_FAILED)
-			goto unlock;
-/* BEGIN android-changed */
-		prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, pgsize,
-		    "atexit handlers");
-/* END android-changed */
-		p->ind = 1;
-		p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
-		    sizeof(p->fns[0]);
-		p->next = NULL;
-		__atexit = p;
-	} else {
-		if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
-			goto unlock;
-	}
-	p->fns[0].fn_ptr = (void (*)(void *))func;
-	p->fns[0].fn_arg = NULL;
-	p->fns[0].fn_dso = NULL;
-	mprotect(p, pgsize, PROT_READ);
-	restartloop = 1;
-unlock:
-	_ATEXIT_UNLOCK();
-}
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 0212d16..8d1c46b 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -32,6 +32,6 @@
 #define __unlockenv() 0
 
 #include <stddef.h>
-int reallocarr(void*, size_t, size_t);
+__LIBC_HIDDEN__ int reallocarr(void*, size_t, size_t);
 
 #endif
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 9a9c756..1ea5dc7 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -33,7 +33,13 @@
 LOCAL_CXX_STL := none
 
 LOCAL_MODULE := libdl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk \
+                                 $(LOCAL_PATH)/libdl.arm.map \
+                                 $(LOCAL_PATH)/libdl.arm64.map \
+                                 $(LOCAL_PATH)/libdl.mips.map \
+                                 $(LOCAL_PATH)/libdl.mips64.map \
+                                 $(LOCAL_PATH)/libdl.x86.map \
+                                 $(LOCAL_PATH)/libdl.x86_64.map \
 
 # NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
 # few symbols from libc. Using --no-undefined here results in having to link
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 3417f99..5ad9f9d 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -16,7 +16,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 3cde5eb..af2f83e 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -49,10 +49,15 @@
 void android_set_application_target_sdk_version(uint32_t target __unused) { }
 uint32_t android_get_application_target_sdk_version() { return 0; }
 
-bool android_init_public_namespace(const char* paths __unused) { return false; }
+bool android_init_namespaces(const char* public_ns_sonames __unused,
+                             const char* anon_ns_library_path __unused) {
+  return false;
+}
+
 struct android_namespace_t* android_create_namespace(const char* name __unused,
                                                      const char* ld_library_path __unused,
                                                      const char* default_library_path __unused,
-                                                     bool isolated __unused) {
+                                                     bool isolated __unused,
+                                                     const char* permitted_when_isolated_path __unused) {
   return 0;
 }
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 421d825..8d123fe 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,7 +30,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libm/Android.bp b/libm/Android.bp
index 0fc860a..081a139 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -3,18 +3,7 @@
 
 bionic_coverage = false
 
-// TODO: this comes from from upstream's libc, not libm, but it's an
-// implementation detail that should have hidden visibility, so it needs
-// to be in whatever library the math code is in.
-libm_common_src_files = ["digittoint.c"]
-
-// TODO: this is not in the BSDs.
-libm_common_src_files += [
-    "significandl.c",
-    "sincos.c",
-]
-
-libm_common_src_files += [
+libm_common_src_files = [
     "upstream-freebsd/lib/msun/bsdsrc/b_exp.c",
     "upstream-freebsd/lib/msun/bsdsrc/b_log.c",
     "upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c",
@@ -186,8 +175,19 @@
 ]
 
 libm_common_src_files += [
-    "fake_long_double.c",
+    // TODO: this comes from from upstream's libc, not libm, but it's an
+    // implementation detail that should have hidden visibility, so it needs
+    // to be in whatever library the math code is in.
+    "digittoint.c",
+
+    // Functionality not in the BSDs.
+    "significandl.c",
+    "sincos.c",
+
+    // Modified versions of BSD code.
     "signbit.c",
+
+    // Home-grown stuff.
     "fabs.cpp",
 ]
 
@@ -292,6 +292,9 @@
     sanitize: ["never"],
 
     multilib: {
+        lib32: {
+            srcs: ["fake_long_double.c"],
+        },
         lib64: {
             srcs: libm_ld128_src_files,
             local_include_dirs: libm_ld_local_includes,
@@ -307,15 +310,18 @@
         arm: {
             srcs: [
                 "arm/fenv.c",
-                "arm/sqrt.S",
-                "arm/floor.S",
             ],
-            exclude_srcs: [
-                // TODO: these require neon not available in arm
-                "upstream-freebsd/lib/msun/src/e_sqrt.c",
-                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
-                "upstream-freebsd/lib/msun/src/s_floor.c",
-            ],
+            armv7_a_neon: {
+                srcs: [
+                    "arm/sqrt.S",
+                    "arm/floor.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                    "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                ],
+            },
             instruction_set: "arm",
             ldflags: ["-Wl,--hash-style=both"],
             version_script: "libm.arm.map",
@@ -323,8 +329,8 @@
 
         arm64: {
             srcs: [
-                "arm64/fenv.c",
                 "arm64/ceil.S",
+                "arm64/fenv.c",
                 "arm64/fma.S",
                 "arm64/floor.S",
                 "arm64/lrint.S",
@@ -333,6 +339,8 @@
                 "arm64/trunc.S",
             ],
             exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
                 "upstream-freebsd/lib/msun/src/s_ceil.c",
                 "upstream-freebsd/lib/msun/src/s_ceilf.c",
                 "upstream-freebsd/lib/msun/src/s_fma.c",
@@ -345,8 +353,6 @@
                 "upstream-freebsd/lib/msun/src/s_lrintf.c",
                 "upstream-freebsd/lib/msun/src/s_rint.c",
                 "upstream-freebsd/lib/msun/src/s_rintf.c",
-                "upstream-freebsd/lib/msun/src/e_sqrt.c",
-                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
                 "upstream-freebsd/lib/msun/src/s_trunc.c",
                 "upstream-freebsd/lib/msun/src/s_truncf.c",
             ],
@@ -364,8 +370,73 @@
         },
 
         x86: {
+            srcs: [
+                "i387/fenv.c",
+                "x86/sqrt.S",
+                "x86/sqrtf.S",
+                "x86/e_acos.S",
+                "x86/e_asin.S",
+                "x86/e_atan2.S",
+                "x86/e_cosh.S",
+                "x86/e_exp.S",
+                "x86/e_hypot.S",
+                "x86/e_log10.S",
+                "x86/e_log.S",
+                "x86/e_pow.S",
+                "x86/e_sinh.S",
+                "x86/libm_reduce_pi04l.S",
+                "x86/libm_sincos_huge.S",
+                "x86/libm_tancot_huge.S",
+                "x86/s_atan.S",
+                "x86/s_cbrt.S",
+                "x86/s_cos.S",
+                "x86/s_expm1.S",
+                "x86/s_log1p.S",
+                "x86/s_sin.S",
+                "x86/s_tanh.S",
+                "x86/s_tan.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_acos.c",
+                "upstream-freebsd/lib/msun/src/e_asin.c",
+                "upstream-freebsd/lib/msun/src/e_atan2.c",
+                "upstream-freebsd/lib/msun/src/e_cosh.c",
+                "upstream-freebsd/lib/msun/src/e_exp.c",
+                "upstream-freebsd/lib/msun/src/e_hypot.c",
+                "upstream-freebsd/lib/msun/src/e_log.c",
+                "upstream-freebsd/lib/msun/src/e_log10.c",
+                "upstream-freebsd/lib/msun/src/e_pow.c",
+                "upstream-freebsd/lib/msun/src/e_sinh.c",
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_atan.c",
+                "upstream-freebsd/lib/msun/src/s_cbrt.c",
+                "upstream-freebsd/lib/msun/src/s_cos.c",
+                "upstream-freebsd/lib/msun/src/s_expm1.c",
+                "upstream-freebsd/lib/msun/src/s_log1p.c",
+                "upstream-freebsd/lib/msun/src/s_sin.c",
+                "upstream-freebsd/lib/msun/src/s_tan.c",
+                "upstream-freebsd/lib/msun/src/s_tanh.c",
+            ],
+            sse4_1: {
+                srcs: [
+                    "x86/ceil.S",
+                    "x86/ceilf.S",
+                    "x86/floor.S",
+                    "x86/floorf.S",
+                    "x86/trunc.S",
+                    "x86/truncf.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/s_ceil.c",
+                    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                    "upstream-freebsd/lib/msun/src/s_floorf.c",
+                    "upstream-freebsd/lib/msun/src/s_trunc.c",
+                    "upstream-freebsd/lib/msun/src/s_truncf.c",
+                ],
+            },
             local_include_dirs: ["i387"],
-            srcs: ["i387/fenv.c"],
             // Clang has wrong long double sizes for x86.
             clang: false,
             ldflags: ["-Wl,--hash-style=both"],
@@ -373,7 +444,69 @@
         },
 
         x86_64: {
-            srcs: ["amd64/fenv.c"],
+            srcs: [
+                "amd64/fenv.c",
+                "x86_64/sqrt.S",
+                "x86_64/sqrtf.S",
+                "x86_64/e_acos.S",
+                "x86_64/e_asin.S",
+                "x86_64/e_atan2.S",
+                "x86_64/e_cosh.S",
+                "x86_64/e_exp.S",
+                "x86_64/e_hypot.S",
+                "x86_64/e_log10.S",
+                "x86_64/e_log.S",
+                "x86_64/e_pow.S",
+                "x86_64/e_sinh.S",
+                "x86_64/s_atan.S",
+                "x86_64/s_cbrt.S",
+                "x86_64/s_cos.S",
+                "x86_64/s_expm1.S",
+                "x86_64/s_log1p.S",
+                "x86_64/s_sin.S",
+                "x86_64/s_tanh.S",
+                "x86_64/s_tan.S",
+            ],
+            exclude_srcs: [
+                "upstream-freebsd/lib/msun/src/e_acos.c",
+                "upstream-freebsd/lib/msun/src/e_asin.c",
+                "upstream-freebsd/lib/msun/src/e_atan2.c",
+                "upstream-freebsd/lib/msun/src/e_cosh.c",
+                "upstream-freebsd/lib/msun/src/e_exp.c",
+                "upstream-freebsd/lib/msun/src/e_hypot.c",
+                "upstream-freebsd/lib/msun/src/e_log.c",
+                "upstream-freebsd/lib/msun/src/e_log10.c",
+                "upstream-freebsd/lib/msun/src/e_pow.c",
+                "upstream-freebsd/lib/msun/src/e_sinh.c",
+                "upstream-freebsd/lib/msun/src/e_sqrt.c",
+                "upstream-freebsd/lib/msun/src/e_sqrtf.c",
+                "upstream-freebsd/lib/msun/src/s_atan.c",
+                "upstream-freebsd/lib/msun/src/s_cbrt.c",
+                "upstream-freebsd/lib/msun/src/s_cos.c",
+                "upstream-freebsd/lib/msun/src/s_expm1.c",
+                "upstream-freebsd/lib/msun/src/s_log1p.c",
+                "upstream-freebsd/lib/msun/src/s_sin.c",
+                "upstream-freebsd/lib/msun/src/s_tan.c",
+                "upstream-freebsd/lib/msun/src/s_tanh.c",
+            ],
+            sse4_1: {
+                srcs: [
+                    "x86_64/ceil.S",
+                    "x86_64/ceilf.S",
+                    "x86_64/floor.S",
+                    "x86_64/floorf.S",
+                    "x86_64/trunc.S",
+                    "x86_64/truncf.S",
+                ],
+                exclude_srcs: [
+                    "upstream-freebsd/lib/msun/src/s_ceil.c",
+                    "upstream-freebsd/lib/msun/src/s_ceilf.c",
+                    "upstream-freebsd/lib/msun/src/s_floor.c",
+                    "upstream-freebsd/lib/msun/src/s_floorf.c",
+                    "upstream-freebsd/lib/msun/src/s_trunc.c",
+                    "upstream-freebsd/lib/msun/src/s_truncf.c",
+                ],
+            },
             // Clang has wrong long double sizes for x86.
             clang: false,
             version_script: "libm.x86_64.map",
diff --git a/libm/Android.mk b/libm/Android.mk
index bd51e7c..faf3c50 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -22,14 +22,19 @@
     upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c \
     upstream-freebsd/lib/msun/src/catrig.c \
     upstream-freebsd/lib/msun/src/catrigf.c \
+    upstream-freebsd/lib/msun/src/e_acos.c \
     upstream-freebsd/lib/msun/src/e_acosf.c \
     upstream-freebsd/lib/msun/src/e_acosh.c \
     upstream-freebsd/lib/msun/src/e_acoshf.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
     upstream-freebsd/lib/msun/src/e_asinf.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
     upstream-freebsd/lib/msun/src/e_atan2f.c \
     upstream-freebsd/lib/msun/src/e_atanh.c \
     upstream-freebsd/lib/msun/src/e_atanhf.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
     upstream-freebsd/lib/msun/src/e_coshf.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
     upstream-freebsd/lib/msun/src/e_expf.c \
     upstream-freebsd/lib/msun/src/e_fmod.c \
     upstream-freebsd/lib/msun/src/e_fmodf.c \
@@ -37,6 +42,7 @@
     upstream-freebsd/lib/msun/src/e_gammaf.c \
     upstream-freebsd/lib/msun/src/e_gammaf_r.c \
     upstream-freebsd/lib/msun/src/e_gamma_r.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
     upstream-freebsd/lib/msun/src/e_hypotf.c \
     upstream-freebsd/lib/msun/src/e_j0.c \
     upstream-freebsd/lib/msun/src/e_j0f.c \
@@ -48,10 +54,13 @@
     upstream-freebsd/lib/msun/src/e_lgammaf.c \
     upstream-freebsd/lib/msun/src/e_lgammaf_r.c \
     upstream-freebsd/lib/msun/src/e_lgamma_r.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
     upstream-freebsd/lib/msun/src/e_log10f.c \
     upstream-freebsd/lib/msun/src/e_log2.c \
     upstream-freebsd/lib/msun/src/e_log2f.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
     upstream-freebsd/lib/msun/src/e_logf.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
     upstream-freebsd/lib/msun/src/e_powf.c \
     upstream-freebsd/lib/msun/src/e_remainder.c \
     upstream-freebsd/lib/msun/src/e_remainderf.c \
@@ -59,7 +68,10 @@
     upstream-freebsd/lib/msun/src/e_rem_pio2f.c \
     upstream-freebsd/lib/msun/src/e_scalb.c \
     upstream-freebsd/lib/msun/src/e_scalbf.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
     upstream-freebsd/lib/msun/src/e_sinhf.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
     upstream-freebsd/lib/msun/src/imprecise.c \
     upstream-freebsd/lib/msun/src/k_cos.c \
     upstream-freebsd/lib/msun/src/k_cosf.c \
@@ -72,13 +84,17 @@
     upstream-freebsd/lib/msun/src/k_tanf.c \
     upstream-freebsd/lib/msun/src/s_asinh.c \
     upstream-freebsd/lib/msun/src/s_asinhf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
     upstream-freebsd/lib/msun/src/s_atanf.c \
     upstream-freebsd/lib/msun/src/s_carg.c \
     upstream-freebsd/lib/msun/src/s_cargf.c \
     upstream-freebsd/lib/msun/src/s_cargl.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
     upstream-freebsd/lib/msun/src/s_cbrtf.c \
     upstream-freebsd/lib/msun/src/s_ccosh.c \
     upstream-freebsd/lib/msun/src/s_ccoshf.c \
+    upstream-freebsd/lib/msun/src/s_ceil.c \
+    upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_cexp.c \
     upstream-freebsd/lib/msun/src/s_cexpf.c \
     upstream-freebsd/lib/msun/src/s_cimag.c \
@@ -89,6 +105,7 @@
     upstream-freebsd/lib/msun/src/s_conjl.c \
     upstream-freebsd/lib/msun/src/s_copysign.c \
     upstream-freebsd/lib/msun/src/s_copysignf.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
     upstream-freebsd/lib/msun/src/s_cosf.c \
     upstream-freebsd/lib/msun/src/s_cproj.c \
     upstream-freebsd/lib/msun/src/s_cprojf.c \
@@ -107,10 +124,15 @@
     upstream-freebsd/lib/msun/src/s_erff.c \
     upstream-freebsd/lib/msun/src/s_exp2.c \
     upstream-freebsd/lib/msun/src/s_exp2f.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
     upstream-freebsd/lib/msun/src/s_expm1f.c \
     upstream-freebsd/lib/msun/src/s_fdim.c \
     upstream-freebsd/lib/msun/src/s_finite.c \
     upstream-freebsd/lib/msun/src/s_finitef.c \
+    upstream-freebsd/lib/msun/src/s_floor.c \
+    upstream-freebsd/lib/msun/src/s_floorf.c \
+    upstream-freebsd/lib/msun/src/s_fma.c \
+    upstream-freebsd/lib/msun/src/s_fmaf.c \
     upstream-freebsd/lib/msun/src/s_fmax.c \
     upstream-freebsd/lib/msun/src/s_fmaxf.c \
     upstream-freebsd/lib/msun/src/s_fmin.c \
@@ -119,11 +141,16 @@
     upstream-freebsd/lib/msun/src/s_frexpf.c \
     upstream-freebsd/lib/msun/src/s_ilogb.c \
     upstream-freebsd/lib/msun/src/s_ilogbf.c \
+    upstream-freebsd/lib/msun/src/s_llrint.c \
+    upstream-freebsd/lib/msun/src/s_llrintf.c \
     upstream-freebsd/lib/msun/src/s_llround.c \
     upstream-freebsd/lib/msun/src/s_llroundf.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
     upstream-freebsd/lib/msun/src/s_log1pf.c \
     upstream-freebsd/lib/msun/src/s_logb.c \
     upstream-freebsd/lib/msun/src/s_logbf.c \
+    upstream-freebsd/lib/msun/src/s_lrint.c \
+    upstream-freebsd/lib/msun/src/s_lrintf.c \
     upstream-freebsd/lib/msun/src/s_lround.c \
     upstream-freebsd/lib/msun/src/s_lroundf.c \
     upstream-freebsd/lib/msun/src/s_modf.c \
@@ -134,6 +161,8 @@
     upstream-freebsd/lib/msun/src/s_nextafterf.c \
     upstream-freebsd/lib/msun/src/s_remquo.c \
     upstream-freebsd/lib/msun/src/s_remquof.c \
+    upstream-freebsd/lib/msun/src/s_rint.c \
+    upstream-freebsd/lib/msun/src/s_rintf.c \
     upstream-freebsd/lib/msun/src/s_round.c \
     upstream-freebsd/lib/msun/src/s_roundf.c \
     upstream-freebsd/lib/msun/src/s_scalbln.c \
@@ -142,10 +171,15 @@
     upstream-freebsd/lib/msun/src/s_signgam.c \
     upstream-freebsd/lib/msun/src/s_significand.c \
     upstream-freebsd/lib/msun/src/s_significandf.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
     upstream-freebsd/lib/msun/src/s_sinf.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
     upstream-freebsd/lib/msun/src/s_tanf.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
     upstream-freebsd/lib/msun/src/s_tanhf.c \
     upstream-freebsd/lib/msun/src/s_tgammaf.c \
+    upstream-freebsd/lib/msun/src/s_trunc.c \
+    upstream-freebsd/lib/msun/src/s_truncf.c \
     upstream-freebsd/lib/msun/src/w_cabs.c \
     upstream-freebsd/lib/msun/src/w_cabsf.c \
     upstream-freebsd/lib/msun/src/w_cabsl.c \
@@ -236,37 +270,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_arm += \
     arm/fenv.c \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_ceil.c \
-    upstream-freebsd/lib/msun/src/s_ceilf.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_floorf.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
-    upstream-freebsd/lib/msun/src/s_trunc.c \
-    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 # s_floor.S requires neon instructions.
 ifdef TARGET_2ND_ARCH
@@ -276,17 +279,16 @@
 endif
 
 # Use the C version on armv7-a since it doesn't support neon instructions.
-ifeq ($(arch_variant),armv7-a)
-LOCAL_SRC_FILES_arm += \
-    upstream-freebsd/lib/msun/src/e_sqrt.c \
-    upstream-freebsd/lib/msun/src/e_sqrtf.c \
-    upstream-freebsd/lib/msun/src/s_floor.c \
-
-else
+ifneq ($(arch_variant),armv7-a)
 LOCAL_SRC_FILES_arm += \
     arm/sqrt.S \
     arm/floor.S \
 
+LOCAL_SRC_FILES_EXCLUDE_arm += \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_floor.c \
+
 endif
 
 # -----------------------------------------------------------------------------
@@ -301,64 +303,30 @@
     arm64/rint.S \
     arm64/sqrt.S \
     arm64/trunc.S \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
+
+LOCAL_SRC_FILES_EXCLUDE_arm64 += \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_ceil.c \
+    upstream-freebsd/lib/msun/src/s_ceilf.c \
+    upstream-freebsd/lib/msun/src/s_fma.c \
+    upstream-freebsd/lib/msun/src/s_fmaf.c \
+    upstream-freebsd/lib/msun/src/s_floor.c \
+    upstream-freebsd/lib/msun/src/s_floorf.c \
+    upstream-freebsd/lib/msun/src/s_llrint.c \
+    upstream-freebsd/lib/msun/src/s_llrintf.c \
+    upstream-freebsd/lib/msun/src/s_lrint.c \
+    upstream-freebsd/lib/msun/src/s_lrintf.c \
+    upstream-freebsd/lib/msun/src/s_rint.c \
+    upstream-freebsd/lib/msun/src/s_rintf.c \
+    upstream-freebsd/lib/msun/src/s_trunc.c \
+    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 # -----------------------------------------------------------------------------
 # mips
 # -----------------------------------------------------------------------------
 libm_mips_arch_files := \
     mips/fenv.c \
-    upstream-freebsd/lib/msun/src/e_acos.c \
-    upstream-freebsd/lib/msun/src/e_asin.c \
-    upstream-freebsd/lib/msun/src/e_atan2.c \
-    upstream-freebsd/lib/msun/src/e_cosh.c \
-    upstream-freebsd/lib/msun/src/e_exp.c \
-    upstream-freebsd/lib/msun/src/e_hypot.c \
-    upstream-freebsd/lib/msun/src/e_log.c \
-    upstream-freebsd/lib/msun/src/e_log10.c \
-    upstream-freebsd/lib/msun/src/e_pow.c \
-    upstream-freebsd/lib/msun/src/e_sinh.c \
-    upstream-freebsd/lib/msun/src/e_sqrt.c \
-    upstream-freebsd/lib/msun/src/e_sqrtf.c \
-    upstream-freebsd/lib/msun/src/s_atan.c \
-    upstream-freebsd/lib/msun/src/s_cbrt.c \
-    upstream-freebsd/lib/msun/src/s_ceil.c \
-    upstream-freebsd/lib/msun/src/s_ceilf.c \
-    upstream-freebsd/lib/msun/src/s_cos.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_floor.c \
-    upstream-freebsd/lib/msun/src/s_floorf.c \
-    upstream-freebsd/lib/msun/src/s_expm1.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_log1p.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
-    upstream-freebsd/lib/msun/src/s_sin.c \
-    upstream-freebsd/lib/msun/src/s_tan.c \
-    upstream-freebsd/lib/msun/src/s_tanh.c \
-    upstream-freebsd/lib/msun/src/s_trunc.c \
-    upstream-freebsd/lib/msun/src/s_truncf.c \
 
 LOCAL_SRC_FILES_mips += $(libm_mips_arch_files)
 LOCAL_SRC_FILES_mips64 += $(libm_mips_arch_files)
@@ -368,14 +336,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_x86 += \
     i387/fenv.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
     x86/sqrt.S \
     x86/sqrtf.S \
     x86/e_acos.S \
@@ -400,6 +360,28 @@
     x86/s_tanh.S \
     x86/s_tan.S \
 
+LOCAL_SRC_FILES_EXCLUDE_x86 += \
+    upstream-freebsd/lib/msun/src/e_acos.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
+
 ifeq ($(ARCH_X86_HAVE_SSE4_1),true)
 LOCAL_SRC_FILES_x86 += \
     x86/ceil.S \
@@ -409,8 +391,7 @@
     x86/trunc.S \
     x86/truncf.S \
 
-else
-LOCAL_SRC_FILES_x86 += \
+LOCAL_SRC_FILES_EXCLUDE_x86 += \
     upstream-freebsd/lib/msun/src/s_ceil.c \
     upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_floor.c \
@@ -425,14 +406,6 @@
 # -----------------------------------------------------------------------------
 LOCAL_SRC_FILES_x86_64 += \
     amd64/fenv.c \
-    upstream-freebsd/lib/msun/src/s_fma.c \
-    upstream-freebsd/lib/msun/src/s_fmaf.c \
-    upstream-freebsd/lib/msun/src/s_llrint.c \
-    upstream-freebsd/lib/msun/src/s_llrintf.c \
-    upstream-freebsd/lib/msun/src/s_lrint.c \
-    upstream-freebsd/lib/msun/src/s_lrintf.c \
-    upstream-freebsd/lib/msun/src/s_rint.c \
-    upstream-freebsd/lib/msun/src/s_rintf.c \
     x86_64/sqrt.S \
     x86_64/sqrtf.S \
     x86_64/e_acos.S \
@@ -454,6 +427,28 @@
     x86_64/s_tanh.S \
     x86_64/s_tan.S \
 
+LOCAL_SRC_FILES_EXCLUDE_x86_64 += \
+    upstream-freebsd/lib/msun/src/e_acos.c \
+    upstream-freebsd/lib/msun/src/e_asin.c \
+    upstream-freebsd/lib/msun/src/e_atan2.c \
+    upstream-freebsd/lib/msun/src/e_cosh.c \
+    upstream-freebsd/lib/msun/src/e_exp.c \
+    upstream-freebsd/lib/msun/src/e_hypot.c \
+    upstream-freebsd/lib/msun/src/e_log.c \
+    upstream-freebsd/lib/msun/src/e_log10.c \
+    upstream-freebsd/lib/msun/src/e_pow.c \
+    upstream-freebsd/lib/msun/src/e_sinh.c \
+    upstream-freebsd/lib/msun/src/e_sqrt.c \
+    upstream-freebsd/lib/msun/src/e_sqrtf.c \
+    upstream-freebsd/lib/msun/src/s_atan.c \
+    upstream-freebsd/lib/msun/src/s_cbrt.c \
+    upstream-freebsd/lib/msun/src/s_cos.c \
+    upstream-freebsd/lib/msun/src/s_expm1.c \
+    upstream-freebsd/lib/msun/src/s_log1p.c \
+    upstream-freebsd/lib/msun/src/s_sin.c \
+    upstream-freebsd/lib/msun/src/s_tan.c \
+    upstream-freebsd/lib/msun/src/s_tanh.c \
+
 ifeq ($(ARCH_X86_HAVE_SSE4_1),true)
 LOCAL_SRC_FILES_x86_64 += \
     x86_64/ceil.S \
@@ -463,8 +458,7 @@
     x86_64/trunc.S \
     x86_64/truncf.S \
 
-else
-LOCAL_SRC_FILES_x86_64 += \
+LOCAL_SRC_FILES_EXCLUDE_x86_64 += \
     upstream-freebsd/lib/msun/src/s_ceil.c \
     upstream-freebsd/lib/msun/src/s_ceilf.c \
     upstream-freebsd/lib/msun/src/s_floor.c \
diff --git a/libm/libm.arm.map b/libm/libm.arm.map
index f44cf90..e781f2d 100644
--- a/libm/libm.arm.map
+++ b/libm/libm.arm.map
@@ -272,8 +272,8 @@
     *;
 };
 
-LIBC_PRIVATE { # arm x86 mips
-  global: # arm x86 mips
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
     ___Unwind_RaiseException; # arm
@@ -354,7 +354,6 @@
     __lesf2; # arm
     __ltdf2; # arm
     __ltsf2; # arm
-    __muldc3; # arm x86 mips
     __muldf3; # arm
     __nedf2; # arm
     __nesf2; # arm
@@ -376,4 +375,4 @@
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
     restore_core_regs; # arm
-} LIBC; # arm x86 mips
+} LIBC; # arm mips
diff --git a/libm/libm.map.txt b/libm/libm.map.txt
index 3bd081f..075ebd5 100644
--- a/libm/libm.map.txt
+++ b/libm/libm.map.txt
@@ -271,8 +271,8 @@
     *;
 };
 
-LIBC_PRIVATE { # arm x86 mips
-  global: # arm x86 mips
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
     ___Unwind_Backtrace; # arm
     ___Unwind_ForcedUnwind; # arm
     ___Unwind_RaiseException; # arm
@@ -353,7 +353,6 @@
     __lesf2; # arm
     __ltdf2; # arm
     __ltsf2; # arm
-    __muldc3; # arm x86 mips
     __muldf3; # arm
     __nedf2; # arm
     __nesf2; # arm
@@ -375,4 +374,4 @@
     _Unwind_VRS_Pop; # arm
     _Unwind_VRS_Set; # arm
     restore_core_regs; # arm
-} LIBC; # arm x86 mips
+} LIBC; # arm mips
diff --git a/libm/libm.mips.map b/libm/libm.mips.map
index 78ed1ea..476c6ad 100644
--- a/libm/libm.mips.map
+++ b/libm/libm.mips.map
@@ -272,11 +272,10 @@
     *;
 };
 
-LIBC_PRIVATE { # arm x86 mips
-  global: # arm x86 mips
+LIBC_PRIVATE { # arm mips
+  global: # arm mips
     __fixdfdi; # arm mips
     __fixsfdi; # arm mips
     __fixunsdfdi; # arm mips
     __fixunssfdi; # arm mips
-    __muldc3; # arm x86 mips
-} LIBC; # arm x86 mips
+} LIBC; # arm mips
diff --git a/libm/libm.x86.map b/libm/libm.x86.map
index 8aa6d88..1623ea0 100644
--- a/libm/libm.x86.map
+++ b/libm/libm.x86.map
@@ -272,7 +272,3 @@
     *;
 };
 
-LIBC_PRIVATE { # arm x86 mips
-  global: # arm x86 mips
-    __muldc3; # arm x86 mips
-} LIBC; # arm x86 mips
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7957921..fde9f5c 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -89,9 +89,12 @@
   return dlopen_ext(filename, flags, nullptr, caller_addr);
 }
 
+extern android_namespace_t* g_anonymous_namespace;
+
 void* dlsym(void* handle, const char* symbol) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
 
+  // TODO(dimitry): move (most of) the code below to linker.cpp
 #if !defined(__LP64__)
   if (handle == nullptr) {
     __bionic_format_dlerror("dlsym library handle is null", nullptr);
@@ -108,16 +111,10 @@
   const ElfW(Sym)* sym = nullptr;
   void* caller_addr = __builtin_return_address(0);
   soinfo* caller = find_containing_library(caller_addr);
-  if (caller == nullptr) {
-    char buf[256];
-    __libc_format_buffer(buf, sizeof(buf), "dlsym couldn't locate its caller address=%p; "
-                         "the caller was code not loaded by the dynamic linker", caller_addr);
-    __bionic_format_dlerror(buf, nullptr);
-    return nullptr;
-  }
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
-    sym = dlsym_linear_lookup(caller->get_namespace(), symbol, &found, caller, handle);
+    sym = dlsym_linear_lookup(ns, symbol, &found, caller, handle);
   } else {
     sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
   }
@@ -184,22 +181,24 @@
   return get_application_target_sdk_version();
 }
 
-bool android_init_public_namespace(const char* path) {
+bool android_init_namespaces(const char* public_ns_sonames,
+                             const char* anon_ns_library_path) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
-  bool success = init_public_namespace(path);
+  bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
   if (!success) {
-    __bionic_format_dlerror("android_init_public_namespace failed", linker_get_error_buffer());
+    __bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
   }
 
   return success;
 }
 
 android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
-                                              const char* default_library_path, bool is_isolated) {
+                                              const char* default_library_path, bool is_isolated,
+                                              const char* permitted_when_isolated_path) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
 
-  android_namespace_t* result = create_namespace(name, ld_library_path,
-                                                 default_library_path, is_isolated);
+  android_namespace_t* result = create_namespace(name, ld_library_path, default_library_path,
+                                                 is_isolated, permitted_when_isolated_path);
 
   if (result == nullptr) {
     __bionic_format_dlerror("android_create_namespace failed", linker_get_error_buffer());
@@ -234,11 +233,11 @@
   // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
   // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
     "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
-  // 0000000000111111 111122222222223333333333444444 4444555555555566666666667
-  // 0123456789012345 678901234567890123456789012345 6789012345678901234567890
-    "get_sdk_version\0android_init_public_namespace\0android_create_namespace\0"
+  // 0000000000111111 111122222222223333333333 4444444444555555555566666
+  // 0123456789012345 678901234567890123456789 0123456789012345678901234
+    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
 #if defined(__arm__)
-  // 271
+  // 265
     "dl_unwind_find_exidx\0"
 #endif
     ;
@@ -260,10 +259,10 @@
   ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
   ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
   ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
-  ELFW(SYM_INITIALIZER)(216, &android_init_public_namespace, 1),
-  ELFW(SYM_INITIALIZER)(246, &android_create_namespace, 1),
+  ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(271, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
 #endif
 };
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8b678ff..bd4d691 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -37,7 +37,6 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include <sys/prctl.h>
 #include <unistd.h>
 
 #include <new>
@@ -60,7 +59,7 @@
 #include "linker_reloc_iterators.h"
 #include "linker_utils.h"
 
-#include "base/strings.h"
+#include "android-base/strings.h"
 #include "ziparchive/zip_archive.h"
 
 extern void __libc_init_globals(KernelArgumentBlock&);
@@ -94,6 +93,10 @@
     default_library_paths_ = library_paths;
   }
 
+  void set_permitted_paths(std::vector<std::string>&& permitted_paths) {
+    permitted_paths_ = permitted_paths;
+  }
+
   soinfo::soinfo_list_t& soinfo_list() { return soinfo_list_; }
 
   // For isolated namespaces - checks if the file is on the search path;
@@ -105,12 +108,14 @@
   bool is_isolated_;
   std::vector<std::string> ld_library_paths_;
   std::vector<std::string> default_library_paths_;
+  std::vector<std::string> permitted_paths_;
   soinfo::soinfo_list_t soinfo_list_;
 
   DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
 };
 
 android_namespace_t g_default_namespace;
+android_namespace_t* g_anonymous_namespace = &g_default_namespace;
 
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
@@ -309,6 +314,12 @@
     }
   }
 
+  for (const auto& dir : permitted_paths_) {
+    if (file_is_under_dir(file, dir)) {
+      return true;
+    }
+  }
+
   return false;
 }
 
@@ -537,13 +548,6 @@
 static bool realpath_fd(int fd, std::string* realpath) {
   std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
   __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
-  // set DUMPABLE to 1 to access /proc/self/fd
-  int dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
-  prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-  auto guard = make_scope_guard([&]() {
-    // restore dumpable
-    prctl(PR_SET_DUMPABLE, dumpable, 0, 0, 0);
-  });
   if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
     PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
     return false;
@@ -1575,9 +1579,6 @@
       }
     }
 
-    if (fd != -1 && !ns->is_accessible(*realpath)) {
-      fd = -1;
-    }
     return fd;
   }
 
@@ -1694,6 +1695,13 @@
     return false;
   }
 
+  if (!ns->is_accessible(realpath)) {
+    // do not load libraries if they are not accessible for the specified namespace.
+    DL_ERR("library \"%s\" is not accessible for the namespace \"%s\"",
+           name, ns->get_name());
+    return false;
+  }
+
   soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
   if (si == nullptr) {
     return false;
@@ -2195,7 +2203,7 @@
     return nullptr;
   }
 
-  android_namespace_t* ns = caller->get_namespace();
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (extinfo != nullptr) {
     if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
@@ -2240,14 +2248,14 @@
   soinfo_unload(si);
 }
 
-bool init_public_namespace(const char* libs) {
-  CHECK(libs != nullptr);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
+  CHECK(public_ns_sonames != nullptr);
   if (g_public_namespace_initialized) {
-    DL_ERR("Public namespace has already been initialized.");
+    DL_ERR("public namespace has already been initialized.");
     return false;
   }
 
-  std::vector<std::string> sonames = android::base::Split(libs, ":");
+  std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
 
   ProtectedDataGuard guard;
 
@@ -2261,7 +2269,7 @@
     find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
 
     if (candidate == nullptr) {
-      DL_ERR("Error initializing public namespace: \"%s\" was not found"
+      DL_ERR("error initializing public namespace: \"%s\" was not found"
              " in the default namespace", soname.c_str());
       return false;
     }
@@ -2270,32 +2278,46 @@
     g_public_namespace.push_back(candidate);
   }
 
-  failure_guard.disable();
   g_public_namespace_initialized = true;
+
+  // create anonymous namespace
+  android_namespace_t* anon_ns =
+      create_namespace("(anonymous)", nullptr, anon_ns_library_path, false, nullptr);
+
+  if (anon_ns == nullptr) {
+    g_public_namespace_initialized = false;
+    return false;
+  }
+  g_anonymous_namespace = anon_ns;
+  failure_guard.disable();
   return true;
 }
 
 android_namespace_t* create_namespace(const char* name,
                                       const char* ld_library_path,
                                       const char* default_library_path,
-                                      bool is_isolated) {
+                                      bool is_isolated,
+                                      const char* permitted_when_isolated_path) {
   if (!g_public_namespace_initialized) {
-    DL_ERR("Cannot create namespace: public namespace is not initialized.");
+    DL_ERR("cannot create namespace: public namespace is not initialized.");
     return nullptr;
   }
 
   ProtectedDataGuard guard;
   std::vector<std::string> ld_library_paths;
   std::vector<std::string> default_library_paths;
+  std::vector<std::string> permitted_paths;
 
   parse_path(ld_library_path, ":", &ld_library_paths);
   parse_path(default_library_path, ":", &default_library_paths);
+  parse_path(permitted_when_isolated_path, ":", &permitted_paths);
 
   android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
   ns->set_name(name);
   ns->set_isolated(is_isolated);
   ns->set_ld_library_paths(std::move(ld_library_paths));
   ns->set_default_library_paths(std::move(default_library_paths));
+  ns->set_permitted_paths(std::move(permitted_paths));
 
   // TODO(dimtiry): Should this be global group of caller's namespace?
   auto global_group = make_global_group(&g_default_namespace);
@@ -2734,14 +2756,14 @@
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO R_X86_64_32 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
                    static_cast<size_t>(sym_addr), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend;
         break;
       case R_X86_64_64:
         count_relocation(kRelocRelative);
         MARK(rel->r_offset);
         TRACE_TYPE(RELO, "RELO R_X86_64_64 %08zx <- +%08zx %s", static_cast<size_t>(reloc),
                    static_cast<size_t>(sym_addr), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend;
+        *reinterpret_cast<Elf64_Addr*>(reloc) = sym_addr + addend;
         break;
       case R_X86_64_PC32:
         count_relocation(kRelocRelative);
@@ -2749,7 +2771,7 @@
         TRACE_TYPE(RELO, "RELO R_X86_64_PC32 %08zx <- +%08zx (%08zx - %08zx) %s",
                    static_cast<size_t>(reloc), static_cast<size_t>(sym_addr - reloc),
                    static_cast<size_t>(sym_addr), static_cast<size_t>(reloc), sym_name);
-        *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + addend - reloc;
+        *reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr + addend - reloc;
         break;
 #elif defined(__arm__)
       case R_ARM_ABS32:
diff --git a/linker/linker.h b/linker/linker.h
index c46b4e1..49329c7 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -444,8 +444,9 @@
 void set_application_target_sdk_version(uint32_t target);
 uint32_t get_application_target_sdk_version();
 
-bool init_public_namespace(const char* path);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
 android_namespace_t* create_namespace(const char* name, const char* ld_library_path,
-                                      const char* default_library_path, bool is_isolated);
+                                      const char* default_library_path, bool is_isolated,
+                                      const char* permitted_when_isolated_path);
 
 #endif
diff --git a/linker/linker_mapped_file_fragment.cpp b/linker/linker_mapped_file_fragment.cpp
index 6a500ef..27c1c69 100644
--- a/linker/linker_mapped_file_fragment.cpp
+++ b/linker/linker_mapped_file_fragment.cpp
@@ -16,32 +16,13 @@
 
 #include "linker_mapped_file_fragment.h"
 #include "linker_debug.h"
+#include "linker_utils.h"
 
 #include <inttypes.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
-constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
-
-static off64_t page_start(off64_t offset) {
-  return offset & kPageMask;
-}
-
-static bool safe_add(off64_t* out, off64_t a, size_t b) {
-  CHECK(a >= 0);
-  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
-    return false;
-  }
-
-  *out = a + b;
-  return true;
-}
-
-static size_t page_offset(off64_t offset) {
-  return static_cast<size_t>(offset & (PAGE_SIZE-1));
-}
-
 MappedFileFragment::MappedFileFragment() : map_start_(nullptr), map_size_(0),
                                            data_(nullptr), size_ (0)
 { }
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 347983e..4c4ce17 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -37,6 +37,7 @@
 
 #include "linker.h"
 #include "linker_debug.h"
+#include "linker_utils.h"
 
 static int GetTargetElfMachine() {
 #if defined(__arm__)
@@ -244,6 +245,16 @@
   return true;
 }
 
+bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) {
+  off64_t range_start;
+  off64_t range_end;
+
+  return safe_add(&range_start, file_offset_, offset) &&
+         safe_add(&range_end, range_start, size) &&
+         range_start < file_size_ &&
+         range_end <= file_size_;
+}
+
 // Loads the program header table from an ELF file into a read-only private
 // anonymous mmap-ed block.
 bool ElfReader::ReadProgramHeaders() {
@@ -256,7 +267,14 @@
     return false;
   }
 
-  if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, phdr_num_ * sizeof(ElfW(Phdr)))) {
+  // Boundary checks
+  size_t size = phdr_num_ * sizeof(ElfW(Phdr));
+  if (!CheckFileRange(header_.e_phoff, size)) {
+    DL_ERR("\"%s\" has invalid phdr offset/size", name_.c_str());
+    return false;
+  }
+
+  if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
     DL_ERR("\"%s\" phdr mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
   }
@@ -268,7 +286,18 @@
 bool ElfReader::ReadSectionHeaders() {
   shdr_num_ = header_.e_shnum;
 
-  if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, shdr_num_ * sizeof(ElfW(Shdr)))) {
+  if (shdr_num_ == 0) {
+    DL_ERR("\"%s\" has no section headers", name_.c_str());
+    return false;
+  }
+
+  size_t size = shdr_num_ * sizeof(ElfW(Shdr));
+  if (!CheckFileRange(header_.e_shoff, size)) {
+    DL_ERR("\"%s\" has invalid shdr offset/size", name_.c_str());
+    return false;
+  }
+
+  if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
     DL_ERR("\"%s\" shdr mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
   }
@@ -288,7 +317,7 @@
   }
 
   if (dynamic_shdr == nullptr) {
-    DL_ERR("\"%s\" .dynamic section was not found", name_.c_str());
+    DL_ERR("\"%s\" .dynamic section header was not found", name_.c_str());
     return false;
   }
 
@@ -305,6 +334,12 @@
     return false;
   }
 
+  if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    PRINT("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    return false;
+  }
+
   if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
     DL_ERR("\"%s\" dynamic section mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
@@ -312,6 +347,12 @@
 
   dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
 
+  if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
+           name_.c_str());
+    return false;
+  }
+
   if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
     DL_ERR("\"%s\" strtab section mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index f7b1caf..c359cca 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -64,6 +64,7 @@
   bool LoadSegments();
   bool FindPhdr();
   bool CheckPhdr(ElfW(Addr));
+  bool CheckFileRange(ElfW(Addr) offset, size_t size);
 
   bool did_read_;
   bool did_load_;
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index f81b77b..1b0c4e4 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -66,9 +66,18 @@
   const char* haystack = file.c_str();
   size_t needle_len = strlen(needle);
 
-  return (strncmp(haystack, needle, needle_len) == 0 &&
-          haystack[needle_len] == '/' &&
-          strchr(haystack + needle_len + 1, '/') == nullptr);
+  return strncmp(haystack, needle, needle_len) == 0 &&
+         haystack[needle_len] == '/' &&
+         strchr(haystack + needle_len + 1, '/') == nullptr;
+}
+
+bool file_is_under_dir(const std::string& file, const std::string& dir) {
+  const char* needle = dir.c_str();
+  const char* haystack = file.c_str();
+  size_t needle_len = strlen(needle);
+
+  return strncmp(haystack, needle, needle_len) == 0 &&
+         haystack[needle_len] == '/';
 }
 
 const char* const kZipFileSeparator = "!/";
@@ -105,3 +114,23 @@
   return true;
 }
 
+constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
+
+off64_t page_start(off64_t offset) {
+  return offset & kPageMask;
+}
+
+bool safe_add(off64_t* out, off64_t a, size_t b) {
+  CHECK(a >= 0);
+  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
+    return false;
+  }
+
+  *out = a + b;
+  return true;
+}
+
+size_t page_offset(off64_t offset) {
+  return static_cast<size_t>(offset & (PAGE_SIZE-1));
+}
+
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index b998fb5..987eabd 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -22,6 +22,11 @@
 
 bool normalize_path(const char* path, std::string* normalized_path);
 bool file_is_in_dir(const std::string& file, const std::string& dir);
+bool file_is_under_dir(const std::string& file, const std::string& dir);
 bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path);
 
+off64_t page_start(off64_t offset);
+size_t page_offset(off64_t offset);
+bool safe_add(off64_t* out, off64_t a, size_t b);
+
 #endif
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index d9b290c..fd749fa 100644
--- a/linker/tests/linker_utils_test.cpp
+++ b/linker/tests/linker_utils_test.cpp
@@ -54,6 +54,18 @@
   ASSERT_FALSE(file_is_in_dir("/file", "/"));
 }
 
+TEST(linker_utils, file_is_under_dir_smoke) {
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo/bar"));
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo"));
+
+  ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/bar/foo"));
+
+  ASSERT_TRUE(file_is_under_dir("/file", ""));
+  ASSERT_TRUE(file_is_under_dir("/foo/bar/file", ""));
+  ASSERT_FALSE(file_is_under_dir("/file", "/"));
+  ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/"));
+}
+
 TEST(linker_utils, parse_zip_path_smoke) {
   std::string zip_path;
   std::string entry_path;
@@ -69,3 +81,24 @@
   ASSERT_EQ("", entry_path);
 }
 
+TEST(linker_utils, page_start) {
+  ASSERT_EQ(0x0001000, page_start(0x0001000));
+  ASSERT_EQ(0x3002000, page_start(0x300222f));
+  ASSERT_EQ(0x6001000, page_start(0x6001fff));
+}
+
+TEST(linker_utils, page_offset) {
+  ASSERT_EQ(0x0U, page_offset(0x0001000));
+  ASSERT_EQ(0x22fU, page_offset(0x300222f));
+  ASSERT_EQ(0xfffU, page_offset(0x6001fff));
+}
+
+TEST(linker_utils, safe_add) {
+  int64_t val = 42;
+  ASSERT_FALSE(safe_add(&val, INT64_MAX-20, 21U));
+  ASSERT_EQ(42, val);
+  ASSERT_TRUE(safe_add(&val, INT64_MAX-42, 42U));
+  ASSERT_EQ(INT64_MAX, val);
+  ASSERT_TRUE(safe_add(&val, 2000, 42U));
+  ASSERT_EQ(2042, val);
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index e2fae52..86c141a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -272,18 +272,20 @@
 # Tests for the device using bionic's .so. Run with:
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
+#   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests-gcc32
+#   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests-gcc64
 # -----------------------------------------------------------------------------
-bionic-unit-tests_whole_static_libraries := \
+common_bionic-unit-tests_whole_static_libraries := \
     libBionicTests \
     libBionicGtestMain \
 
-bionic-unit-tests_static_libraries := \
+common_bionic-unit-tests_static_libraries := \
     libtinyxml2 \
     liblog \
     libbase \
 
 # TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
-bionic-unit-tests_src_files := \
+common_bionic-unit-tests_src_files := \
     atexit_test.cpp \
     dl_test.cpp \
     dlext_test.cpp \
@@ -293,32 +295,56 @@
     pthread_dlfcn_test.cpp \
     thread_local_test.cpp \
 
-bionic-unit-tests_cflags := $(test_cflags)
+common_bionic-unit-tests_cflags := $(test_cflags)
 
-bionic-unit-tests_conlyflags := \
+common_bionic-unit-tests_conlyflags := \
     -fexceptions \
     -fnon-call-exceptions \
 
-bionic-unit-tests_cppflags := $(test_cppflags)
+common_bionic-unit-tests_cppflags := $(test_cppflags)
 
-bionic-unit-tests_ldflags := \
+common_bionic-unit-tests_ldflags := \
     -Wl,--export-dynamic
 
-bionic-unit-tests_c_includes := \
+common_bionic-unit-tests_c_includes := \
     bionic/libc \
 
-bionic-unit-tests_shared_libraries_target := \
+common_bionic-unit-tests_shared_libraries_target := \
     libdl \
     libpagemap \
     libdl_preempt_test_1 \
     libdl_preempt_test_2
 
-bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global
+common_bionic-unit-tests_shared_libraries_target += libdl_test_df_1_global
 
-module := bionic-unit-tests
 module_tag := optional
 build_type := target
 build_target := NATIVE_TEST
+
+module := bionic-unit-tests
+bionic-unit-tests_clang_target := true
+bionic-unit-tests_whole_static_libraries := $(common_bionic-unit-tests_whole_static_libraries)
+bionic-unit-tests_static_libraries := $(common_bionic-unit-tests_static_libraries)
+bionic-unit-tests_src_files := $(common_bionic-unit-tests_src_files)
+bionic-unit-tests_cflags := $(common_bionic-unit-tests_cflags)
+bionic-unit-tests_conlyflags := $(common_bionic-unit-tests_conlyflags)
+bionic-unit-tests_cppflags := $(common_bionic-unit-tests_cppflags)
+bionic-unit-tests_ldflags := $(common_bionic-unit-tests_ldflags)
+bionic-unit-tests_c_includes := $(common_bionic-unit-tests_c_includes)
+bionic-unit-tests_shared_libraries_target := $(common_bionic-unit-tests_shared_libraries_target)
+include $(LOCAL_PATH)/Android.build.mk
+
+module := bionic-unit-tests-gcc
+bionic-unit-tests-gcc_clang_target := false
+bionic-unit-tests-gcc_whole_static_libraries := $(common_bionic-unit-tests_whole_static_libraries)
+bionic-unit-tests-gcc_static_libraries := $(common_bionic-unit-tests_static_libraries)
+bionic-unit-tests-gcc_src_files := $(common_bionic-unit-tests_src_files)
+bionic-unit-tests-gcc_cflags := $(common_bionic-unit-tests_cflags)
+bionic-unit-tests-gcc_conlyflags := $(common_bionic-unit-tests_conlyflags)
+bionic-unit-tests-gcc_cppflags := $(common_bionic-unit-tests_cppflags)
+bionic-unit-tests-gcc_ldflags := $(common_bionic-unit-tests_ldflags)
+bionic-unit-tests-gcc_c_includes := $(common_bionic-unit-tests_c_includes)
+bionic-unit-tests-gcc_shared_libraries_target := $(common_bionic-unit-tests_shared_libraries_target)
 include $(LOCAL_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
diff --git a/tests/__cxa_thread_atexit_test.cpp b/tests/__cxa_thread_atexit_test.cpp
index e388f3b..1432968 100644
--- a/tests/__cxa_thread_atexit_test.cpp
+++ b/tests/__cxa_thread_atexit_test.cpp
@@ -35,7 +35,12 @@
   std::string message;
 };
 
+#if defined(__clang__) && defined(__aarch64__)
+// b/25642296, aarch64 clang compiled "thread_local" does not link.
+static ClassWithDtor class_with_dtor;
+#else
 static thread_local ClassWithDtor class_with_dtor;
+#endif
 
 static void* thread_nop(void* arg) {
   class_with_dtor.set_message(*static_cast<std::string*>(arg));
@@ -47,7 +52,12 @@
   pthread_t t;
   ASSERT_EQ(0, pthread_create(&t, nullptr, thread_nop, &msg));
   ASSERT_EQ(0, pthread_join(t, nullptr));
+#if defined(__clang__) && defined(__aarch64__)
+  GTEST_LOG_(INFO) << "Skipping test, b/25642296, "
+                   << "thread_local does not work with aarch64 clang/llvm.\n";
+#else
   ASSERT_EQ("dtor called.", class_with_dtor_output);
+#endif
 }
 
 class ClassWithDtorForMainThread {
@@ -64,7 +74,13 @@
 };
 
 static void thread_atexit_main() {
+#if defined(__clang__) && defined(__aarch64__)
+  static ClassWithDtorForMainThread class_with_dtor_for_main_thread;
+  GTEST_LOG_(INFO) << "Skipping test, b/25642296, "
+                   << "thread_local does not work with aarch64 clang/llvm.\n";
+#else
   static thread_local ClassWithDtorForMainThread class_with_dtor_for_main_thread;
+#endif
   class_with_dtor_for_main_thread.set_message("d-tor for main thread called.");
   exit(0);
 }
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index a56c771..5327e36 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -32,6 +32,7 @@
 #include <pagemap/pagemap.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 #define ASSERT_DL_NOTNULL(ptr) \
     ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
@@ -610,26 +611,27 @@
   static const char* root_lib = "libnstest_root.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  ASSERT_FALSE(android_init_public_namespace(path.c_str()));
-  ASSERT_STREQ("android_init_public_namespace failed: Error initializing public namespace: "
+  ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
+  ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
                "\"libnstest_public.so\" was not found in the default namespace", dlerror());
 
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
 
-  void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW);
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
   // Check that libraries added to public namespace are NODELETE
   dlclose(handle_public);
   handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW | RTLD_NOLOAD);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
-  android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
+  android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
   ASSERT_TRUE(ns1 != nullptr) << dlerror();
 
-  android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
+  android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
   ASSERT_TRUE(ns2 != nullptr) << dlerror();
 
   // This should not have affect search path for default namespace:
@@ -651,6 +653,14 @@
 
   ASSERT_TRUE(handle1 != handle2);
 
+  // dlopen for a public library using an absolute path should work for isolated namespaces
+  extinfo.library_namespace = ns2;
+  handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  ASSERT_TRUE(handle == handle_public);
+
+  dlclose(handle);
+
   typedef const char* (*fn_t)();
 
   fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
@@ -714,20 +724,21 @@
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
-  void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW);
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
   android_set_application_target_sdk_version(42U); // something > 23
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
-  android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
+  android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
   ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
 
-  android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
+  android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
   ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
 
-  android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true);
+  android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true, lib_path.c_str());
   ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
 
   ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
@@ -757,18 +768,19 @@
   // Check dlopen by absolute path
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 == nullptr);
-  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" not found", dlerror());
+  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated1\"", dlerror());
 
   extinfo.library_namespace = ns_isolated2;
 
+  // this should work because isolation_path for private_isolated2 includes lib_path
   handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
-  ASSERT_TRUE(handle2 == nullptr);
-  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+  dlclose(handle2);
 
   // Check dlopen by absolute path
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
-  ASSERT_TRUE(handle2 == nullptr);
-  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" not found", dlerror());
+  ASSERT_TRUE(handle2 != nullptr) << dlerror();
+  dlclose(handle2);
 
   typedef const char* (*fn_t)();
   fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
@@ -795,3 +807,95 @@
 
   dlclose(handle1);
 }
+
+TEST(dlext, ns_anonymous) {
+  static const char* root_lib = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
+      << dlerror();
+
+  android_namespace_t* ns = android_create_namespace(
+                                "private", nullptr,
+                                (lib_path + "/private_namespace_libs").c_str(),
+                                false, nullptr);
+
+  ASSERT_TRUE(ns != nullptr) << dlerror();
+
+  std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns;
+
+  // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
+  void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  uintptr_t ns_get_dlopened_string_addr =
+      reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
+  typedef const char* (*fn_t)();
+  fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
+
+  std::vector<map_record> maps;
+  Maps::parse_maps(&maps);
+
+  uintptr_t addr_start = 0;
+  uintptr_t addr_end = 0;
+  std::vector<map_record> maps_to_copy;
+
+  for (const auto& rec : maps) {
+    if (rec.pathname == private_library_absolute_path) {
+      if (addr_start == 0) {
+        addr_start = rec.addr_start;
+      }
+      addr_end = rec.addr_end;
+
+      maps_to_copy.push_back(rec);
+    }
+  }
+
+  // some sanity checks..
+  ASSERT_TRUE(addr_start > 0);
+  ASSERT_TRUE(addr_end > 0);
+  ASSERT_EQ(3U, maps_to_copy.size());
+  ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
+  ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
+
+  // copy
+  uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
+                                                             PROT_NONE, MAP_ANON | MAP_PRIVATE,
+                                                             -1, 0));
+  ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
+
+  for (const auto& rec : maps_to_copy) {
+    uintptr_t offset = rec.addr_start - addr_start;
+    size_t size = rec.addr_end - rec.addr_start;
+    void* addr = reinterpret_cast<void*>(reserved_addr + offset);
+    void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
+                     MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
+    ASSERT_TRUE(map != MAP_FAILED);
+    memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
+    mprotect(map, size, rec.perms);
+  }
+
+  // call the function copy
+  uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start;
+  fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_anon());
+
+  // They should belong to different namespaces (private and anonymous)
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_private());
+
+  ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
+}
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 3b9f6b9..a662c73 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -575,27 +575,15 @@
   exit(result);
 }
 
-#if defined(__APPLE__)
-
-static int pipe2(int pipefd[2], int flags) {
-  int ret = pipe(pipefd);
-  if (ret != -1) {
-    ret = fcntl(pipefd[0], F_SETFL, flags);
-  }
-  if (ret != -1) {
-    ret = fcntl(pipefd[1], F_SETFL, flags);
-  }
-  return ret;
-}
-
-#endif
-
 static ChildProcInfo RunChildProcess(const std::string& test_name, int testcase_id, int test_id,
                                      int argc, char** argv) {
   int pipefd[2];
-  int ret = pipe2(pipefd, O_NONBLOCK);
-  if (ret == -1) {
-    perror("pipe2 in RunTestInSeparateProc");
+  if (pipe(pipefd) == -1) {
+    perror("pipe in RunTestInSeparateProc");
+    exit(1);
+  }
+  if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) == -1) {
+    perror("fcntl in RunTestInSeparateProc");
     exit(1);
   }
   pid_t pid = fork();
@@ -685,6 +673,30 @@
   return timeout_child_count;
 }
 
+static void ReadChildProcOutput(std::vector<TestCase>& testcase_list,
+                                std::vector<ChildProcInfo>& child_proc_list) {
+  for (const auto& child_proc : child_proc_list) {
+    TestCase& testcase = testcase_list[child_proc.testcase_id];
+    int test_id = child_proc.test_id;
+    while (true) {
+      char buf[1024];
+      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(child_proc.child_read_fd, buf, sizeof(buf) - 1));
+      if (bytes_read > 0) {
+        buf[bytes_read] = '\0';
+        testcase.GetTest(test_id).AppendTestOutput(buf);
+      } else if (bytes_read == 0) {
+        break; // Read end.
+      } else {
+        if (errno == EAGAIN) {
+          break;
+        }
+        perror("failed to read child_read_fd");
+        exit(1);
+      }
+    }
+  }
+}
+
 static void WaitChildProcs(std::vector<TestCase>& testcase_list,
                            std::vector<ChildProcInfo>& child_proc_list) {
   size_t finished_child_count = 0;
@@ -709,6 +721,7 @@
       finished_child_count += CheckChildProcTimeout(child_proc_list);
     }
 
+    ReadChildProcOutput(testcase_list, child_proc_list);
     if (finished_child_count > 0) {
       return;
     }
@@ -742,26 +755,6 @@
     kill(child_proc.pid, SIGKILL);
     WaitForOneChild(child_proc.pid);
   }
-
-  while (true) {
-    char buf[1024];
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(child_proc.child_read_fd, buf, sizeof(buf) - 1));
-    if (bytes_read > 0) {
-      buf[bytes_read] = '\0';
-      testcase.GetTest(test_id).AppendTestOutput(buf);
-    } else if (bytes_read == 0) {
-      break; // Read end.
-    } else {
-      if (errno == EAGAIN) {
-        // No data is available. This rarely happens, only when the child process created other
-        // processes which have not exited so far. But the child process has already exited or
-        // been killed, so the test has finished, and we shouldn't wait further.
-        break;
-      }
-      perror("read child_read_fd in RunTestInSeparateProc");
-      exit(1);
-    }
-  }
   close(child_proc.child_read_fd);
 
   if (child_proc.timed_out) {
@@ -780,8 +773,14 @@
     testcase.GetTest(test_id).AppendTestOutput(buf);
 
   } else {
-    testcase.SetTestResult(test_id, WEXITSTATUS(child_proc.exit_status) == 0 ?
-                           TEST_SUCCESS : TEST_FAILED);
+    int exitcode = WEXITSTATUS(child_proc.exit_status);
+    testcase.SetTestResult(test_id, exitcode == 0 ? TEST_SUCCESS : TEST_FAILED);
+    if (exitcode != 0) {
+      char buf[1024];
+      snprintf(buf, sizeof(buf), "%s exited with exitcode %d.\n",
+               testcase.GetTestName(test_id).c_str(), exitcode);
+      testcase.GetTest(test_id).AppendTestOutput(buf);
+    }
   }
 }
 
diff --git a/tests/libs/namespaces_root.cpp b/tests/libs/namespaces_root.cpp
index 0bb4611..b0006c7 100644
--- a/tests/libs/namespaces_root.cpp
+++ b/tests/libs/namespaces_root.cpp
@@ -40,10 +40,12 @@
     return nullptr;
   }
 
-  const char* result = *static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
-  if (result != nullptr) {
+  const char** result = static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
+  if (result == nullptr) {
+    return nullptr;
+  } else {
     g_dlopened = true;
   }
 
-  return result;
+  return *result;
 }
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index e62518a..27d992b 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -30,12 +30,9 @@
 #include <unwind.h>
 
 #include <atomic>
-#include <regex>
 #include <vector>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-
+#include "private/bionic_constants.h"
 #include "private/bionic_macros.h"
 #include "private/ScopeGuard.h"
 #include "BionicDeathTest.h"
@@ -43,8 +40,6 @@
 
 #include "utils.h"
 
-extern "C" pid_t gettid();
-
 TEST(pthread, pthread_key_create) {
   pthread_key_t key;
   ASSERT_EQ(0, pthread_key_create(&key, NULL));
@@ -164,7 +159,7 @@
   pthread_key_t key;
   ASSERT_EQ(0, pthread_key_create(&key, NULL));
 
-  size_t stack_size = 128 * 1024;
+  size_t stack_size = 640 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, stack);
   memset(stack, 0xff, stack_size);
@@ -222,13 +217,13 @@
     while (spin_flag_) {}
     return NULL;
   }
-  static volatile bool spin_flag_;
+  static std::atomic<bool> spin_flag_;
 };
 
 // It doesn't matter if spin_flag_ is used in several tests,
 // because it is always set to false after each test. Each thread
 // loops on spin_flag_ can find it becomes false at some time.
-volatile bool SpinFunctionHelper::spin_flag_ = false;
+std::atomic<bool> SpinFunctionHelper::spin_flag_;
 
 static void* JoinFn(void* arg) {
   return reinterpret_cast<void*>(pthread_join(reinterpret_cast<pthread_t>(arg), NULL));
@@ -421,6 +416,8 @@
   pthread_t t1;
   ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
   ASSERT_EQ(0, pthread_setname_np(t1, "short 2"));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t1, nullptr));
 }
 
 TEST(pthread, pthread_setname_np__no_such_thread) {
@@ -471,6 +468,8 @@
   ASSERT_EQ(0, pthread_getcpuclockid(t, &c));
   timespec ts;
   ASSERT_EQ(0, clock_gettime(c, &ts));
+  spinhelper.UnSpin();
+  ASSERT_EQ(0, pthread_join(t, nullptr));
 }
 
 TEST(pthread, pthread_getcpuclockid__no_such_thread) {
@@ -539,7 +538,7 @@
   // http://b/11693195 --- pthread_join could return before the thread had actually exited.
   // If the joiner unmapped the thread's stack, that could lead to SIGSEGV in the thread.
   for (size_t i = 0; i < 1024; ++i) {
-    size_t stack_size = 64*1024;
+    size_t stack_size = 640*1024;
     void* stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 
     pthread_attr_t a;
@@ -721,58 +720,47 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&l));
 }
 
-static void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
-  while (tid == 0) {
-    usleep(1000);
-  }
-  std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
-  std::regex regex {R"(\s+S\s+)"};
-
-  while (true) {
-    std::string content;
-    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
-    if (std::regex_search(content, regex)) {
-      break;
-    }
-    usleep(1000);
-  }
-}
-
 struct RwlockWakeupHelperArg {
   pthread_rwlock_t lock;
   enum Progress {
     LOCK_INITIALIZED,
     LOCK_WAITING,
     LOCK_RELEASED,
-    LOCK_ACCESSED
+    LOCK_ACCESSED,
+    LOCK_TIMEDOUT,
   };
   std::atomic<Progress> progress;
   std::atomic<pid_t> tid;
+  std::function<int (pthread_rwlock_t*)> trylock_function;
+  std::function<int (pthread_rwlock_t*)> lock_function;
+  std::function<int (pthread_rwlock_t*, const timespec*)> timed_lock_function;
 };
 
-static void pthread_rwlock_reader_wakeup_writer_helper(RwlockWakeupHelperArg* arg) {
+static void pthread_rwlock_wakeup_helper(RwlockWakeupHelperArg* arg) {
   arg->tid = gettid();
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
   arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
 
-  ASSERT_EQ(EBUSY, pthread_rwlock_trywrlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_wrlock(&arg->lock));
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+  ASSERT_EQ(0, arg->lock_function(&arg->lock));
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
   ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
 
   arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
 }
 
-TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+static void test_pthread_rwlock_reader_wakeup_writer(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
   ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
   wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
   wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_trywrlock;
+  wakeup_arg.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_reader_wakeup_writer_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -784,29 +772,31 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
-static void pthread_rwlock_writer_wakeup_reader_helper(RwlockWakeupHelperArg* arg) {
-  arg->tid = gettid();
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
-  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
-
-  ASSERT_EQ(EBUSY, pthread_rwlock_tryrdlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_rdlock(&arg->lock));
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
-  ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
-
-  arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
+TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+  test_pthread_rwlock_reader_wakeup_writer(pthread_rwlock_wrlock);
 }
 
-TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_reader_wakeup_writer([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedwrlock(lock, &ts);
+  });
+}
+
+static void test_pthread_rwlock_writer_wakeup_reader(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
   ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
   wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
   wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_tryrdlock;
+  wakeup_arg.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_writer_wakeup_reader_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -818,6 +808,85 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
+TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+  test_pthread_rwlock_writer_wakeup_reader(pthread_rwlock_rdlock);
+}
+
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_writer_wakeup_reader([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedrdlock(lock, &ts);
+  });
+}
+
+static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
+  arg->tid = gettid();
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
+  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
+
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, arg->progress);
+  arg->progress = RwlockWakeupHelperArg::LOCK_TIMEDOUT;
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+  RwlockWakeupHelperArg wakeup_arg;
+  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+  ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
+  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+  wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_tryrdlock;
+  wakeup_arg.timed_lock_function = pthread_rwlock_timedrdlock;
+
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+  WaitUntilThreadSleep(wakeup_arg.tid);
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
+TEST(pthread, pthread_rwlock_timedwrlock_timeout) {
+  RwlockWakeupHelperArg wakeup_arg;
+  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+  ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
+  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+  wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = pthread_rwlock_trywrlock;
+  wakeup_arg.timed_lock_function = pthread_rwlock_timedwrlock;
+
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+  WaitUntilThreadSleep(wakeup_arg.tid);
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
 class RwlockKindTestHelper {
  private:
   struct ThreadArg {
@@ -1062,36 +1131,44 @@
   };
   std::atomic<Progress> progress;
   pthread_t thread;
+  std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function;
 
  protected:
-  virtual void SetUp() {
-    ASSERT_EQ(0, pthread_mutex_init(&mutex, NULL));
-    ASSERT_EQ(0, pthread_cond_init(&cond, NULL));
+  void SetUp() override {
+    ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+  }
+
+  void InitCond(clockid_t clock=CLOCK_REALTIME) {
+    pthread_condattr_t attr;
+    ASSERT_EQ(0, pthread_condattr_init(&attr));
+    ASSERT_EQ(0, pthread_condattr_setclock(&attr, clock));
+    ASSERT_EQ(0, pthread_cond_init(&cond, &attr));
+    ASSERT_EQ(0, pthread_condattr_destroy(&attr));
+  }
+
+  void StartWaitingThread(std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function) {
     progress = INITIALIZED;
-    ASSERT_EQ(0,
-      pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
-  }
-
-  virtual void TearDown() {
-    ASSERT_EQ(0, pthread_join(thread, NULL));
-    ASSERT_EQ(FINISHED, progress);
-    ASSERT_EQ(0, pthread_cond_destroy(&cond));
-    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
-  }
-
-  void SleepUntilProgress(Progress expected_progress) {
-    while (progress != expected_progress) {
+    this->wait_function = wait_function;
+    ASSERT_EQ(0, pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
+    while (progress != WAITING) {
       usleep(5000);
     }
     usleep(5000);
   }
 
+  void TearDown() override {
+    ASSERT_EQ(0, pthread_join(thread, nullptr));
+    ASSERT_EQ(FINISHED, progress);
+    ASSERT_EQ(0, pthread_cond_destroy(&cond));
+    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
+  }
+
  private:
   static void WaitThreadFn(pthread_CondWakeupTest* test) {
     ASSERT_EQ(0, pthread_mutex_lock(&test->mutex));
     test->progress = WAITING;
     while (test->progress == WAITING) {
-      ASSERT_EQ(0, pthread_cond_wait(&test->cond, &test->mutex));
+      ASSERT_EQ(0, test->wait_function(&test->cond, &test->mutex));
     }
     ASSERT_EQ(SIGNALED, test->progress);
     test->progress = FINISHED;
@@ -1099,39 +1176,65 @@
   }
 };
 
-TEST_F(pthread_CondWakeupTest, signal) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, signal_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_signal(&cond);
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
 }
 
-TEST_F(pthread_CondWakeupTest, broadcast) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, broadcast_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_broadcast(&cond);
+  ASSERT_EQ(0, pthread_cond_broadcast(&cond));
 }
 
-TEST(pthread, pthread_mutex_timedlock) {
-  pthread_mutex_t m;
-  ASSERT_EQ(0, pthread_mutex_init(&m, NULL));
-
-  // If the mutex is already locked, pthread_mutex_timedlock should time out.
-  ASSERT_EQ(0, pthread_mutex_lock(&m));
-
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_REALTIME) {
+  InitCond(CLOCK_REALTIME);
   timespec ts;
   ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
-  // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC) {
+  InitCond(CLOCK_MONOTONIC);
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
+TEST(pthread, pthread_cond_timedwait_timeout) {
+  pthread_mutex_t mutex;
+  ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+  pthread_cond_t cond;
+  ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
+  ASSERT_EQ(0, pthread_mutex_lock(&mutex));
+  timespec ts;
   ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
-
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
-  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(0, pthread_mutex_unlock(&mutex));
 }
 
 TEST(pthread, pthread_attr_getstack__main_thread) {
@@ -1552,6 +1655,35 @@
 #endif
 }
 
+TEST(pthread, pthread_mutex_timedlock) {
+  pthread_mutex_t m;
+  ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
+
+  // If the mutex is already locked, pthread_mutex_timedlock should time out.
+  ASSERT_EQ(0, pthread_mutex_lock(&m));
+
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+
+  // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
+  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
+
+  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+}
+
 class StrictAlignmentAllocator {
  public:
   void* allocate(size_t size, size_t alignment) {
@@ -1749,13 +1881,13 @@
   const size_t ITERATION_COUNT = 10000;
   for (size_t i = 1; i <= ITERATION_COUNT; ++i) {
     arg->array[arg->id] = i;
-    int ret = pthread_barrier_wait(arg->barrier);
-    ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
+    int result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
     for (size_t j = 0; j < arg->array_length; ++j) {
       ASSERT_EQ(i, arg->array[j]);
     }
-    ret = pthread_barrier_wait(arg->barrier);
-    ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
+    result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
   }
 }
 
@@ -1779,3 +1911,14 @@
     ASSERT_EQ(0, pthread_join(threads[i], nullptr));
   }
 }
+
+TEST(pthread, pthread_spinlock_smoke) {
+  pthread_spinlock_t lock;
+  ASSERT_EQ(0, pthread_spin_init(&lock, 0));
+  ASSERT_EQ(0, pthread_spin_trylock(&lock));
+  ASSERT_EQ(0, pthread_spin_unlock(&lock));
+  ASSERT_EQ(0, pthread_spin_lock(&lock));
+  ASSERT_EQ(EBUSY, pthread_spin_trylock(&lock));
+  ASSERT_EQ(0, pthread_spin_unlock(&lock));
+  ASSERT_EQ(0, pthread_spin_destroy(&lock));
+}
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index e517f81..b65bfb8 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -117,6 +117,16 @@
   ts.tv_nsec = -1;
   ASSERT_EQ(-1, sem_timedwait(&s, &ts));
   ASSERT_EQ(EINVAL, errno);
+  errno = 0;
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(EINVAL, errno);
+
+  errno = 0;
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(ETIMEDOUT, errno);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index c95cbbd..7872567 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -30,6 +30,7 @@
 #include <locale.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 TEST(stdio_ext, __fbufsize) {
   FILE* fp = fopen("/proc/version", "r");
@@ -140,3 +141,24 @@
   ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY));
   fclose(fp);
 }
+
+static void LockingByCallerHelper(std::atomic<pid_t>* pid) {
+  *pid = gettid();
+  flockfile(stdout);
+  funlockfile(stdout);
+}
+
+TEST(stdio_ext, __fsetlocking_BYCALLER) {
+  // Check if users can use flockfile/funlockfile to protect stdio operations.
+  int old_state = __fsetlocking(stdout, FSETLOCKING_BYCALLER);
+  flockfile(stdout);
+  pthread_t thread;
+  std::atomic<pid_t> pid(0);
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                              reinterpret_cast<void* (*)(void*)>(LockingByCallerHelper), &pid));
+  WaitUntilThreadSleep(pid);
+  funlockfile(stdout);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  __fsetlocking(stdout, old_state);
+}
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index dffb646..ddb6c77 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <sys/mman.h>
+#include <sys/user.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -219,3 +220,15 @@
 TEST(sys_mman, mremap) {
   ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
 }
+
+const size_t huge = size_t(PTRDIFF_MAX) + 1;
+
+TEST(sys_mman, mmap_PTRDIFF_MAX) {
+  ASSERT_EQ(MAP_FAILED, mmap(nullptr, huge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+}
+
+TEST(sys_mman, mremap_PTRDIFF_MAX) {
+  void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, huge, MREMAP_MAYMOVE));
+}
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index c7bfee6..09eac3f 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -41,9 +41,6 @@
             return;
         }
 
-        old_pa = __system_property_area__;
-        __system_property_area__ = NULL;
-
         pa_dirname = dirname;
         pa_filename = pa_dirname + "/__properties__";
 
@@ -57,9 +54,8 @@
             return;
         }
 
-        __system_property_area__ = old_pa;
-
         __system_property_set_filename(PROP_FILENAME);
+        __system_properties_init();
         unlink(pa_filename.c_str());
         rmdir(pa_dirname.c_str());
     }
@@ -68,7 +64,6 @@
 private:
     std::string pa_dirname;
     std::string pa_filename;
-    void *old_pa;
 };
 
 static void foreach_test_callback(const prop_info *pi, void* cookie) {
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 0a97abc..5e06b1f 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -30,8 +30,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <base/file.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/strings.h>
 
 #include "private/get_cpu_count_from_string.h"
 
diff --git a/tests/utils.h b/tests/utils.h
index 53cf6b6..a8f3441 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -18,6 +18,14 @@
 #define __TEST_UTILS_H
 #include <inttypes.h>
 #include <sys/mman.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <string>
+#include <regex>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 
 #include "private/ScopeGuard.h"
 
@@ -82,4 +90,23 @@
   }
 };
 
+extern "C" pid_t gettid();
+
+static inline void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
+  while (tid == 0) {
+    usleep(1000);
+  }
+  std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
+  std::regex regex {R"(\s+S\s+)"};
+
+  while (true) {
+    std::string content;
+    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
+    if (std::regex_search(content, regex)) {
+      break;
+    }
+    usleep(1000);
+  }
+}
+
 #endif