Merge "Revert "property_contexts: split into platform and non-platform components""
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index ec48870..ebdae83 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -11,6 +11,26 @@
 and “pax-utils” for scanelf.
 
 
+## How we manage incompatible changes
+
+Our general practice with dynamic linker behavior changes is that they
+will be tied to an app's target API level:
+
+* Below the affected API level we'll preserve the old behavior or issue
+a warning, as appropriate.
+
+* At the affected API level and above, we’ll refuse to load the library.
+
+* Warnings about any behavior change that will affect a library if you
+increase your target API level will appear in logcat when that library
+is loaded, even if you're not yet targeting that API level.
+
+* On a developer preview build, dynamic linker warnings will also show up
+as toasts. Experience has shown that many developers don’t habitually
+check logcat for warnings until their app stops functioning, so the
+toasts help bring some visibility to the issues before it's too late.
+
+
 ## Changes to library search order
 
 We have made various fixes to library search order when resolving symbols.
diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
index 4a5c2da..c90dfad 100644
--- a/benchmarks/time_benchmark.cpp
+++ b/benchmarks/time_benchmark.cpp
@@ -40,7 +40,7 @@
 static void BM_time_gettimeofday(benchmark::State& state) {
   timeval tv;
   while (state.KeepRunning()) {
-    gettimeofday(&tv, NULL);
+    gettimeofday(&tv, nullptr);
   }
 }
 BENCHMARK(BM_time_gettimeofday);
@@ -48,14 +48,31 @@
 void BM_time_gettimeofday_syscall(benchmark::State& state) {
   timeval tv;
   while (state.KeepRunning()) {
-    syscall(__NR_gettimeofday, &tv, NULL);
+    syscall(__NR_gettimeofday, &tv, nullptr);
   }
 }
 BENCHMARK(BM_time_gettimeofday_syscall);
 
 void BM_time_time(benchmark::State& state) {
   while (state.KeepRunning()) {
-    time(NULL);
+    time(nullptr);
   }
 }
 BENCHMARK(BM_time_time);
+
+void BM_time_localtime(benchmark::State& state) {
+  time_t t = time(nullptr);
+  while (state.KeepRunning()) {
+    localtime(&t);
+  }
+}
+BENCHMARK(BM_time_localtime);
+
+void BM_time_localtime_r(benchmark::State& state) {
+  time_t t = time(nullptr);
+  while (state.KeepRunning()) {
+    struct tm tm;
+    localtime_r(&t, &tm);
+  }
+}
+BENCHMARK(BM_time_localtime_r);
diff --git a/libc/Android.bp b/libc/Android.bp
index 3f7e94c..33fa447 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1201,6 +1201,13 @@
     name: "libc_bionic",
 }
 
+genrule {
+    name: "generated_android_ids",
+    out: [ "generated_android_ids.h" ],
+    tool_files: [ "fs_config_generator.py" ],
+    cmd: "$(location fs_config_generator.py) aidarray system/core/include/private/android_filesystem_config.h > $(out)",
+}
+
 // ========================================================
 // libc_bionic_ndk.a- The portions of libc_bionic that can
 // be safely used in libc_ndk.a (no troublesome global data
@@ -1389,6 +1396,7 @@
     local_include_dirs: ["stdio"],
     include_dirs: ["bionic/libstdc++/include"],
     name: "libc_bionic_ndk",
+    generated_headers: ["generated_android_ids"],
 }
 
 // ========================================================
diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
index 1d152bb..4ff982b 100644
--- a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
@@ -101,16 +101,38 @@
         vld1.8      {d0}, [r1]!
         vst1.8      {d0}, [r0, :64]!
 
-2:      // Make sure we have at least 64 bytes to copy.
+2:      cmp         r2, #256
+        ble         .L_copy_loop
+
+        // Make sure DST is 64 BYTE aligned.
+        rsb         r3, r0, #0
+        ands        r3, r3, #0x30
+        beq         .L_copy_loop
+
+        sub         r2, r2, r3
+        cmp         r3, #0x10
+        beq         .L_copy_16
+
+        vld1.8      {d0  - d3},   [r1]!
+        vst1.8      {d0  - d3},   [r0, :128]!
+        ands        r3, r3, #0x10
+        beq         .L_copy_loop
+
+.L_copy_16:
+        vld1.8      {d0, d1}, [r1]!
+        vst1.8      {d0, d1}, [r0, :128]!
+
+.L_copy_loop:
+        // Make sure we have at least 64 bytes to copy.
         subs        r2, r2, #64
         blo         2f
 
 1:      // The main loop copies 64 bytes at a time.
         vld1.8      {d0  - d3},   [r1]!
-        vld1.8      {d4  - d7},   [r1]!
+        vst1.8      {d0  - d3},   [r0, :128]!
         pld         [r1, #(64*4)]
         subs        r2, r2, #64
-        vst1.8      {d0  - d3},   [r0, :128]!
+        vld1.8      {d4  - d7},   [r1]!
         vst1.8      {d4  - d7},   [r0, :128]!
         bhs         1b
 
diff --git a/libc/bionic/abort.cpp b/libc/bionic/abort.cpp
index 9aefd44..cf8fa8e 100644
--- a/libc/bionic/abort.cpp
+++ b/libc/bionic/abort.cpp
@@ -31,8 +31,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-extern "C" int tgkill(int tgid, int tid, int sig);
-
 void abort() {
   // Don't block SIGABRT to give any signal handler a chance; we ignore
   // any errors -- X311J doesn't allow abort to return anyway.
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index db0f777..e99eaca 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -43,6 +43,9 @@
 #include "private/libc_logging.h"
 #include "private/ThreadLocalBuffer.h"
 
+// Generated android_ids array
+#include "generated_android_ids.h"
+
 // POSIX seems to envisage an implementation where the <pwd.h> functions are
 // implemented by brute-force searching with getpwent(3), and the <grp.h>
 // functions are implemented similarly with getgrent(3). This means that it's
diff --git a/libc/bionic/pthread_kill.cpp b/libc/bionic/pthread_kill.cpp
index 93513fa..72a6ed1 100644
--- a/libc/bionic/pthread_kill.cpp
+++ b/libc/bionic/pthread_kill.cpp
@@ -32,8 +32,6 @@
 #include "private/ErrnoRestorer.h"
 #include "pthread_internal.h"
 
-extern "C" int tgkill(int tgid, int tid, int sig);
-
 int pthread_kill(pthread_t t, int sig) {
   ErrnoRestorer errno_restorer;
 
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 0f68431..5aefbaf 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -56,6 +56,7 @@
 #include "private/bionic_futex.h"
 #include "private/bionic_lock.h"
 #include "private/bionic_macros.h"
+#include "private/bionic_sdk_version.h"
 #include "private/libc_logging.h"
 
 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
@@ -1046,7 +1047,7 @@
 int __system_property_area_init()
 {
     free_and_unmap_contexts();
-    mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+    mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
     if (!initialize_properties()) {
         return -1;
     }
@@ -1265,6 +1266,11 @@
 
 const prop_info *__system_property_find_nth(unsigned n)
 {
+    if (bionic_get_application_target_sdk_version() >= __ANDROID_API_O__) {
+      __libc_fatal("__system_property_find_nth is not supported since Android O,"
+                   " please use __system_property_foreach instead.");
+    }
+
     find_nth_cookie cookie(n);
 
     const int err = __system_property_foreach(find_nth_fn, &cookie);
diff --git a/libc/fs_config_generator.py b/libc/fs_config_generator.py
new file mode 120000
index 0000000..aafb7dc
--- /dev/null
+++ b/libc/fs_config_generator.py
@@ -0,0 +1 @@
+../../build/tools/fs_config/fs_config_generator.py
\ No newline at end of file
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 7ae50de..ffce1fa 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -150,6 +150,7 @@
 int raise(int);
 int kill(pid_t, int);
 int killpg(int, int);
+int tgkill(int tgid, int tid, int sig) __INTRODUCED_IN_32(16);
 
 int sigaltstack(const stack_t*, stack_t*);
 
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index d3e0d8d..faed9a0 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -81,7 +81,8 @@
 ** is inefficient and order of results may change from call
 ** to call.
 */ 
-const prop_info *__system_property_find_nth(unsigned n);
+const prop_info *__system_property_find_nth(unsigned n)
+  __REMOVED_IN(26);
 
 /* Pass a prop_info for each system property to the provided
 ** callback.  Use __system_property_read() to read the value
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index f9c5ede..3ff7ead 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -186,19 +186,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
@@ -1535,8 +1532,15 @@
     wcswcs; # arm x86 mips
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -131,19 +131,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     __vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
     gMallocLeakZygoteChild;
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index f122937..391c65c 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -187,19 +187,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
@@ -1561,8 +1558,15 @@
     wcswcs; # arm x86 mips
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index a969703..c89b4ad 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -183,19 +183,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
@@ -1376,8 +1373,15 @@
     wcswcs; # arm x86 mips
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -131,19 +131,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     __vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
     gMallocLeakZygoteChild;
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index dfa839e..51b222d 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -183,19 +183,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __timer_create; # arm x86 mips
     __timer_delete; # arm x86 mips
@@ -1375,8 +1372,15 @@
     wcswcs; # arm x86 mips
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -131,19 +131,16 @@
     __sym_ntos;
     __sym_ston;
     __system_properties_init;
-    __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area__; # var
     __system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_area_serial; # introduced=23
     __system_property_find;
-    __system_property_find_nth;
     __system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_get;
     __system_property_read;
     __system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
     __system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
-    __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
     __umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     __vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
     gMallocLeakZygoteChild;
 } LIBC_O;
 
+LIBC_DEPRECATED {
+  global:
+    __system_property_find_nth;
+};
+
 LIBC_PLATFORM {
   global:
+    __system_property_add;
+    __system_property_update;
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index 74411f7..723e4f2 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -1327,21 +1327,22 @@
 
   // If that's not set, look at the "persist.sys.timezone" system property.
   if (name == NULL) {
+    // The lookup is the most expensive part by several orders of magnitude, so we cache it.
+    // We check for null more than once because the system property may not have been set
+    // yet, so our first lookup may fail.
     static const prop_info* pi;
+    if (pi == NULL) pi = __system_property_find("persist.sys.timezone");
 
-    if (!pi) {
-      pi = __system_property_find("persist.sys.timezone");
-    }
     if (pi) {
-      static char buf[PROP_VALUE_MAX];
-      static uint32_t s = -1;
-      static bool ok = false;
+      // If the property hasn't changed since the last time we read it, there's nothing else to do.
+      static uint32_t last_serial = -1;
       uint32_t serial = __system_property_serial(pi);
-      if (serial != s) {
-        ok = __system_property_read(pi, 0, buf) > 0;
-        s = serial;
-      }
-      if (ok) {
+      if (serial == last_serial) return;
+
+      // Otherwise read the new value...
+      last_serial = serial;
+      char buf[PROP_VALUE_MAX];
+      if (__system_property_read(pi, NULL, buf) > 0) {
         // POSIX and Java disagree about the sign in a timezone string. For POSIX, "GMT+3" means
         // "3 hours west/behind", but for Java it means "3 hours east/ahead". Since (a) Java is
         // the one that matches human expectations and (b) this system property is used directly
@@ -1532,16 +1533,22 @@
 #endif
 
 static struct tm *
-localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
+localtime_tzset(time_t const *timep, struct tm *tmp)
 {
   int err = lock();
   if (err) {
     errno = err;
     return NULL;
   }
-  if (setname || !lcl_is_set)
-    tzset_unlocked();
-  tmp = localsub(lclptr, timep, setname, tmp);
+
+  // http://b/31339449: POSIX says localtime(3) acts as if it called tzset(3), but upstream
+  // and glibc both think it's okay for localtime_r(3) to not do so (presumably because of
+  // the "not required to set tzname" clause). It's unclear that POSIX actually intended this,
+  // the BSDs disagree with glibc, and it's confusing to developers to have localtime_r(3)
+  // behave differently than other time zone-sensitive functions in <time.h>.
+  tzset_unlocked();
+
+  tmp = localsub(lclptr, timep, true, tmp);
   unlock();
   return tmp;
 }
@@ -1549,13 +1556,13 @@
 struct tm *
 localtime(const time_t *timep)
 {
-  return localtime_tzset(timep, &tm, true);
+  return localtime_tzset(timep, &tm);
 }
 
 struct tm *
 localtime_r(const time_t *timep, struct tm *tmp)
 {
-  return localtime_tzset(timep, tmp, false);
+  return localtime_tzset(timep, tmp);
 }
 
 /*
diff --git a/libc/upstream-freebsd/README.txt b/libc/upstream-freebsd/README.md
similarity index 100%
rename from libc/upstream-freebsd/README.txt
rename to libc/upstream-freebsd/README.md
diff --git a/libc/upstream-netbsd/README.txt b/libc/upstream-netbsd/README.md
similarity index 100%
rename from libc/upstream-netbsd/README.txt
rename to libc/upstream-netbsd/README.md
diff --git a/libc/upstream-openbsd/README.txt b/libc/upstream-openbsd/README.md
similarity index 100%
rename from libc/upstream-openbsd/README.txt
rename to libc/upstream-openbsd/README.md
diff --git a/linker/arch/arm/begin.S b/linker/arch/arm/begin.S
index 8cb599b..480047a 100644
--- a/linker/arch/arm/begin.S
+++ b/linker/arch/arm/begin.S
@@ -33,5 +33,5 @@
   bl __linker_init
 
   /* linker init returns the _entry address in the main image */
-  mov pc, r0
+  bx r0
 END(_start)
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 13edfe1..dad7409 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -306,9 +306,21 @@
   si->dynamic = nullptr;
 
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
+
+  // We haven't supported non-PIE since Lollipop for security reasons.
   if (elf_hdr->e_type != ET_DYN) {
-    __libc_fatal("\"%s\": error: only position independent executables (PIE) are supported.",
-                 g_argv[0]);
+    // We don't use __libc_fatal here because we don't want a tombstone: it's
+    // been several years now but we still find ourselves on app compatibility
+    // investigations because some app's trying to launch an executable that
+    // hasn't worked in at least three years, and we've "helpfully" dropped a
+    // tombstone for them. The tombstone never provided any detail relevant to
+    // fixing the problem anyway, and the utility of drawing extra attention
+    // to the problem is non-existent at this late date.
+    __libc_format_fd(STDERR_FILENO,
+                     "\"%s\": error: Android 5.0 and later only support "
+                     "position-independent executables (-fPIE).\n",
+                     g_argv[0]);
+    exit(0);
   }
 
   // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
diff --git a/tests/Android.bp b/tests/Android.bp
index da90a92..fe34b9f 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -155,6 +155,8 @@
     shared: {
         enabled: false,
     },
+
+    generated_headers: ["generated_android_ids"],
 }
 
 // -----------------------------------------------------------------------------
@@ -364,6 +366,8 @@
 
     include_dirs: ["bionic/libc"],
 
+    stl: "libc++_static",
+
     target: {
         android: {
             shared_libs: [
@@ -422,6 +426,9 @@
     defaults: ["bionic_tests_defaults"],
     host_supported: false,
 
+    srcs: [
+        "gtest_preinit_debuggerd.cpp",
+    ],
     whole_static_libs: [
         "libBionicTests",
         "libBionicGtestMain",
@@ -435,6 +442,7 @@
         "libtinyxml2",
         "liblog",
         "libbase",
+        "libdebuggerd_client",
     ],
 
     static_executable: true,
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 9236558..266c7d7 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -102,11 +102,7 @@
     $($(module)_ldlibs) \
     $($(module)_ldlibs_$(build_type)) \
 
-ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true)
-  LOCAL_CXX_STL := libc++_static
-else
-  LOCAL_CXX_STL := libc++
-endif
+LOCAL_CXX_STL := libc++_static
 
 ifeq ($(build_type),target)
   include $(BUILD_$(build_target))
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index cc236f8..f8232aa 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -30,6 +30,9 @@
 
 #include <private/android_filesystem_config.h>
 
+// Generated android_ids array
+#include "generated_android_ids.h"
+
 enum uid_type_t {
   TYPE_SYSTEM,
   TYPE_APP
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index f0dac7c..b9ee585 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -170,6 +170,9 @@
   void SetResult(TestResult result) { result_ = result; }
 
   TestResult GetResult() const { return result_; }
+  TestResult GetExpectedResult() const {
+    return GetName().find("xfail_") == 0 ? TEST_FAILED : TEST_SUCCESS;
+  }
 
   void SetTestTime(int64_t elapsed_time_ns) { elapsed_time_ns_ = elapsed_time_ns; }
 
@@ -224,6 +227,15 @@
     return test_list_[test_id].GetResult();
   }
 
+  TestResult GetExpectedTestResult(size_t test_id) const {
+    VerifyTestId(test_id);
+    return test_list_[test_id].GetExpectedResult();
+  }
+
+  bool GetTestSuccess(size_t test_id) const {
+    return GetTestResult(test_id) == GetExpectedTestResult(test_id);
+  }
+
   void SetTestTime(size_t test_id, int64_t elapsed_time_ns) {
     VerifyTestId(test_id);
     test_list_[test_id].SetTestTime(elapsed_time_ns);
@@ -356,7 +368,7 @@
   printf("%s", test_output.c_str());
 
   TestResult result = testcase.GetTestResult(test_id);
-  if (result == TEST_SUCCESS) {
+  if (result == testcase.GetExpectedTestResult(test_id)) {
     ColoredPrintf(COLOR_GREEN, "[       OK ] ");
   } else {
     ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
@@ -373,10 +385,19 @@
 
 static void OnTestEndPrint(const TestCase& testcase, size_t test_id) {
   TestResult result = testcase.GetTestResult(test_id);
+  TestResult expected = testcase.GetExpectedTestResult(test_id);
   if (result == TEST_SUCCESS) {
-    ColoredPrintf(COLOR_GREEN, "[    OK    ] ");
+    if (expected == TEST_SUCCESS) {
+      ColoredPrintf(COLOR_GREEN, "[    OK    ] ");
+    } else if (expected == TEST_FAILED) {
+      ColoredPrintf(COLOR_RED, "[  XPASS   ] ");
+    }
   } else if (result == TEST_FAILED) {
-    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+    if (expected == TEST_SUCCESS) {
+      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+    } else if (expected == TEST_FAILED) {
+      ColoredPrintf(COLOR_YELLOW, "[  XFAIL   ] ");
+    }
   } else if (result == TEST_TIMEOUT) {
     ColoredPrintf(COLOR_RED, "[ TIMEOUT  ] ");
   }
@@ -398,6 +419,7 @@
                                     int64_t elapsed_time_ns) {
 
   std::vector<std::string> fail_test_name_list;
+  std::vector<std::string> xpass_test_name_list;
   std::vector<std::pair<std::string, int64_t>> timeout_test_list;
 
   // For tests that were slow but didn't time out.
@@ -405,18 +427,28 @@
   size_t testcase_count = testcase_list.size();
   size_t test_count = 0;
   size_t success_test_count = 0;
+  size_t expected_failure_count = 0;
 
   for (const auto& testcase : testcase_list) {
     test_count += testcase.TestCount();
     for (size_t i = 0; i < testcase.TestCount(); ++i) {
       TestResult result = testcase.GetTestResult(i);
-      if (result == TEST_SUCCESS) {
-        ++success_test_count;
-      } else if (result == TEST_FAILED) {
-        fail_test_name_list.push_back(testcase.GetTestName(i));
-      } else if (result == TEST_TIMEOUT) {
-        timeout_test_list.push_back(std::make_pair(testcase.GetTestName(i),
-                                                   testcase.GetTestTime(i)));
+      TestResult expected = testcase.GetExpectedTestResult(i);
+      if (result == TEST_TIMEOUT) {
+        timeout_test_list.push_back(
+            std::make_pair(testcase.GetTestName(i), testcase.GetTestTime(i)));
+      } else if (result == expected) {
+        if (result == TEST_SUCCESS) {
+          ++success_test_count;
+        } else {
+          ++expected_failure_count;
+        }
+      } else {
+        if (result == TEST_FAILED) {
+          fail_test_name_list.push_back(testcase.GetTestName(i));
+        } else {
+          xpass_test_name_list.push_back(testcase.GetTestName(i));
+        }
       }
       if (result != TEST_TIMEOUT &&
           testcase.GetTestTime(i) / 1000000 >= GetSlowThresholdMs(testcase.GetTestName(i))) {
@@ -435,7 +467,12 @@
   }
   printf("\n");
   ColoredPrintf(COLOR_GREEN,  "[   PASS   ] ");
-  printf("%zu %s.\n", success_test_count, (success_test_count == 1) ? "test" : "tests");
+  printf("%zu %s.", success_test_count, (success_test_count == 1) ? "test" : "tests");
+  if (expected_failure_count > 0) {
+    printf(" (%zu expected failure%s)", expected_failure_count,
+           (expected_failure_count == 1) ? "" : "s");
+  }
+  printf("\n");
 
   // Print tests that timed out.
   size_t timeout_test_count = timeout_test_list.size();
@@ -472,7 +509,18 @@
     }
   }
 
-  if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0) {
+  // Print tests that should have failed.
+  size_t xpass_test_count = xpass_test_name_list.size();
+  if (xpass_test_count > 0) {
+    ColoredPrintf(COLOR_RED,  "[  XPASS   ] ");
+    printf("%zu %s, listed below:\n", xpass_test_count, (xpass_test_count == 1) ? "test" : "tests");
+    for (const auto& name : xpass_test_name_list) {
+      ColoredPrintf(COLOR_RED, "[  XPASS   ] ");
+      printf("%s\n", name.c_str());
+    }
+  }
+
+  if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0 || xpass_test_count > 0) {
     printf("\n");
   }
 
@@ -485,6 +533,10 @@
   if (fail_test_count > 0) {
     printf("%2zu FAILED %s\n", fail_test_count, (fail_test_count == 1) ? "TEST" : "TESTS");
   }
+  if (xpass_test_count > 0) {
+    printf("%2zu SHOULD HAVE FAILED %s\n", xpass_test_count, (xpass_test_count == 1) ? "TEST" : "TESTS");
+  }
+
   fflush(stdout);
 }
 
@@ -540,7 +592,7 @@
     auto& testcase = testcase_list[i];
     total_test_count += testcase.TestCount();
     for (size_t j = 0; j < testcase.TestCount(); ++j) {
-      if (testcase.GetTestResult(j) != TEST_SUCCESS) {
+      if (!testcase.GetTestSuccess(j)) {
         ++failed_count_list[i];
       }
       elapsed_time_list[i] += testcase.GetTestTime(j);
@@ -568,7 +620,7 @@
       fprintf(fp, "    <testcase name=\"%s\" status=\"run\" time=\"%.3lf\" classname=\"%s\"",
               testcase.GetTest(j).GetName().c_str(), testcase.GetTestTime(j) / 1e9,
               testcase.GetName().c_str());
-      if (testcase.GetTestResult(j) == TEST_SUCCESS) {
+      if (!testcase.GetTestSuccess(j)) {
         fputs(" />\n", fp);
       } else {
         fputs(">\n", fp);
@@ -927,7 +979,7 @@
           if (++finished_test_count_list[testcase_id] == testcase.TestCount()) {
             ++finished_testcase_count;
           }
-          if (testcase.GetTestResult(test_id) != TEST_SUCCESS) {
+          if (!testcase.GetTestSuccess(test_id)) {
             all_tests_passed = false;
           }
 
diff --git a/tests/gtest_preinit_debuggerd.cpp b/tests/gtest_preinit_debuggerd.cpp
new file mode 100644
index 0000000..aac2e3f
--- /dev/null
+++ b/tests/gtest_preinit_debuggerd.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "debuggerd/client.h"
+
+void __gtest_preinit() {
+  debuggerd_init(nullptr);
+}
+
+__attribute__((section(".preinit_array"), __used__))
+void (*__local_gtest_preinit)(void) = __gtest_preinit;
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 4cd991a..004f668 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -26,6 +26,7 @@
     sanitize: {
         never: true,
     },
+    stl: "libc++_static",
     target: {
         darwin: {
             enabled: false,
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 63da9e0..da70d21 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -31,6 +31,7 @@
 
 #include "BionicDeathTest.h"
 #include "TemporaryFile.h"
+#include "utils.h"
 
 #if defined(NOFORTIFY)
 #define STDIO_TEST stdio_nofortify
@@ -47,6 +48,7 @@
   rewind(fp);
 
   char line[1024];
+  memset(line, 0xff, sizeof(line));
   ASSERT_EQ(line, fgets(line, sizeof(line), fp));
   ASSERT_STREQ(expected, line);
 
@@ -938,7 +940,7 @@
   fclose(fp);
 }
 
-TEST(STDIO_TEST, fmemopen_NULL) {
+TEST(STDIO_TEST, KNOWN_FAILURE_ON_BIONIC(fmemopen_NULL)) {
   FILE* fp = fmemopen(nullptr, 128, "r+");
   ASSERT_NE(EOF, fputs("xyz\n", fp));
 
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index 569d4fb..60bd224 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -70,8 +70,38 @@
 
 TEST(sys_uio, process_vm_readv) {
   ASSERT_EQ(0, process_vm_readv(0, nullptr, 0, nullptr, 0, 0));
+
+  // Test that we can read memory from our own process
+  char src[1024] = "This is the source buffer containing some data";
+  char dst[1024] = "";
+  iovec remote = { src, sizeof src };
+  iovec local = { dst, sizeof dst };
+  ASSERT_EQ(ssize_t(sizeof src), process_vm_readv(getpid(), &local, 1, &remote, 1, 0));
+  // Check whether data was copied (in the correct direction)
+  ASSERT_EQ('T', dst[0]);
+  ASSERT_EQ(0, memcmp(src, dst, sizeof src));
+
+  // Reading from non-allocated memory should return an error
+  remote = { nullptr, sizeof dst };
+  ASSERT_EQ(-1, process_vm_readv(getpid(), &local, 1, &remote, 1, 0));
+  ASSERT_EQ(EFAULT, errno);
 }
 
 TEST(sys_uio, process_vm_writev) {
   ASSERT_EQ(0, process_vm_writev(0, nullptr, 0, nullptr, 0, 0));
+
+  // Test that we can read memory from our own process
+  char src[1024] = "This is the source buffer containing some data";
+  char dst[1024] = "";
+  iovec remote = { dst, sizeof dst };
+  iovec local = { src, sizeof src };
+  ASSERT_EQ(ssize_t(sizeof src), process_vm_writev(getpid(), &local, 1, &remote, 1, 0));
+  // Check whether data was copied (in the correct direction)
+  ASSERT_EQ('T', dst[0]);
+  ASSERT_EQ(0, memcmp(src, dst, sizeof src));
+
+  // Writing to non-allocated memory should return an error
+  remote = { nullptr, sizeof dst };
+  ASSERT_EQ(-1, process_vm_writev(getpid(), &local, 1, &remote, 1, 0));
+  ASSERT_EQ(EFAULT, errno);
 }
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 09eac3f..70482f0 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -244,16 +244,10 @@
     ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
     ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
 
-    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(0));
-    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(1));
-    ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(2));
-
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(3));
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(4));
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(5));
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(100));
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(200));
-    ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(247));
+    // This method is no longer supported and should result in abort
+    ASSERT_EXIT(__system_property_find_nth(0), testing::KilledBySignal(SIGABRT),
+                "__system_property_find_nth is not supported since Android O,"
+                " please use __system_property_foreach instead.");
 #else // __BIONIC__
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif // __BIONIC__
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 914cb61..8c4a8a9 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -674,3 +674,39 @@
   ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
   EXPECT_EQ(9, tm.tm_hour);
 }
+
+TEST(time, bug_31339449) {
+  // POSIX says localtime acts as if it calls tzset.
+  // tzset does two things:
+  //  1. it sets the time zone ctime/localtime/mktime/strftime will use.
+  //  2. it sets the global `tzname`.
+  // POSIX says localtime_r need not set `tzname` (2).
+  // Q: should localtime_r set the time zone (1)?
+  // Upstream tzcode (and glibc) answer "no", everyone else answers "yes".
+
+  // Pick a time, any time...
+  time_t t = 1475619727;
+
+  // Call tzset with a specific timezone.
+  setenv("TZ", "America/Atka", 1);
+  tzset();
+
+  // If we change the timezone and call localtime, localtime should use the new timezone.
+  setenv("TZ", "America/Los_Angeles", 1);
+  struct tm* tm_p = localtime(&t);
+  EXPECT_EQ(15, tm_p->tm_hour);
+
+  // Reset the timezone back.
+  setenv("TZ", "America/Atka", 1);
+  tzset();
+
+#if defined(__BIONIC__)
+  // If we change the timezone again and call localtime_r, localtime_r should use the new timezone.
+  setenv("TZ", "America/Los_Angeles", 1);
+  struct tm tm = {};
+  localtime_r(&t, &tm);
+  EXPECT_EQ(15, tm.tm_hour);
+#else
+  // The BSDs agree with us, but glibc gets this wrong.
+#endif
+}
diff --git a/tests/utils.h b/tests/utils.h
index 4c3aef4..79eed10 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -32,6 +32,12 @@
 
 #include "private/ScopeGuard.h"
 
+#if defined(__BIONIC__)
+#define KNOWN_FAILURE_ON_BIONIC(x) xfail_ ## x
+#else
+#define KNOWN_FAILURE_ON_BIONIC(x) x
+#endif
+
 #if defined(__linux__)
 
 struct map_record {
diff --git a/tests/wctype_test.cpp b/tests/wctype_test.cpp
index 84a0e65..1bc4128 100644
--- a/tests/wctype_test.cpp
+++ b/tests/wctype_test.cpp
@@ -29,7 +29,9 @@
 
 // bionic's dlsym doesn't work in static binaries, so we can't access icu,
 // so any unicode test case will fail.
-static bool have_dl = (dlopen("libc.so", 0) != nullptr);
+static bool have_dl() {
+  return (dlopen("libc.so", 0) != nullptr);
+}
 
 static void TestIsWideFn(int fn(wint_t),
                          int fn_l(wint_t, locale_t),
@@ -37,7 +39,7 @@
                          const wchar_t* falses) {
   UtfLocale l;
   for (const wchar_t* p = trues; *p; ++p) {
-    if (!have_dl && *p > 0x7f) {
+    if (!have_dl() && *p > 0x7f) {
       GTEST_LOG_(INFO) << "skipping unicode test " << *p;
       continue;
     }
@@ -45,7 +47,7 @@
     EXPECT_TRUE(fn_l(*p, l.l)) << *p;
   }
   for (const wchar_t* p = falses; *p; ++p) {
-    if (!have_dl && *p > 0x7f) {
+    if (!have_dl() && *p > 0x7f) {
       GTEST_LOG_(INFO) << "skipping unicode test " << *p;
       continue;
     }
@@ -107,7 +109,7 @@
   EXPECT_EQ(wint_t('!'), towlower(L'!'));
   EXPECT_EQ(wint_t('a'), towlower(L'a'));
   EXPECT_EQ(wint_t('a'), towlower(L'A'));
-  if (have_dl) {
+  if (have_dl()) {
     EXPECT_EQ(wint_t(L'ç'), towlower(L'ç'));
     EXPECT_EQ(wint_t(L'ç'), towlower(L'Ç'));
     EXPECT_EQ(wint_t(L'δ'), towlower(L'δ'));
@@ -123,7 +125,7 @@
   EXPECT_EQ(wint_t('!'), towlower_l(L'!', l.l));
   EXPECT_EQ(wint_t('a'), towlower_l(L'a', l.l));
   EXPECT_EQ(wint_t('a'), towlower_l(L'A', l.l));
-  if (have_dl) {
+  if (have_dl()) {
     EXPECT_EQ(wint_t(L'ç'), towlower_l(L'ç', l.l));
     EXPECT_EQ(wint_t(L'ç'), towlower_l(L'Ç', l.l));
     EXPECT_EQ(wint_t(L'δ'), towlower_l(L'δ', l.l));
@@ -138,7 +140,7 @@
   EXPECT_EQ(wint_t('!'), towupper(L'!'));
   EXPECT_EQ(wint_t('A'), towupper(L'a'));
   EXPECT_EQ(wint_t('A'), towupper(L'A'));
-  if (have_dl) {
+  if (have_dl()) {
     EXPECT_EQ(wint_t(L'Ç'), towupper(L'ç'));
     EXPECT_EQ(wint_t(L'Ç'), towupper(L'Ç'));
     EXPECT_EQ(wint_t(L'Δ'), towupper(L'δ'));
@@ -154,7 +156,7 @@
   EXPECT_EQ(wint_t('!'), towupper_l(L'!', l.l));
   EXPECT_EQ(wint_t('A'), towupper_l(L'a', l.l));
   EXPECT_EQ(wint_t('A'), towupper_l(L'A', l.l));
-  if (have_dl) {
+  if (have_dl()) {
     EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'ç', l.l));
     EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'Ç', l.l));
     EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'δ', l.l));