Merge "Do not set properties in bionic_systrace"
diff --git a/libc/Android.mk b/libc/Android.mk
index ba3e5aa..456527a 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -697,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)
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/flockfile.cpp b/libc/bionic/flockfile.cpp
index db68801..db53828 100644
--- a/libc/bionic/flockfile.cpp
+++ b/libc/bionic/flockfile.cpp
@@ -36,20 +36,12 @@
 // struct __sfileext (see fileext.h).
 
 void flockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
   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 == nullptr) {
@@ -60,10 +52,6 @@
 }
 
 void funlockfile(FILE* fp) {
-  if (!__sdidinit) {
-    __sinit();
-  }
-
   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 91e210e..b0c62d6 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -54,7 +54,6 @@
 extern "C" int __system_properties_init(void);
 extern "C" int __set_tls(void* ptr);
 extern "C" int __set_tid_address(int* tid_address);
-extern "C" int __sinit(void);
 
 __LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
 
@@ -80,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);
@@ -98,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.
@@ -134,9 +136,6 @@
   __pthread_internal_add(main_thread);
 
   __system_properties_init(); // Requires 'environ'.
-  // Initialize stdio here to get rid of data races caused by lazy initialization.
-  // TODO: Remove other calls to __sinit().
-  __sinit();
 }
 
 __noreturn static void __early_abort(int line) {
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/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/include/android/dlext.h b/libc/include/android/dlext.h
index ed9a3b9..7979c43 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -152,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/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 3ae7059..6dcd3ae 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -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.
  */
@@ -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/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/libdl.c b/libdl/libdl.c
index 3928ba2..af2f83e 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -57,6 +57,7 @@
 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/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/linker/dlfcn.cpp b/linker/dlfcn.cpp
index d07ec86..fde9f5c 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -193,11 +193,12 @@
 }
 
 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());
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 82d0d9e..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>
@@ -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,6 +108,7 @@
   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);
@@ -126,11 +130,9 @@
 
 static const char* const kDefaultLdPaths[] = {
 #if defined(__LP64__)
-  "/odm/lib64",
   "/vendor/lib64",
   "/system/lib64",
 #else
-  "/odm/lib",
   "/vendor/lib",
   "/system/lib",
 #endif
@@ -139,15 +141,11 @@
 
 static const char* const kAsanDefaultLdPaths[] = {
 #if defined(__LP64__)
-  "/data/odm/lib64",
-  "/odm/lib64",
   "/data/vendor/lib64",
   "/vendor/lib64",
   "/data/lib64",
   "/system/lib64",
 #else
-  "/data/odm/lib",
-  "/odm/lib",
   "/data/vendor/lib",
   "/vendor/lib",
   "/data/lib",
@@ -316,6 +314,12 @@
     }
   }
 
+  for (const auto& dir : permitted_paths_) {
+    if (file_is_under_dir(file, dir)) {
+      return true;
+    }
+  }
+
   return false;
 }
 
@@ -544,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;
@@ -2285,7 +2282,7 @@
 
   // create anonymous namespace
   android_namespace_t* anon_ns =
-      create_namespace("(anonymous)", nullptr, anon_ns_library_path, false);
+      create_namespace("(anonymous)", nullptr, anon_ns_library_path, false, nullptr);
 
   if (anon_ns == nullptr) {
     g_public_namespace_initialized = false;
@@ -2299,7 +2296,8 @@
 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.");
     return nullptr;
@@ -2308,15 +2306,18 @@
   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);
diff --git a/linker/linker.h b/linker/linker.h
index b391fc3..49329c7 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -446,6 +446,7 @@
 
 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_utils.cpp b/linker/linker_utils.cpp
index db43d38..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 = "!/";
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index 65ffbdc5..987eabd 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -22,6 +22,7 @@
 
 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);
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index 3be9b3f..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;
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 97b5208..5327e36 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -628,10 +628,10 @@
   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:
@@ -732,13 +732,13 @@
 
   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);
@@ -772,14 +772,15 @@
 
   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 + "\" is not accessible for the namespace \"private_isolated2\"", 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"));
@@ -824,7 +825,7 @@
   android_namespace_t* ns = android_create_namespace(
                                 "private", nullptr,
                                 (lib_path + "/private_namespace_libs").c_str(),
-                                false);
+                                false, nullptr);
 
   ASSERT_TRUE(ns != nullptr) << dlerror();