Merge "Avoid explicit use of "10000" in build files."
diff --git a/apex/Android.bp b/apex/Android.bp
index 100430d..c6c4cbf 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -36,6 +36,9 @@
     },
     key: "com.android.runtime.key",
     certificate: ":com.android.runtime.certificate",
+    prebuilts: [
+        "bionic-linker-config",
+    ],
 }
 
 sdk {
@@ -76,3 +79,10 @@
         },
     },
 }
+
+prebuilt_etc {
+    name: "bionic-linker-config",
+    src: "linker.config.txt",
+    filename: "linker.config.txt",
+    installable: false,
+}
diff --git a/apex/linker.config.txt b/apex/linker.config.txt
new file mode 100644
index 0000000..7bac3d6
--- /dev/null
+++ b/apex/linker.config.txt
@@ -0,0 +1,6 @@
+# Extra linker configurations for bionic APEX
+# See https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md#apex_etc_linker_config_txt
+
+[properties]
+# Set bionic APEX as force visible so bionic APEX namespace is accessible via android_get_exported_namespace
+visible = true
diff --git a/docs/fdtrack.md b/docs/fdtrack.md
new file mode 100644
index 0000000..5bc9860
--- /dev/null
+++ b/docs/fdtrack.md
@@ -0,0 +1,66 @@
+## fdtrack
+
+fdtrack consists of two parts: a set of hooks in bionic to register a callback
+that's invoked on file descriptor operations, and a library that implements a
+hook to perform and store backtraces for file descriptor creation.
+
+### bionic hooks
+bionic provides a header in the `bionic_libc_platform_headers` header_lib at <[bionic/fdtrack.h](https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/platform/bionic/fdtrack.h)>.
+Register a callback with `android_fdtrack_compare_exchange_hook` to receive
+callbacks upon file descriptor creation and destruction. This function can be
+called at any point in order to start capturing events, but be sure to properly
+handle unbalanced closes. This callback may be called from an async signal safe
+context, but not vfork (bionic tracks whether a thread is vforked, and chooses
+not to call callbacks when this is the case).
+
+### libfdtrack
+[libfdtrack](https://android.googlesource.com/platform/bionic/+/refs/heads/master/libfdtrack)
+implements a library that uses libunwindstack to unwind and store fd creation backtraces.
+
+
+#### Using libfdtrack
+libfdtrack registers its hook upon being loaded, so to start capturing
+backtraces, `dlopen("libfdtrack.so", RTLD_GLOBAL)` is all that's needed. To dump
+its output to logcat, either use `fdtrack_dump`, or send the signal
+`BIONIC_SIGNAL_FDTRACK` (available from `<bionic/reserved_signals.h>`) to the
+process. If you wish to iterate through the results programmatically,
+`fdtrack_iterate` can be used (warning: this interface is currently unstable,
+don't use it in code that can be used on multiple platform versions.)
+
+libfdtrack adds a significant amount of overhead, so for processes that are
+latency-critical like system_server, it's not feasible to always capture
+backtraces. Instead, if you can detect that an fd leak is ongoing, turning on
+backtraces for a while and then triggering a dump can be sufficient.
+system_server [implements this approach](https://android.googlesource.com/platform/frameworks/base/+/679f3e4242b8e018eb7df90ef433f81088a64fff%5E%21/),
+spawning a thread that regularly checks the count of fds in the process, turns
+on fdtrack when it hits a threshold, and then aborts after another threshold.
+This dumps the output to logcat, which will be available in both the tombstone
+and logcat from bugreports.
+
+#### Implementation details
+There are multiple methods to unwind in Android:
+
+ * libunwindstack
+   * Pros
+     * Primary method on the platform
+     * Able to unwind through ART
+   * Cons
+     * Uses malloc internally: unsafe unless a separate allocator is
+       statically-linked and steps are taken to prevent the unwind from being
+       interrupted by a signal
+     * Slow - infeasible to be used always in latency-sensitive processes
+ * `android_unsafe_frame_pointer_chase`
+   * Pros
+     * Definitely async signal safe
+     * Fast
+   * Cons
+     * Unable to unwind through ART because it doesn't maintain the frame pointer
+     * Requires -fno-omit-frame-pointer to be used on all code being unwound
+       through, which currently isn't the case on Android
+     * Frame layout is a mess on 32-bit ARM: the ARM standard, clang, and GCC
+       [all disagree](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172)
+     * Chasing the frame pointer will often result in multiple frames inside the
+       same function
+
+libfdtrack chooses to use libunwindstack for now, since unwinding through ART
+is critical to being useful for the initial user, system_server.
diff --git a/libc/Android.bp b/libc/Android.bp
index f638292..61d99ac 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -62,6 +62,8 @@
     cppflags: [],
     include_dirs: [
         "bionic/libc/async_safe/include",
+        // For android_filesystem_config.h.
+        "system/core/libcutils/include",
     ],
 
     header_libs: [
@@ -1178,7 +1180,6 @@
         },
     },
     whole_static_libs: [
-        "libc_bionic_systrace",
         "libsystemproperties",
     ],
     cppflags: ["-Wold-style-cast"],
@@ -1238,6 +1239,7 @@
         "bionic/pthread_setname_np.cpp",
         "bionic/pthread_setschedparam.cpp",
         "bionic/pthread_spinlock.cpp",
+        "bionic/sys_thread_properties.cpp",
 
         // The following implementations depend on pthread data or implementation,
         // so we can't include them in libc_ndk.a.
diff --git a/libc/NOTICE b/libc/NOTICE
index e8dc4e7..58d6679 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1040,6 +1040,22 @@
 -------------------------------------------------------------------
 
 Copyright (C) 2020 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2020 The Android Open Source Project
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 207035a..8b2a32b 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -30,6 +30,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/net.h>
 #include <pthread.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -51,12 +52,22 @@
 #include "private/ErrnoRestorer.h"
 #include "private/ScopedPthreadMutexLocker.h"
 
-// Don't call libc's close, since it might call back into us as a result of fdsan.
+// Don't call libc's close or socket, since it might call back into us as a result of fdsan/fdtrack.
 #pragma GCC poison close
 static int __close(int fd) {
   return syscall(__NR_close, fd);
 }
 
+static int __socket(int domain, int type, int protocol) {
+#if defined(__i386__)
+  unsigned long args[3] = {static_cast<unsigned long>(domain), static_cast<unsigned long>(type),
+                           static_cast<unsigned long>(protocol)};
+  return syscall(__NR_socketcall, SYS_SOCKET, &args);
+#else
+  return syscall(__NR_socket, domain, type, protocol);
+#endif
+}
+
 // Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
 enum AndroidEventLogType {
   EVENT_TYPE_INT = 0,
@@ -460,7 +471,7 @@
   // found that all logd crashes thus far have had no problem stuffing
   // the UNIX domain socket and moving on so not critical *today*.
 
-  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  int log_fd = TEMP_FAILURE_RETRY(__socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
   if (log_fd == -1) {
     return -1;
   }
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 56a8488..95f46e9 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -101,6 +101,19 @@
   __set_tcb_dtv(tcb, const_cast<TlsDtv*>(&zero_dtv));
 }
 
+// This is public so that the zygote can call it too. It is not expected
+// to be useful otherwise.
+//
+// Note in particular that it is not possible to return from any existing
+// stack frame with stack protector enabled after this function is called.
+extern "C" void android_reset_stack_guards() {
+  // The TLS stack guard is set from the global, so ensure that we've initialized the global
+  // before we initialize the TLS. Dynamic executables will initialize their copy of the global
+  // stack protector from the one in the main thread's TLS.
+  __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
+  __init_tcb_stack_guard(__get_bionic_tcb());
+}
+
 // Finish initializing the main thread.
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 extern "C" void __libc_init_main_thread_late() {
@@ -119,11 +132,7 @@
   // User code should never see this; we'll compute it when asked.
   pthread_attr_setstacksize(&main_thread.attr, 0);
 
-  // The TLS stack guard is set from the global, so ensure that we've initialized the global
-  // before we initialize the TLS. Dynamic executables will initialize their copy of the global
-  // stack protector from the one in the main thread's TLS.
-  __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
-  __init_tcb_stack_guard(__get_bionic_tcb());
+  android_reset_stack_guards();
 
   __init_thread(&main_thread);
 
diff --git a/libc/bionic/bionic_allocator.cpp b/libc/bionic/bionic_allocator.cpp
index b6d6ba7..98183d4 100644
--- a/libc/bionic/bionic_allocator.cpp
+++ b/libc/bionic/bionic_allocator.cpp
@@ -394,6 +394,26 @@
   }
 }
 
+size_t BionicAllocator::get_chunk_size(void* ptr) {
+  if (ptr == nullptr) return 0;
+
+  page_info* info = get_page_info_unchecked(ptr);
+  if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
+    // Invalid pointer (mismatched signature)
+    return 0;
+  }
+  if (info->type == kLargeObject) {
+    return info->allocated_size - (static_cast<char*>(ptr) - reinterpret_cast<char*>(info));
+  }
+
+  BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
+  if (allocator != info->allocator_addr) {
+    // Invalid pointer.
+    return 0;
+  }
+  return allocator->get_block_size();
+}
+
 BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator(uint32_t type) {
   if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
     async_safe_fatal("invalid type: %u", type);
diff --git a/libc/bionic/bionic_elf_tls.cpp b/libc/bionic/bionic_elf_tls.cpp
index 61d826c..d5fb05a 100644
--- a/libc/bionic/bionic_elf_tls.cpp
+++ b/libc/bionic/bionic_elf_tls.cpp
@@ -28,6 +28,7 @@
 
 #include "private/bionic_elf_tls.h"
 
+#include <async_safe/CHECK.h>
 #include <async_safe/log.h>
 #include <string.h>
 #include <sys/param.h>
@@ -269,6 +270,12 @@
         continue;
       }
     }
+    if (modules.on_destruction_cb != nullptr) {
+      void* dtls_begin = dtv->modules[i];
+      void* dtls_end =
+          static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
+      modules.on_destruction_cb(dtls_begin, dtls_end);
+    }
     allocator.free(dtv->modules[i]);
     dtv->modules[i] = nullptr;
   }
@@ -297,6 +304,12 @@
       memcpy(mod_ptr, segment.init_ptr, segment.init_size);
     }
     dtv->modules[module_idx] = mod_ptr;
+
+    // Reports the allocation to the listener, if any.
+    if (modules.on_creation_cb != nullptr) {
+      modules.on_creation_cb(mod_ptr,
+                             static_cast<void*>(static_cast<char*>(mod_ptr) + segment.size));
+    }
   }
 
   return static_cast<char*>(mod_ptr) + ti->offset;
@@ -351,6 +364,14 @@
       // This module's TLS memory is allocated statically, so don't free it here.
       continue;
     }
+
+    if (modules.on_destruction_cb != nullptr) {
+      void* dtls_begin = dtv->modules[i];
+      void* dtls_end =
+          static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
+      modules.on_destruction_cb(dtls_begin, dtls_end);
+    }
+
     allocator.free(dtv->modules[i]);
   }
 
@@ -364,3 +385,22 @@
   // Clear the DTV slot. The DTV must not be used again with this thread.
   tcb->tls_slot(TLS_SLOT_DTV) = nullptr;
 }
+
+// Invokes all the registered thread_exit callbacks, if any.
+void __notify_thread_exit_callbacks() {
+  TlsModules& modules = __libc_shared_globals()->tls_modules;
+  if (modules.first_thread_exit_callback == nullptr) {
+    // If there is no first_thread_exit_callback, there shouldn't be a tail.
+    CHECK(modules.thread_exit_callback_tail_node == nullptr);
+    return;
+  }
+
+  // Callbacks are supposed to be invoked in the reverse order
+  // in which they were registered.
+  CallbackHolder* node = modules.thread_exit_callback_tail_node;
+  while (node != nullptr) {
+    node->cb();
+    node = node->prev;
+  }
+  modules.first_thread_exit_callback();
+}
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index fd97712..0de51c5 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -14,52 +14,50 @@
  * limitations under the License.
  */
 
+#include "private/bionic_systrace.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "private/bionic_lock.h"
-#include "private/bionic_systrace.h"
-#include "private/CachedProperty.h"
-
 #include <async_safe/log.h>
 #include <cutils/trace.h> // For ATRACE_TAG_BIONIC.
 
+#include "private/CachedProperty.h"
+#include "private/bionic_lock.h"
+
 #define WRITE_OFFSET   32
 
 static Lock g_lock;
-static CachedProperty g_debug_atrace_tags_enableflags("debug.atrace.tags.enableflags");
-static uint64_t g_tags;
-static int g_trace_marker_fd = -1;
 
-static bool should_trace() {
+bool should_trace(const uint64_t enable_tags) {
+  static uint64_t tags_val;
+  static CachedProperty tags_prop(kTraceTagsProp);
   g_lock.lock();
-  if (g_debug_atrace_tags_enableflags.DidChange()) {
-    g_tags = strtoull(g_debug_atrace_tags_enableflags.Get(), nullptr, 0);
+  if (tags_prop.DidChange()) {
+    tags_val = strtoull(tags_prop.Get(), nullptr, 0);
   }
   g_lock.unlock();
-  return ((g_tags & ATRACE_TAG_BIONIC) != 0);
+  return tags_val & enable_tags;
 }
 
-static int get_trace_marker_fd() {
+int get_trace_marker_fd() {
+  static int opened_trace_marker_fd = -1;
   g_lock.lock();
-  if (g_trace_marker_fd == -1) {
-    g_trace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
-    if (g_trace_marker_fd == -1) {
-      g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
+  if (opened_trace_marker_fd == -1) {
+    opened_trace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
+    if (opened_trace_marker_fd == -1) {
+      opened_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
     }
   }
   g_lock.unlock();
-  return g_trace_marker_fd;
+  return opened_trace_marker_fd;
 }
 
-void bionic_trace_begin(const char* message) {
-  if (!should_trace()) {
-    return;
-  }
-
+// event could be 'B' for begin or 'E' for end.
+void output_trace(const char* message, const char event) {
   int trace_marker_fd = get_trace_marker_fd();
   if (trace_marker_fd == -1) {
     return;
@@ -69,13 +67,22 @@
   // kernel trace_marker.
   int length = strlen(message);
   char buf[length + WRITE_OFFSET];
-  size_t len = async_safe_format_buffer(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
+  size_t len =
+      async_safe_format_buffer(buf, length + WRITE_OFFSET, "%c|%d|%s", event, getpid(), message);
 
   // Tracing may stop just after checking property and before writing the message.
   // So the write is acceptable to fail. See b/20666100.
   TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
 }
 
+void bionic_trace_begin(const char* message) {
+  if (!should_trace()) {
+    return;
+  }
+
+  output_trace(message);
+}
+
 void bionic_trace_end() {
   if (!should_trace()) {
     return;
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 3b804b0..88ae477 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -94,9 +94,6 @@
 }
 
 char* __fgets_chk(char* dst, int supplied_size, FILE* stream, size_t dst_len_from_compiler) {
-  if (supplied_size < 0) {
-    __fortify_fatal("fgets: buffer size %d < 0", supplied_size);
-  }
   __check_buffer_access("fgets", "write into", supplied_size, dst_len_from_compiler);
   return fgets(dst, supplied_size, stream);
 }
diff --git a/libc/bionic/gethostname.cpp b/libc/bionic/gethostname.cpp
index 962fea1..b780a2f 100644
--- a/libc/bionic/gethostname.cpp
+++ b/libc/bionic/gethostname.cpp
@@ -32,10 +32,8 @@
 #include <unistd.h>
 
 int gethostname(char* buf, size_t n) {
-  struct utsname name;
-  if (uname(&name) == -1) {
-    return -1;
-  }
+  utsname name = {};
+  uname(&name);
 
   size_t name_length = static_cast<size_t>(strlen(name.nodename) + 1);
   if (name_length > n) {
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index cf5423e..e3a447d 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -147,6 +147,7 @@
     mod.first_generation = kTlsGenerationFirst;
 
     modules.module_count = 1;
+    modules.static_module_count = 1;
     modules.module_table = &mod;
   } else {
     layout.reserve_exe_segment_and_tcb(nullptr, progname);
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index 3b873b3..81dab57 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -112,7 +112,6 @@
   munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE);
 #endif
 
-  // Free the ELF TLS DTV and all dynamically-allocated ELF TLS memory.
   __free_dynamic_tls(__get_bionic_tcb());
 
   if (old_state == THREAD_DETACHED) {
@@ -128,6 +127,7 @@
     if (thread->mmap_size != 0) {
       // We need to free mapped space for detached threads when they exit.
       // That's not something we can do in C.
+      __notify_thread_exit_callbacks();
       __hwasan_thread_exit();
       _exit_with_stack_teardown(thread->mmap_base, thread->mmap_size);
     }
@@ -135,6 +135,8 @@
 
   // No need to free mapped space. Either there was no space mapped, or it is left for
   // the pthread_join caller to clean up.
+  __notify_thread_exit_callbacks();
   __hwasan_thread_exit();
+
   __exit(0);
 }
diff --git a/libc/bionic/strtol.cpp b/libc/bionic/strtol.cpp
index 63ac102..77f1d92 100644
--- a/libc/bionic/strtol.cpp
+++ b/libc/bionic/strtol.cpp
@@ -184,9 +184,7 @@
 }
 
 // Public API since L, but not in any header.
-extern "C" long long strtoq(const char* s, char** end, int base) {
-  return strtoll(s, end, base);
-}
+__strong_alias(strtoq, strtoll);
 
 unsigned long strtoul(const char* s, char** end, int base) {
   return StrToU<unsigned long, ULONG_MAX>(s, end, base);
@@ -201,6 +199,4 @@
 }
 
 // Public API since L, but not in any header.
-extern "C" unsigned long long strtouq(const char* s, char** end, int base) {
-  return strtoull(s, end, base);
-}
+__strong_alias(strtouq, strtoull);
diff --git a/libc/bionic/sys_thread_properties.cpp b/libc/bionic/sys_thread_properties.cpp
new file mode 100644
index 0000000..24d7551
--- /dev/null
+++ b/libc/bionic/sys_thread_properties.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/thread_properties.h>
+
+#include <async_safe/CHECK.h>
+#include <async_safe/log.h>
+
+#include <elf.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/user.h>
+
+#include "private/bionic_elf_tls.h"
+#include "private/bionic_globals.h"
+#include "private/bionic_tls.h"
+#include "pthread_internal.h"
+
+void __libc_get_static_tls_bounds(void** stls_begin, void** stls_end) {
+  const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+  *stls_begin = reinterpret_cast<char*>(__get_bionic_tcb()) - layout.offset_bionic_tcb();
+  *stls_end = reinterpret_cast<char*>(*stls_begin) + layout.size();
+}
+
+void __libc_register_thread_exit_callback(thread_exit_cb_t cb) {
+  TlsModules& modules = __libc_shared_globals()->tls_modules;
+
+  if (modules.first_thread_exit_callback == nullptr) {
+    modules.first_thread_exit_callback = cb;
+    return;
+  };
+
+  BionicAllocator& allocator = __libc_shared_globals()->tls_allocator;
+  CallbackHolder* new_node =
+      reinterpret_cast<CallbackHolder*>(allocator.alloc(sizeof(CallbackHolder)));
+  new_node->cb = cb;
+  new_node->prev = modules.thread_exit_callback_tail_node;
+  modules.thread_exit_callback_tail_node = new_node;
+}
+
+static inline __always_inline bionic_tcb* __get_bionic_tcb_for_thread(pid_t tid) {
+  // If tid is same as self, then we don't need ptrace.
+  if (gettid() == tid) return __get_bionic_tcb();
+
+  // Find the thread-pointer register for the given thread.
+  void** tp_reg = nullptr;
+
+#if defined(__x86_64__) || defined(__i386__)
+  struct user_regs_struct regs;
+  struct iovec pt_iov = {
+      .iov_base = &regs,
+      .iov_len = sizeof(regs),
+  };
+  if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
+#if defined(__x86_64__)
+    tp_reg = reinterpret_cast<void**>(regs.fs);
+#elif defined(__i386__)
+    tp_reg = reinterpret_cast<void**>(regs.xgs);
+#endif
+  }
+#elif defined(__aarch64__) || defined(__arm__)
+  uint64_t reg;
+  struct iovec pt_iov {
+    .iov_base = &reg, .iov_len = sizeof(reg),
+  };
+
+  if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) {
+    tp_reg = reinterpret_cast<void**>(reg);
+  }
+#endif
+
+  if (tp_reg == nullptr) {
+    async_safe_write_log(ANDROID_LOG_FATAL, "libc",
+                         "__get_bionic_tcb_for_thread failed to read thread register.");
+  }
+
+  return reinterpret_cast<bionic_tcb*>(&tp_reg[MIN_TLS_SLOT]);
+}
+
+void __libc_iterate_dynamic_tls(pid_t tid,
+                                void (*cb)(void* __dynamic_tls_begin, void* __dynamic_tls_end,
+                                           size_t __dso_id, void* __arg),
+                                void* arg) {
+  TlsModules& modules = __libc_shared_globals()->tls_modules;
+  bionic_tcb* const tcb = __get_bionic_tcb_for_thread(tid);
+  TlsDtv* const dtv = __get_tcb_dtv(tcb);
+  BionicAllocator& allocator = __libc_shared_globals()->tls_allocator;
+
+  for (size_t i = modules.static_module_count; i < dtv->count; ++i) {
+    void* dtls_begin = dtv->modules[i];
+    if (dtls_begin == nullptr) continue;
+    void* dtls_end =
+        static_cast<void*>(static_cast<char*>(dtls_begin) + allocator.get_chunk_size(dtls_begin));
+    size_t dso_id = __tls_module_idx_to_id(i);
+
+    cb(dtls_begin, dtls_end, dso_id, arg);
+  }
+}
+
+void __libc_register_dynamic_tls_listeners(dtls_listener_t on_creation,
+                                           dtls_listener_t on_destruction) {
+  TlsModules& tls_modules = __libc_shared_globals()->tls_modules;
+  tls_modules.on_creation_cb = on_creation;
+  tls_modules.on_destruction_cb = on_destruction;
+}
diff --git a/libc/bionic/system_property_set.cpp b/libc/bionic/system_property_set.cpp
index 212aafc..6823b6a 100644
--- a/libc/bionic/system_property_set.cpp
+++ b/libc/bionic/system_property_set.cpp
@@ -41,12 +41,13 @@
 #include <sys/_system_properties.h>
 #include <unistd.h>
 
-#include <async_safe/log.h>
 #include <async_safe/CHECK.h>
+#include <async_safe/log.h>
+#include <system_properties/prop_trace.h>
 
-#include "private/bionic_defs.h"
 #include "platform/bionic/macros.h"
 #include "private/ScopedFd.h"
+#include "private/bionic_defs.h"
 
 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
 static const char* kServiceVersionPropertyName = "ro.property_service.version";
@@ -249,6 +250,8 @@
   if (key == nullptr) return -1;
   if (value == nullptr) value = "";
 
+  SyspropTrace trace(key, value, nullptr /* prop_info */, PropertyAction::kPropertySet);
+
   if (g_propservice_protocol_version == 0) {
     detect_protocol_version();
   }
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 833fa59..a237254 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -170,6 +170,16 @@
  * Available since API level 28.
  */
 #define M_PURGE (-101)
+/*
+ * mallopt() option for per-thread memory initialization tuning.
+ * The value argument should be one of:
+ * 1: Disable automatic heap initialization and, where possible, memory tagging,
+ *    on this thread.
+ * 0: Normal behavior.
+ *
+ * Available since API level 31.
+ */
+#define M_THREAD_DISABLE_MEM_INIT (-103)
 /**
  * mallopt() option to set the maximum number of items in the secondary
  * cache of the scudo allocator.
diff --git a/libc/include/math.h b/libc/include/math.h
index 7efc83a..8c084b2 100644
--- a/libc/include/math.h
+++ b/libc/include/math.h
@@ -10,12 +10,10 @@
  */
 
 /*
- * from: @(#)fdlibm.h 5.1 93/09/24
- * $FreeBSD$
+ * Originally based on fdlibm.h 5.1 via FreeBSD.
  */
 
-#ifndef _MATH_H_
-#define _MATH_H_
+#pragma once
 
 #include <sys/cdefs.h>
 #include <limits.h>
@@ -408,5 +406,3 @@
 #endif
 
 __END_DECLS
-
-#endif
diff --git a/libc/include/sys/procfs.h b/libc/include/sys/procfs.h
index 75a1e98..a082e97 100644
--- a/libc/include/sys/procfs.h
+++ b/libc/include/sys/procfs.h
@@ -26,16 +26,24 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_PROCFS_H_
-#define _SYS_PROCFS_H_
+#pragma once
 
 #include <sys/cdefs.h>
+#include <sys/ptrace.h>
 #include <sys/ucontext.h>
 
 __BEGIN_DECLS
 
+#if defined(__arm__)
+#define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t))
+#elif defined(__aarch64__)
+#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
+#else
+#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+#endif
+
 typedef unsigned long elf_greg_t;
-typedef elf_greg_t elf_gregset_t[NGREG];
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef fpregset_t elf_fpregset_t;
 
@@ -58,5 +66,3 @@
 #define ELF_PRARGSZ 80
 
 __END_DECLS
-
-#endif
diff --git a/libc/include/sys/thread_properties.h b/libc/include/sys/thread_properties.h
new file mode 100644
index 0000000..b5d30c7
--- /dev/null
+++ b/libc/include/sys/thread_properties.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+/**
+ * @file thread_properties.h
+ * @brief Thread properties API.
+ *
+ * https://sourceware.org/glibc/wiki/ThreadPropertiesAPI
+ * API for querying various properties of the current thread, used mostly by
+ * the sanitizers.
+ *
+ * Available since API level 31.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/**
+ * Gets the bounds of static TLS for the current thread.
+ *
+ * Available since API level 31.
+ */
+void __libc_get_static_tls_bounds(void** __static_tls_begin,
+                                  void** __static_tls_end) __INTRODUCED_IN(31);
+
+
+/**
+ * Registers callback to be called right before the thread is dead.
+ * The callbacks are chained, they are called in the order opposite to the order
+ * they were registered.
+ *
+ * The callbacks must be registered only before any threads were created.
+ * No signals may arrive during the calls to these callbacks.
+ * The callbacks may not access the thread's dynamic TLS because they will have
+ * been freed by the time these callbacks are invoked.
+ *
+ * Available since API level 31.
+ */
+void __libc_register_thread_exit_callback(void (*__cb)(void)) __INTRODUCED_IN(31);
+
+/**
+ * Iterates over all dynamic TLS chunks for the given thread.
+ * The thread should have been suspended. It is undefined-behaviour if there is concurrent
+ * modification of the target thread's dynamic TLS.
+ *
+ * Available since API level 31.
+ */
+void __libc_iterate_dynamic_tls(pid_t __tid,
+                                void (*__cb)(void* __dynamic_tls_begin,
+                                             void* __dynamic_tls_end,
+                                             size_t __dso_id,
+                                             void* __arg),
+                                void* __arg) __INTRODUCED_IN(31);
+
+/**
+ * Register on_creation and on_destruction callbacks, which will be called after a dynamic
+ * TLS creation and before a dynamic TLS destruction, respectively.
+ *
+ * Available since API level 31.
+ */
+void __libc_register_dynamic_tls_listeners(
+    void (*__on_creation)(void* __dynamic_tls_begin,
+                          void* __dynamic_tls_end),
+    void (*__on_destruction)(void* __dynamic_tls_begin,
+                             void* __dynamic_tls_end)) __INTRODUCED_IN(31);
+
+__END_DECLS
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 10732a1..a224eab 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1554,6 +1554,10 @@
   global:
     ffsl;
     ffsll;
+    __libc_get_static_tls_bounds;
+    __libc_register_thread_exit_callback;
+    __libc_iterate_dynamic_tls;
+    __libc_register_dynamic_tls_listeners;
 } LIBC_R;
 
 LIBC_PRIVATE {
@@ -1766,4 +1770,5 @@
     android_net_res_stats_get_info_for_net;
     android_net_res_stats_aggregate;
     android_net_res_stats_get_usable_servers;
+    android_reset_stack_guards;
 } LIBC_Q;
diff --git a/libc/platform/bionic/mte_kernel.h b/libc/platform/bionic/mte_kernel.h
index e8ef2a5..d81480a 100644
--- a/libc/platform/bionic/mte_kernel.h
+++ b/libc/platform/bionic/mte_kernel.h
@@ -54,4 +54,6 @@
 #define PTRACE_PEEKMTETAGS 33
 #define PTRACE_POKEMTETAGS 34
 
+#define NT_ARM_TAGGED_ADDR_CTRL 0x409
+
 #endif
diff --git a/libc/platform/scudo_platform_tls_slot.h b/libc/platform/scudo_platform_tls_slot.h
new file mode 100644
index 0000000..9d017c0
--- /dev/null
+++ b/libc/platform/scudo_platform_tls_slot.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "bionic/tls.h"
+
+inline uintptr_t *getPlatformAllocatorTlsSlot() {
+  return reinterpret_cast<uintptr_t*>(&__get_tls()[TLS_SLOT_SANITIZER]);
+}
diff --git a/libc/private/bionic_allocator.h b/libc/private/bionic_allocator.h
index c705ce4..342fd51 100644
--- a/libc/private/bionic_allocator.h
+++ b/libc/private/bionic_allocator.h
@@ -110,6 +110,11 @@
   // Note that this implementation of realloc never shrinks allocation
   void* realloc(void* ptr, size_t size);
   void free(void* ptr);
+
+  // Returns the size of the given allocated heap chunk, if it is valid.
+  // Otherwise, this may return 0 or cause a segfault if the pointer is invalid.
+  size_t get_chunk_size(void* ptr);
+
  private:
   void* alloc_mmap(size_t align, size_t size);
   inline void* alloc_impl(size_t align, size_t size);
diff --git a/libc/private/bionic_elf_tls.h b/libc/private/bionic_elf_tls.h
index fa1af76..e0ec7b5 100644
--- a/libc/private/bionic_elf_tls.h
+++ b/libc/private/bionic_elf_tls.h
@@ -111,6 +111,18 @@
   void* soinfo_ptr = nullptr;
 };
 
+// Signature of the callbacks that will be called after DTLS creation and
+// before DTLS destruction.
+typedef void (*dtls_listener_t)(void* dynamic_tls_begin, void* dynamic_tls_end);
+
+// Signature of the thread-exit callbacks.
+typedef void (*thread_exit_cb_t)(void);
+
+struct CallbackHolder {
+  thread_exit_cb_t cb;
+  CallbackHolder* prev;
+};
+
 // Table of the ELF TLS modules. Either the dynamic linker or the static
 // initialization code prepares this table, and it's then used during thread
 // creation and for dynamic TLS lookups.
@@ -128,7 +140,20 @@
   // Pointer to a block of TlsModule objects. The first module has ID 1 and
   // is stored at index 0 in this table.
   size_t module_count = 0;
+  size_t static_module_count = 0;
   TlsModule* module_table = nullptr;
+
+  // Callback to be invoked after a dynamic TLS allocation.
+  dtls_listener_t on_creation_cb = nullptr;
+
+  // Callback to be invoked before a dynamic TLS deallocation.
+  dtls_listener_t on_destruction_cb = nullptr;
+
+  // The first thread-exit callback; inlined to avoid allocation.
+  thread_exit_cb_t first_thread_exit_callback = nullptr;
+
+  // The additional callbacks, if any.
+  CallbackHolder* thread_exit_callback_tail_node = nullptr;
 };
 
 void __init_static_tls(void* static_tls);
@@ -175,3 +200,4 @@
 
 struct bionic_tcb;
 void __free_dynamic_tls(bionic_tcb* tcb);
+void __notify_thread_exit_callbacks();
diff --git a/libc/private/bionic_ifuncs.h b/libc/private/bionic_ifuncs.h
index f175bec..e6b349a 100644
--- a/libc/private/bionic_ifuncs.h
+++ b/libc/private/bionic_ifuncs.h
@@ -40,9 +40,12 @@
 #define IFUNC_ARGS ()
 #endif
 
+// We can't have HWASAN enabled in resolvers because they may be called before HWASAN is
+// initialized.
 #define DEFINE_IFUNC_FOR(name) \
     name##_func name __attribute__((ifunc(#name "_resolver"))); \
     __attribute__((visibility("hidden"))) \
+    __attribute__((no_sanitize("hwaddress"))) \
     name##_func* name##_resolver IFUNC_ARGS
 
 #define DECLARE_FUNC(type, name) \
diff --git a/libc/private/bionic_systrace.h b/libc/private/bionic_systrace.h
index dbe1739..6b11812 100644
--- a/libc/private/bionic_systrace.h
+++ b/libc/private/bionic_systrace.h
@@ -16,8 +16,12 @@
 
 #pragma once
 
+#include <cutils/trace.h>  // For ATRACE_TAG_BIONIC.
+
 #include "platform/bionic/macros.h"
 
+static constexpr char kTraceTagsProp[] = "debug.atrace.tags.enableflags";
+
 // Tracing class for bionic. To begin a trace at a specified point:
 //   ScopedTrace("Trace message");
 // The trace will end when the contructor goes out of scope.
@@ -33,5 +37,9 @@
   BIONIC_DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
 };
 
+int get_trace_marker_fd();
+bool should_trace(const uint64_t enable_tags = ATRACE_TAG_BIONIC);
+void output_trace(const char* message, const char event = 'B');
+
 void bionic_trace_begin(const char* message);
 void bionic_trace_end();
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index afc2c48..b8aced8 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -773,10 +773,7 @@
 // Returns first argument, or nullptr if no characters were read.
 // Does not return nullptr if n == 1.
 char* fgets_unlocked(char* buf, int n, FILE* fp) {
-  if (n <= 0) {
-    errno = EINVAL;
-    return nullptr;
-  }
+  if (n <= 0) __fortify_fatal("fgets: buffer size %d <= 0", n);
 
   _SET_ORIENTATION(fp, -1);
 
diff --git a/libc/system_properties/Android.bp b/libc/system_properties/Android.bp
index 8780dda..3846169 100644
--- a/libc/system_properties/Android.bp
+++ b/libc/system_properties/Android.bp
@@ -8,9 +8,11 @@
         "contexts_serialized.cpp",
         "prop_area.cpp",
         "prop_info.cpp",
+        "prop_trace.cpp",
         "system_properties.cpp",
     ],
     whole_static_libs: [
+        "libc_bionic_systrace",
         "libpropertyinfoparser",
     ],
     header_libs: [
@@ -23,3 +25,20 @@
     ],
     export_include_dirs: ["include"],
 }
+
+cc_benchmark {
+    name: "property_context_lookup_benchmark",
+    srcs: [
+        "context_lookup_benchmark.cpp",
+    ],
+    include_dirs: [
+        "bionic/libc",
+    ],
+
+    shared_libs: ["libbase"],
+    static_libs: [
+        "libpropertyinfoserializer",
+        "libsystemproperties",
+        "libasync_safe",
+    ],
+}
diff --git a/libc/system_properties/context_lookup_benchmark.cpp b/libc/system_properties/context_lookup_benchmark.cpp
new file mode 100644
index 0000000..1564250
--- /dev/null
+++ b/libc/system_properties/context_lookup_benchmark.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <benchmark/benchmark.h>
+#include <property_info_parser/property_info_parser.h>
+#include <property_info_serializer/property_info_serializer.h>
+#include <system_properties/contexts_split.h>
+
+#include "context_lookup_benchmark_data.h"
+
+using android::base::Split;
+using android::base::WriteStringToFd;
+using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
+using android::properties::PropertyInfoArea;
+using android::properties::PropertyInfoEntry;
+
+BENCHMARK_MAIN();
+
+class LegacyPropertyMapping : public ContextsSplit {
+ public:
+  LegacyPropertyMapping(const char* property_contexts) {
+    TemporaryFile file;
+    if (!WriteStringToFd(property_contexts, file.fd)) {
+      PLOG(FATAL) << "Could not write to temporary file";
+    }
+
+    if (!InitializePropertiesFromFile(file.path)) {
+      LOG(FATAL) << "Could not initialize properties";
+    }
+  }
+};
+
+static std::vector<std::string> PropertiesToLookup() {
+  std::vector<std::string> properties;
+  auto property_lines = Split(aosp_s_property_contexts, "\n");
+  for (const auto& line : property_lines) {
+    if (line.empty() || line[0] == '#') {
+      continue;
+    }
+
+    auto property = Split(line, " ")[0];
+    properties.push_back(property);
+    properties.push_back(property + "0");
+    properties.push_back(property + "A");
+  }
+  return properties;
+}
+
+static void LegacyLookupOreo(benchmark::State& state) {
+  LegacyPropertyMapping mapping(oreo_property_contexts);
+  auto properties = PropertiesToLookup();
+  for (auto _ : state) {
+    for (const auto& property : properties) {
+      benchmark::DoNotOptimize(mapping.GetPrefixNodeForName(property.c_str()));
+    }
+  }
+}
+BENCHMARK(LegacyLookupOreo);
+
+static void LegacyLookupS(benchmark::State& state) {
+  LegacyPropertyMapping mapping(aosp_s_property_contexts);
+  auto properties = PropertiesToLookup();
+  for (auto _ : state) {
+    for (const auto& property : properties) {
+      benchmark::DoNotOptimize(mapping.GetPrefixNodeForName(property.c_str()));
+    }
+  }
+}
+BENCHMARK(LegacyLookupS);
+
+static std::string CreateSerializedTrie(const char* input_file) {
+  std::vector<std::string> errors;
+  std::vector<PropertyInfoEntry> property_infos;
+  ParsePropertyInfoFile(input_file, false, &property_infos, &errors);
+
+  std::string serialized_trie;
+  std::string error;
+  if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_trie,
+                 &error)) {
+    LOG(FATAL) << "Could not build trie: " << error;
+  }
+  return serialized_trie;
+}
+
+static void TrieLookupOreo(benchmark::State& state) {
+  std::string serialized_trie = CreateSerializedTrie(oreo_property_contexts);
+  PropertyInfoArea* trie = reinterpret_cast<PropertyInfoArea*>(serialized_trie.data());
+  auto properties = PropertiesToLookup();
+  for (auto _ : state) {
+    for (const auto& property : properties) {
+      trie->GetPropertyInfo(property.c_str(), nullptr, nullptr);
+    }
+  }
+}
+BENCHMARK(TrieLookupOreo);
+
+static void TrieLookupS(benchmark::State& state) {
+  std::string serialized_trie = CreateSerializedTrie(aosp_s_property_contexts);
+  PropertyInfoArea* trie = reinterpret_cast<PropertyInfoArea*>(serialized_trie.data());
+  auto properties = PropertiesToLookup();
+  for (auto _ : state) {
+    for (const auto& property : properties) {
+      trie->GetPropertyInfo(property.c_str(), nullptr, nullptr);
+    }
+  }
+}
+BENCHMARK(TrieLookupS);
diff --git a/libc/system_properties/context_lookup_benchmark_data.h b/libc/system_properties/context_lookup_benchmark_data.h
new file mode 100644
index 0000000..3cc3257
--- /dev/null
+++ b/libc/system_properties/context_lookup_benchmark_data.h
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+static char oreo_property_contexts[] = R"(
+net.rmnet               u:object_r:net_radio_prop:s0
+net.gprs                u:object_r:net_radio_prop:s0
+net.ppp                 u:object_r:net_radio_prop:s0
+net.qmi                 u:object_r:net_radio_prop:s0
+net.lte                 u:object_r:net_radio_prop:s0
+net.cdma                u:object_r:net_radio_prop:s0
+net.dns                 u:object_r:net_dns_prop:s0
+sys.usb.config          u:object_r:system_radio_prop:s0
+ril.                    u:object_r:radio_prop:s0
+ro.ril.                 u:object_r:radio_prop:s0
+gsm.                    u:object_r:radio_prop:s0
+persist.radio           u:object_r:radio_prop:s0
+net.                    u:object_r:system_prop:s0
+dev.                    u:object_r:system_prop:s0
+ro.runtime.             u:object_r:system_prop:s0
+ro.runtime.firstboot    u:object_r:firstboot_prop:s0
+hw.                     u:object_r:system_prop:s0
+ro.hw.                  u:object_r:system_prop:s0
+sys.                    u:object_r:system_prop:s0
+sys.cppreopt            u:object_r:cppreopt_prop:s0
+sys.powerctl            u:object_r:powerctl_prop:s0
+sys.usb.ffs.            u:object_r:ffs_prop:s0
+service.                u:object_r:system_prop:s0
+dhcp.                   u:object_r:dhcp_prop:s0
+dhcp.bt-pan.result      u:object_r:pan_result_prop:s0
+bluetooth.              u:object_r:bluetooth_prop:s0
+debug.                  u:object_r:debug_prop:s0
+debug.db.               u:object_r:debuggerd_prop:s0
+dumpstate.              u:object_r:dumpstate_prop:s0
+dumpstate.options       u:object_r:dumpstate_options_prop:s0
+log.                    u:object_r:log_prop:s0
+log.tag                 u:object_r:log_tag_prop:s0
+log.tag.WifiHAL         u:object_r:wifi_log_prop:s0
+security.perf_harden    u:object_r:shell_prop:s0
+service.adb.root        u:object_r:shell_prop:s0
+service.adb.tcp.port    u:object_r:shell_prop:s0
+persist.audio.          u:object_r:audio_prop:s0
+persist.bluetooth.      u:object_r:bluetooth_prop:s0
+persist.debug.          u:object_r:persist_debug_prop:s0
+persist.logd.           u:object_r:logd_prop:s0
+persist.logd.security   u:object_r:device_logging_prop:s0
+persist.logd.logpersistd        u:object_r:logpersistd_logging_prop:s0
+logd.logpersistd        u:object_r:logpersistd_logging_prop:s0
+persist.log.tag         u:object_r:log_tag_prop:s0
+persist.mmc.            u:object_r:mmc_prop:s0
+persist.sys.            u:object_r:system_prop:s0
+persist.sys.safemode    u:object_r:safemode_prop:s0
+ro.sys.safemode         u:object_r:safemode_prop:s0
+persist.sys.audit_safemode      u:object_r:safemode_prop:s0
+persist.service.        u:object_r:system_prop:s0
+persist.service.bdroid. u:object_r:bluetooth_prop:s0
+persist.security.       u:object_r:system_prop:s0
+persist.vendor.overlay.  u:object_r:overlay_prop:s0
+ro.boot.vendor.overlay.  u:object_r:overlay_prop:s0
+ro.boottime.             u:object_r:boottime_prop:s0
+ro.serialno             u:object_r:serialno_prop:s0
+ro.boot.btmacaddr       u:object_r:bluetooth_prop:s0
+ro.boot.serialno        u:object_r:serialno_prop:s0
+ro.bt.                  u:object_r:bluetooth_prop:s0
+# Boolean property set by system server upon boot indicating
+# if device owner is provisioned.
+ro.device_owner         u:object_r:device_logging_prop:s0
+# selinux non-persistent properties
+selinux.restorecon_recursive   u:object_r:restorecon_prop:s0
+# default property context
+*                       u:object_r:default_prop:s0
+# data partition encryption properties
+vold.                   u:object_r:vold_prop:s0
+ro.crypto.              u:object_r:vold_prop:s0
+# ro.build.fingerprint is either set in /system/build.prop, or is
+# set at runtime by system_server.
+ro.build.fingerprint    u:object_r:fingerprint_prop:s0
+ro.persistent_properties.ready  u:object_r:persistent_properties_ready_prop:s0
+# ctl properties
+ctl.bootanim            u:object_r:ctl_bootanim_prop:s0
+ctl.dumpstate           u:object_r:ctl_dumpstate_prop:s0
+ctl.fuse_               u:object_r:ctl_fuse_prop:s0
+ctl.mdnsd               u:object_r:ctl_mdnsd_prop:s0
+ctl.ril-daemon          u:object_r:ctl_rildaemon_prop:s0
+ctl.bugreport           u:object_r:ctl_bugreport_prop:s0
+ctl.console             u:object_r:ctl_console_prop:s0
+ctl.                    u:object_r:ctl_default_prop:s0
+# NFC properties
+nfc.                    u:object_r:nfc_prop:s0
+# These properties are not normally set by processes other than init.
+# They are only distinguished here for setting by qemu-props on the
+# emulator/goldfish.
+config.                 u:object_r:config_prop:s0
+ro.config.              u:object_r:config_prop:s0
+dalvik.                 u:object_r:dalvik_prop:s0
+ro.dalvik.              u:object_r:dalvik_prop:s0
+# Shared between system server and wificond
+wlan.                   u:object_r:wifi_prop:s0
+# hwservicemanager properties
+hwservicemanager.       u:object_r:hwservicemanager_prop:s0
+# ASAN install trigger
+asan.restore_reboot  u:object_r:asan_reboot_prop:s0)";
+
+static char aosp_s_property_contexts[] = R"(
+net.rmnet               u:object_r:net_radio_prop:s0
+net.gprs                u:object_r:net_radio_prop:s0
+net.ppp                 u:object_r:net_radio_prop:s0
+net.qmi                 u:object_r:net_radio_prop:s0
+net.lte                 u:object_r:net_radio_prop:s0
+net.cdma                u:object_r:net_radio_prop:s0
+net.dns                 u:object_r:net_dns_prop:s0
+ril.                    u:object_r:radio_prop:s0
+ro.ril.                 u:object_r:radio_prop:s0
+gsm.                    u:object_r:radio_prop:s0
+persist.radio           u:object_r:radio_prop:s0
+
+net.                    u:object_r:system_prop:s0
+dev.                    u:object_r:system_prop:s0
+ro.runtime.             u:object_r:system_prop:s0
+ro.runtime.firstboot    u:object_r:firstboot_prop:s0
+hw.                     u:object_r:system_prop:s0
+ro.hw.                  u:object_r:system_prop:s0
+sys.                    u:object_r:system_prop:s0
+sys.audio.              u:object_r:audio_prop:s0
+sys.init.perf_lsm_hooks u:object_r:init_perf_lsm_hooks_prop:s0
+sys.cppreopt            u:object_r:cppreopt_prop:s0
+sys.lpdumpd             u:object_r:lpdumpd_prop:s0
+sys.powerctl            u:object_r:powerctl_prop:s0
+service.                u:object_r:system_prop:s0
+dhcp.                   u:object_r:dhcp_prop:s0
+dhcp.bt-pan.result      u:object_r:pan_result_prop:s0
+bluetooth.              u:object_r:bluetooth_prop:s0
+
+debug.                  u:object_r:debug_prop:s0
+debug.db.               u:object_r:debuggerd_prop:s0
+dumpstate.              u:object_r:dumpstate_prop:s0
+dumpstate.options       u:object_r:dumpstate_options_prop:s0
+init.svc_debug_pid.     u:object_r:init_svc_debug_prop:s0
+llk.                    u:object_r:llkd_prop:s0
+khungtask.              u:object_r:llkd_prop:s0
+ro.llk.                 u:object_r:llkd_prop:s0
+ro.khungtask.           u:object_r:llkd_prop:s0
+log.                    u:object_r:log_prop:s0
+log.tag                 u:object_r:log_tag_prop:s0
+log.tag.WifiHAL         u:object_r:wifi_log_prop:s0
+security.perf_harden    u:object_r:shell_prop:s0
+service.adb.root        u:object_r:shell_prop:s0
+service.adb.tls.port    u:object_r:adbd_prop:s0
+persist.adb.wifi.       u:object_r:adbd_prop:s0
+persist.adb.tls_server.enable  u:object_r:system_adbd_prop:s0
+
+persist.audio.          u:object_r:audio_prop:s0
+persist.bluetooth.      u:object_r:bluetooth_prop:s0
+persist.nfc_cfg.        u:object_r:nfc_prop:s0
+persist.debug.          u:object_r:persist_debug_prop:s0
+logd.                   u:object_r:logd_prop:s0
+persist.logd.           u:object_r:logd_prop:s0
+ro.logd.                u:object_r:logd_prop:s0
+persist.logd.security   u:object_r:device_logging_prop:s0
+persist.logd.logpersistd        u:object_r:logpersistd_logging_prop:s0
+logd.logpersistd        u:object_r:logpersistd_logging_prop:s0
+persist.log.tag         u:object_r:log_tag_prop:s0
+persist.mmc.            u:object_r:mmc_prop:s0
+persist.netd.stable_secret      u:object_r:netd_stable_secret_prop:s0
+persist.pm.mock-upgrade u:object_r:mock_ota_prop:s0
+persist.sys.            u:object_r:system_prop:s0
+persist.sys.safemode    u:object_r:safemode_prop:s0
+persist.sys.theme       u:object_r:theme_prop:s0
+persist.sys.fflag.override.settings_dynamic_system    u:object_r:dynamic_system_prop:s0
+ro.sys.safemode         u:object_r:safemode_prop:s0
+persist.sys.audit_safemode      u:object_r:safemode_prop:s0
+persist.sys.dalvik.jvmtiagent   u:object_r:system_jvmti_agent_prop:s0
+persist.service.        u:object_r:system_prop:s0
+persist.service.bdroid. u:object_r:bluetooth_prop:s0
+persist.security.       u:object_r:system_prop:s0
+persist.traced.enable   u:object_r:traced_enabled_prop:s0
+traced.lazy.            u:object_r:traced_lazy_prop:s0
+persist.heapprofd.enable u:object_r:heapprofd_enabled_prop:s0
+persist.traced_perf.enable u:object_r:traced_perf_enabled_prop:s0
+persist.vendor.overlay.  u:object_r:overlay_prop:s0
+ro.boot.vendor.overlay.  u:object_r:overlay_prop:s0
+ro.boottime.             u:object_r:boottime_prop:s0
+ro.serialno             u:object_r:serialno_prop:s0
+ro.boot.btmacaddr       u:object_r:bluetooth_prop:s0
+ro.boot.serialno        u:object_r:serialno_prop:s0
+ro.bt.                  u:object_r:bluetooth_prop:s0
+ro.boot.bootreason      u:object_r:bootloader_boot_reason_prop:s0
+persist.sys.boot.reason u:object_r:last_boot_reason_prop:s0
+sys.boot.reason         u:object_r:system_boot_reason_prop:s0
+sys.boot.reason.last    u:object_r:last_boot_reason_prop:s0
+pm.                     u:object_r:pm_prop:s0
+test.sys.boot.reason    u:object_r:test_boot_reason_prop:s0
+test.userspace_reboot.requested u:object_r:userspace_reboot_test_prop:s0
+sys.lmk.                u:object_r:system_lmk_prop:s0
+sys.trace.              u:object_r:system_trace_prop:s0
+
+# Fastbootd protocol control property
+fastbootd.protocol    u:object_r:fastbootd_protocol_prop:s0 exact enum usb tcp
+
+# adbd protoctl configuration property
+service.adb.tcp.port    u:object_r:adbd_config_prop:s0 exact int
+
+# Boolean property set by system server upon boot indicating
+# if device is fully owned by organization instead of being
+# a personal device.
+ro.organization_owned   u:object_r:device_logging_prop:s0
+
+# selinux non-persistent properties
+selinux.restorecon_recursive   u:object_r:restorecon_prop:s0
+
+# default property context
+*                       u:object_r:default_prop:s0
+
+# data partition encryption properties
+vold.                   u:object_r:vold_prop:s0
+ro.crypto.              u:object_r:vold_prop:s0
+
+# ro.build.fingerprint is either set in /system/build.prop, or is
+# set at runtime by system_server.
+ro.build.fingerprint    u:object_r:fingerprint_prop:s0 exact string
+
+ro.persistent_properties.ready  u:object_r:persistent_properties_ready_prop:s0
+
+# ctl properties
+ctl.bootanim            u:object_r:ctl_bootanim_prop:s0
+ctl.dumpstate           u:object_r:ctl_dumpstate_prop:s0
+ctl.fuse_               u:object_r:ctl_fuse_prop:s0
+ctl.mdnsd               u:object_r:ctl_mdnsd_prop:s0
+ctl.ril-daemon          u:object_r:ctl_rildaemon_prop:s0
+ctl.bugreport           u:object_r:ctl_bugreport_prop:s0
+ctl.console             u:object_r:ctl_console_prop:s0
+ctl.                    u:object_r:ctl_default_prop:s0
+
+# Don't allow uncontrolled access to all services
+ctl.sigstop_on$         u:object_r:ctl_sigstop_prop:s0
+ctl.sigstop_off$        u:object_r:ctl_sigstop_prop:s0
+ctl.start$              u:object_r:ctl_start_prop:s0
+ctl.stop$               u:object_r:ctl_stop_prop:s0
+ctl.restart$            u:object_r:ctl_restart_prop:s0
+ctl.interface_start$    u:object_r:ctl_interface_start_prop:s0
+ctl.interface_stop$     u:object_r:ctl_interface_stop_prop:s0
+ctl.interface_restart$  u:object_r:ctl_interface_restart_prop:s0
+
+ # Restrict access to starting/stopping adbd
+ctl.start$adbd             u:object_r:ctl_adbd_prop:s0
+ctl.stop$adbd              u:object_r:ctl_adbd_prop:s0
+ctl.restart$adbd           u:object_r:ctl_adbd_prop:s0
+
+# Restrict access to starting/stopping gsid.
+ctl.start$gsid          u:object_r:ctl_gsid_prop:s0
+ctl.stop$gsid           u:object_r:ctl_gsid_prop:s0
+ctl.restart$gsid        u:object_r:ctl_gsid_prop:s0
+
+# Restrict access to stopping apexd.
+ctl.stop$apexd          u:object_r:ctl_apexd_prop:s0
+
+# Restrict access to restart dumpstate
+ctl.interface_restart$android.hardware.dumpstate u:object_r:ctl_dumpstate_prop:s0
+
+# NFC properties
+nfc.                    u:object_r:nfc_prop:s0
+
+# These properties are not normally set by processes other than init.
+# They are only distinguished here for setting by qemu-props on the
+# emulator/goldfish.
+config.                 u:object_r:config_prop:s0
+ro.config.              u:object_r:config_prop:s0
+dalvik.                 u:object_r:dalvik_prop:s0
+ro.dalvik.              u:object_r:dalvik_prop:s0
+
+# Shared between system server and wificond
+wifi.                   u:object_r:wifi_prop:s0
+wlan.                   u:object_r:wifi_prop:s0
+
+# Lowpan properties
+lowpan.                 u:object_r:lowpan_prop:s0
+ro.lowpan.              u:object_r:lowpan_prop:s0
+
+# heapprofd properties
+heapprofd.              u:object_r:heapprofd_prop:s0
+
+# hwservicemanager properties
+hwservicemanager.       u:object_r:hwservicemanager_prop:s0
+
+# Common default properties for vendor, odm, vendor_dlkm, and odm_dlkm.
+init.svc.odm.           u:object_r:vendor_default_prop:s0
+init.svc.vendor.        u:object_r:vendor_default_prop:s0
+ro.hardware.            u:object_r:vendor_default_prop:s0
+ro.odm.                 u:object_r:vendor_default_prop:s0
+ro.vendor.              u:object_r:vendor_default_prop:s0
+ro.vendor_dlkm.         u:object_r:vendor_default_prop:s0
+ro.odm_dlkm.            u:object_r:vendor_default_prop:s0
+odm.                    u:object_r:vendor_default_prop:s0
+persist.odm.            u:object_r:vendor_default_prop:s0
+persist.vendor.         u:object_r:vendor_default_prop:s0
+vendor.                 u:object_r:vendor_default_prop:s0
+
+# Properties that relate to time / time zone detection behavior.
+persist.time.           u:object_r:time_prop:s0
+
+# Properties that relate to server configurable flags
+device_config.reset_performed           u:object_r:device_config_reset_performed_prop:s0
+persist.device_config.activity_manager_native_boot. u:object_r:device_config_activity_manager_native_boot_prop:s0
+persist.device_config.attempted_boot_count        u:object_r:device_config_boot_count_prop:s0
+persist.device_config.input_native_boot. u:object_r:device_config_input_native_boot_prop:s0
+persist.device_config.netd_native.           u:object_r:device_config_netd_native_prop:s0
+persist.device_config.runtime_native.        u:object_r:device_config_runtime_native_prop:s0
+persist.device_config.runtime_native_boot.   u:object_r:device_config_runtime_native_boot_prop:s0
+persist.device_config.media_native.          u:object_r:device_config_media_native_prop:s0
+persist.device_config.storage_native_boot.   u:object_r:device_config_storage_native_boot_prop:s0
+persist.device_config.window_manager_native_boot. u:object_r:device_config_window_manager_native_boot_prop:s0
+persist.device_config.configuration. u:object_r:device_config_configuration_prop:s0
+
+# Properties that relate to legacy server configurable flags
+persist.device_config.global_settings.sys_traced u:object_r:device_config_sys_traced_prop:s0
+
+apexd.                  u:object_r:apexd_prop:s0
+persist.apexd.          u:object_r:apexd_prop:s0
+
+bpf.progs_loaded        u:object_r:bpf_progs_loaded_prop:s0
+
+gsid.                   u:object_r:gsid_prop:s0
+ro.gsid.                u:object_r:gsid_prop:s0
+
+# Property for disabling NNAPI vendor extensions on product image (used on GSI /product image,
+# which can't use NNAPI vendor extensions).
+ro.nnapi.extensions.deny_on_product                u:object_r:nnapi_ext_deny_product_prop:s0
+
+# Property that is set once ueventd finishes cold boot.
+ro.cold_boot_done       u:object_r:cold_boot_done_prop:s0
+
+# Charger properties
+ro.charger.                 u:object_r:charger_prop:s0
+sys.boot_from_charger_mode  u:object_r:charger_status_prop:s0 exact int
+ro.enable_boot_charger_mode u:object_r:charger_config_prop:s0 exact bool
+
+# Virtual A/B properties
+ro.virtual_ab.enabled   u:object_r:virtual_ab_prop:s0
+ro.virtual_ab.retrofit  u:object_r:virtual_ab_prop:s0
+
+ro.product.ab_ota_partitions u:object_r:ota_prop:s0 exact string
+# Property to set/clear the warm reset flag after an OTA update.
+ota.warm_reset  u:object_r:ota_prop:s0
+
+# Module properties
+com.android.sdkext.                  u:object_r:module_sdkextensions_prop:s0
+persist.com.android.sdkext.          u:object_r:module_sdkextensions_prop:s0
+
+# Userspace reboot properties
+sys.userspace_reboot.log.         u:object_r:userspace_reboot_log_prop:s0
+persist.sys.userspace_reboot.log. u:object_r:userspace_reboot_log_prop:s0
+
+# Integer property which is used in libgui to configure the number of frames
+# tracked by buffer queue's frame event timing history. The property is set
+# by devices with video decoding pipelines long enough to overflow the default
+# history size.
+ro.lib_gui.frame_event_history_size u:object_r:bq_config_prop:s0
+
+af.fast_track_multiplier     u:object_r:audio_config_prop:s0 exact int
+ro.af.client_heap_size_kbyte u:object_r:audio_config_prop:s0 exact int
+
+audio.camerasound.force         u:object_r:audio_config_prop:s0 exact bool
+audio.deep_buffer.media         u:object_r:audio_config_prop:s0 exact bool
+audio.offload.video             u:object_r:audio_config_prop:s0 exact bool
+audio.offload.min.duration.secs u:object_r:audio_config_prop:s0 exact int
+
+ro.audio.ignore_effects  u:object_r:audio_config_prop:s0 exact bool
+ro.audio.monitorRotation u:object_r:audio_config_prop:s0 exact bool
+
+persist.config.calibration_fac u:object_r:camera_calibration_prop:s0 exact string
+
+config.disable_cameraservice u:object_r:camera_config_prop:s0 exact bool
+
+camera.disable_zsl_mode u:object_r:camera_config_prop:s0 exact bool
+camera.fifo.disable     u:object_r:camera_config_prop:s0 exact bool
+ro.camera.notify_nfc    u:object_r:camera_config_prop:s0 exact bool
+ro.camera.enableLazyHal u:object_r:camera_config_prop:s0 exact bool
+
+# Should always_debuggable be bool? It's checked against the string "1".
+dalvik.vm.always_debuggable                   u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.appimageformat                      u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.backgroundgctype                    u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.boot-dex2oat-cpu-set                u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.boot-dex2oat-threads                u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.boot-image                          u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.checkjni                            u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.dex2oat-Xms                         u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-Xmx                         u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-cpu-set                     u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-filter                      u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-flags                       u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-max-image-block-size        u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.dex2oat-minidebuginfo               u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.dex2oat-resolve-startup-strings     u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.dex2oat-threads                     u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.dex2oat-updatable-bcp-packages-file u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.dex2oat-very-large                  u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.dex2oat-swap                        u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.dex2oat64.enabled                   u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.dexopt.secondary                    u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.execution-mode                      u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.extra-opts                          u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.foreground-heap-growth-multiplier   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.gctype                              u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heapgrowthlimit                     u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heapmaxfree                         u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heapminfree                         u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heapsize                            u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heapstartsize                       u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.heaptargetutilization               u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.hot-startup-method-samples          u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.image-dex2oat-Xms                   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.image-dex2oat-Xmx                   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.image-dex2oat-cpu-set               u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.image-dex2oat-filter                u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.image-dex2oat-flags                 u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.image-dex2oat-threads               u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.isa.arm.features                    u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.arm.variant                     u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.arm64.features                  u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.arm64.variant                   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.mips.features                   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.mips.variant                    u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.mips64.features                 u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.mips64.variant                  u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.unknown.features                u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.unknown.variant                 u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.x86.features                    u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.x86.variant                     u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.x86_64.features                 u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.isa.x86_64.variant                  u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.jitinitialsize                      u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.jitmaxsize                          u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.jitprithreadweight                  u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.jitthreshold                        u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.jittransitionweight                 u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.jniopts                             u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.lockprof.threshold                  u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.method-trace                        u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.method-trace-file                   u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.method-trace-file-siz               u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.method-trace-stream                 u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.profilesystemserver                 u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.profilebootclasspath                u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.restore-dex2oat-cpu-set             u:object_r:dalvik_config_prop:s0 exact string
+dalvik.vm.restore-dex2oat-threads             u:object_r:dalvik_config_prop:s0 exact int
+dalvik.vm.usejit                              u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.usejitprofiles                      u:object_r:dalvik_config_prop:s0 exact bool
+dalvik.vm.zygote.max-boot-retry               u:object_r:dalvik_config_prop:s0 exact int
+ro.zygote                                     u:object_r:dalvik_config_prop:s0 exact string
+
+persist.sys.dalvik.vm.lib.2 u:object_r:dalvik_runtime_prop:s0 exact string
+
+keyguard.no_require_sim u:object_r:keyguard_config_prop:s0 exact bool
+
+media.recorder.show_manufacturer_and_model   u:object_r:media_config_prop:s0 exact bool
+media.stagefright.cache-params               u:object_r:media_config_prop:s0 exact string
+media.stagefright.thumbnail.prefer_hw_codecs u:object_r:media_config_prop:s0 exact bool
+persist.sys.media.avsync                     u:object_r:media_config_prop:s0 exact bool
+
+persist.bluetooth.a2dp_offload.cap             u:object_r:bluetooth_a2dp_offload_prop:s0 exact string
+persist.bluetooth.a2dp_offload.disabled        u:object_r:bluetooth_a2dp_offload_prop:s0 exact bool
+persist.bluetooth.bluetooth_audio_hal.disabled u:object_r:bluetooth_audio_hal_prop:s0 exact bool
+persist.bluetooth.btsnoopenable                u:object_r:exported_bluetooth_prop:s0 exact bool
+
+persist.radio.multisim.config u:object_r:radio_control_prop:s0 exact string
+
+persist.sys.hdmi.keep_awake              u:object_r:hdmi_config_prop:s0 exact bool
+ro.hdmi.cec_device_types                 u:object_r:hdmi_config_prop:s0 exact string
+ro.hdmi.device_type                      u:object_r:hdmi_config_prop:s0 exact string
+ro.hdmi.wake_on_hotplug                  u:object_r:hdmi_config_prop:s0 exact bool
+ro.hdmi.cec.source.send_standby_on_sleep u:object_r:hdmi_config_prop:s0 exact enum to_tv broadcast none
+
+pm.dexopt.ab-ota                        u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.bg-dexopt                     u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.boot                          u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.disable_bg_dexopt             u:object_r:exported_pm_prop:s0 exact bool
+pm.dexopt.downgrade_after_inactive_days u:object_r:exported_pm_prop:s0 exact int
+pm.dexopt.first-boot                    u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.inactive                      u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.install                       u:object_r:exported_pm_prop:s0 exact string
+pm.dexopt.shared                        u:object_r:exported_pm_prop:s0 exact string
+
+ro.apk_verity.mode u:object_r:apk_verity_prop:s0 exact int
+
+ro.bluetooth.a2dp_offload.supported u:object_r:bluetooth_a2dp_offload_prop:s0 exact bool
+
+ro.boot.vendor.overlay.theme u:object_r:exported_overlay_prop:s0 exact string
+
+ro.bt.bdaddr_path u:object_r:exported_bluetooth_prop:s0 exact string
+
+ro.config.alarm_alert         u:object_r:systemsound_config_prop:s0 exact string
+ro.config.alarm_vol_default   u:object_r:systemsound_config_prop:s0 exact int
+ro.config.alarm_vol_steps     u:object_r:systemsound_config_prop:s0 exact int
+ro.config.media_vol_default   u:object_r:systemsound_config_prop:s0 exact int
+ro.config.media_vol_steps     u:object_r:systemsound_config_prop:s0 exact int
+ro.config.notification_sound  u:object_r:systemsound_config_prop:s0 exact string
+ro.config.ringtone            u:object_r:systemsound_config_prop:s0 exact string
+ro.config.system_vol_default  u:object_r:systemsound_config_prop:s0 exact int
+ro.config.system_vol_steps    u:object_r:systemsound_config_prop:s0 exact int
+ro.config.vc_call_vol_default u:object_r:systemsound_config_prop:s0 exact int
+
+ro.control_privapp_permissions u:object_r:packagemanager_config_prop:s0 exact enum disable enforce log
+ro.cp_system_other_odex        u:object_r:packagemanager_config_prop:s0 exact bool
+
+ro.crypto.allow_encrypt_override                u:object_r:vold_config_prop:s0 exact bool
+ro.crypto.dm_default_key.options_format.version u:object_r:vold_config_prop:s0 exact int
+ro.crypto.fde_algorithm                         u:object_r:vold_config_prop:s0 exact string
+ro.crypto.fde_sector_size                       u:object_r:vold_config_prop:s0 exact int
+ro.crypto.scrypt_params                         u:object_r:vold_config_prop:s0 exact string
+ro.crypto.set_dun                               u:object_r:vold_config_prop:s0 exact bool
+ro.crypto.volume.contents_mode                  u:object_r:vold_config_prop:s0 exact string
+ro.crypto.volume.filenames_mode                 u:object_r:vold_config_prop:s0 exact string
+ro.crypto.volume.metadata.encryption            u:object_r:vold_config_prop:s0 exact string
+ro.crypto.volume.metadata.method                u:object_r:vold_config_prop:s0 exact string
+ro.crypto.volume.options                        u:object_r:vold_config_prop:s0 exact string
+
+ro.dalvik.vm.native.bridge u:object_r:dalvik_config_prop:s0 exact string
+
+external_storage.projid.enabled   u:object_r:storage_config_prop:s0 exact bool
+external_storage.casefold.enabled u:object_r:storage_config_prop:s0 exact bool
+external_storage.sdcardfs.enabled u:object_r:storage_config_prop:s0 exact bool
+
+ro.config.per_app_memcg         u:object_r:lmkd_config_prop:s0 exact bool
+ro.lmk.critical                 u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.critical_upgrade         u:object_r:lmkd_config_prop:s0 exact bool
+ro.lmk.debug                    u:object_r:lmkd_config_prop:s0 exact bool
+ro.lmk.downgrade_pressure       u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.kill_heaviest_task       u:object_r:lmkd_config_prop:s0 exact bool
+ro.lmk.kill_timeout_ms          u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.low                      u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.medium                   u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.psi_partial_stall_ms     u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.psi_complete_stall_ms    u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.swap_free_low_percentage u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.swap_util_max            u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.thrashing_limit          u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.thrashing_limit_decay    u:object_r:lmkd_config_prop:s0 exact int
+ro.lmk.use_minfree_levels       u:object_r:lmkd_config_prop:s0 exact bool
+ro.lmk.upgrade_pressure         u:object_r:lmkd_config_prop:s0 exact int
+lmkd.reinit                     u:object_r:lmkd_prop:s0 exact int
+
+ro.media.xml_variant.codecs             u:object_r:media_variant_prop:s0 exact string
+ro.media.xml_variant.codecs_performance u:object_r:media_variant_prop:s0 exact string
+ro.media.xml_variant.profiles           u:object_r:media_variant_prop:s0 exact string
+
+ro.minui.default_rotation u:object_r:recovery_config_prop:s0 exact string
+ro.minui.overscan_percent u:object_r:recovery_config_prop:s0 exact int
+ro.minui.pixel_format     u:object_r:recovery_config_prop:s0 exact string
+
+ro.oem_unlock_supported u:object_r:oem_unlock_prop:s0 exact int
+
+ro.rebootescrow.device u:object_r:rebootescrow_hal_prop:s0 exact string
+
+ro.storage_manager.enabled u:object_r:storagemanager_config_prop:s0 exact bool
+
+ro.vehicle.hal u:object_r:vehicle_hal_prop:s0 exact string
+
+ro.vendor.build.security_patch u:object_r:vendor_security_patch_level_prop:s0 exact string
+
+ro.zram.mark_idle_delay_mins    u:object_r:zram_config_prop:s0 exact int
+ro.zram.first_wb_delay_mins     u:object_r:zram_config_prop:s0 exact int
+ro.zram.periodic_wb_delay_hours u:object_r:zram_config_prop:s0 exact int
+zram.force_writeback            u:object_r:zram_config_prop:s0 exact bool
+persist.sys.zram_enabled        u:object_r:zram_control_prop:s0 exact bool
+
+sendbug.preferred.domain u:object_r:sendbug_config_prop:s0 exact string
+
+persist.sys.usb.usbradio.config u:object_r:usb_control_prop:s0 exact string
+
+sys.usb.config     u:object_r:usb_control_prop:s0 exact string
+sys.usb.configfs   u:object_r:usb_control_prop:s0 exact int
+sys.usb.controller u:object_r:usb_control_prop:s0 exact string
+sys.usb.state      u:object_r:usb_control_prop:s0 exact string
+
+sys.usb.mtp.device_type u:object_r:usb_config_prop:s0 exact int
+
+sys.usb.config. u:object_r:usb_prop:s0
+
+sys.usb.ffs.aio_compat u:object_r:ffs_config_prop:s0 exact bool
+sys.usb.ffs.max_read   u:object_r:ffs_config_prop:s0 exact int
+sys.usb.ffs.max_write  u:object_r:ffs_config_prop:s0 exact int
+
+sys.usb.ffs.ready     u:object_r:ffs_control_prop:s0 exact bool
+sys.usb.ffs.mtp.ready u:object_r:ffs_control_prop:s0 exact bool
+
+tombstoned.max_tombstone_count u:object_r:tombstone_config_prop:s0 exact int
+
+vold.post_fs_data_done u:object_r:vold_config_prop:s0 exact int
+
+apexd.status u:object_r:apexd_prop:s0 exact enum starting activated ready
+
+dev.bootcomplete   u:object_r:boot_status_prop:s0 exact bool
+sys.boot_completed u:object_r:boot_status_prop:s0 exact bool
+
+persist.sys.device_provisioned u:object_r:provisioned_prop:s0 exact string
+
+persist.sys.theme               u:object_r:theme_prop:s0 exact string
+
+sys.retaildemo.enabled u:object_r:retaildemo_prop:s0 exact int
+
+sys.user.0.ce_available u:object_r:exported3_system_prop:s0 exact bool
+
+aac_drc_boost            u:object_r:aac_drc_prop:s0 exact int
+aac_drc_cut              u:object_r:aac_drc_prop:s0 exact int
+aac_drc_enc_target_level u:object_r:aac_drc_prop:s0 exact int
+aac_drc_heavy            u:object_r:aac_drc_prop:s0 exact int
+aac_drc_reference_level  u:object_r:aac_drc_prop:s0 exact int
+ro.aac_drc_effect_type   u:object_r:aac_drc_prop:s0 exact int
+
+build.version.extensions. u:object_r:module_sdkextensions_prop:s0 prefix int
+
+drm.64bit.enabled            u:object_r:mediadrm_config_prop:s0 exact bool
+media.mediadrmservice.enable u:object_r:mediadrm_config_prop:s0 exact bool
+
+drm.service.enabled u:object_r:drm_service_config_prop:s0 exact bool
+
+dumpstate.dry_run u:object_r:exported_dumpstate_prop:s0 exact bool
+dumpstate.unroot  u:object_r:exported_dumpstate_prop:s0 exact bool
+persist.dumpstate.verbose_logging.enabled u:object_r:hal_dumpstate_config_prop:s0 exact bool
+
+hal.instrumentation.enable u:object_r:hal_instrumentation_prop:s0 exact bool
+
+# default contexts only accessible by coredomain
+init.svc. u:object_r:init_service_status_private_prop:s0 prefix string
+
+# vendor-init-readable init service props
+init.svc.bugreport      u:object_r:init_service_status_prop:s0 exact string
+init.svc.bugreportd     u:object_r:init_service_status_prop:s0 exact string
+init.svc.console        u:object_r:init_service_status_prop:s0 exact string
+init.svc.dumpstatez     u:object_r:init_service_status_prop:s0 exact string
+init.svc.mediadrm       u:object_r:init_service_status_prop:s0 exact string
+init.svc.statsd         u:object_r:init_service_status_prop:s0 exact string
+init.svc.surfaceflinger u:object_r:init_service_status_prop:s0 exact string
+init.svc.tombstoned     u:object_r:init_service_status_prop:s0 exact string
+init.svc.zygote         u:object_r:init_service_status_prop:s0 exact string
+
+libc.debug.malloc.options u:object_r:libc_debug_prop:s0 exact string
+libc.debug.malloc.program u:object_r:libc_debug_prop:s0 exact string
+libc.debug.hooks.enable   u:object_r:libc_debug_prop:s0 exact string
+
+net.redirect_socket_calls.hooked u:object_r:socket_hook_prop:s0 exact bool
+
+persist.sys.locale       u:object_r:exported_system_prop:s0 exact string
+persist.sys.timezone     u:object_r:exported_system_prop:s0 exact string
+persist.sys.test_harness u:object_r:test_harness_prop:s0 exact bool
+
+ro.arch u:object_r:build_prop:s0 exact string
+
+# ro.boot. properties are set based on kernel commandline arguments, which are vendor owned.
+ro.boot.                   u:object_r:bootloader_prop:s0
+ro.boot.avb_version        u:object_r:bootloader_prop:s0 exact string
+ro.boot.baseband           u:object_r:bootloader_prop:s0 exact string
+ro.boot.bootdevice         u:object_r:bootloader_prop:s0 exact string
+ro.boot.bootloader         u:object_r:bootloader_prop:s0 exact string
+ro.boot.boottime           u:object_r:bootloader_prop:s0 exact string
+ro.boot.console            u:object_r:bootloader_prop:s0 exact string
+ro.boot.hardware           u:object_r:bootloader_prop:s0 exact string
+ro.boot.hardware.color     u:object_r:bootloader_prop:s0 exact string
+ro.boot.hardware.sku       u:object_r:bootloader_prop:s0 exact string
+ro.boot.keymaster          u:object_r:bootloader_prop:s0 exact string
+ro.boot.mode               u:object_r:bootloader_prop:s0 exact string
+ro.boot.revision           u:object_r:bootloader_prop:s0 exact string
+ro.boot.vbmeta.avb_version u:object_r:bootloader_prop:s0 exact string
+ro.boot.verifiedbootstate  u:object_r:bootloader_prop:s0 exact string
+ro.boot.veritymode         u:object_r:bootloader_prop:s0 exact string
+
+# These ro.X properties are set to values of ro.boot.X by property_service.
+ro.baseband   u:object_r:bootloader_prop:s0 exact string
+ro.bootloader u:object_r:bootloader_prop:s0 exact string
+ro.bootmode   u:object_r:bootloader_prop:s0 exact string
+ro.hardware   u:object_r:bootloader_prop:s0 exact string
+ro.revision   u:object_r:bootloader_prop:s0 exact string
+
+ro.boot.dynamic_partitions          u:object_r:exported_default_prop:s0 exact string
+ro.boot.dynamic_partitions_retrofit u:object_r:exported_default_prop:s0 exact string
+
+ro.build.date                        u:object_r:build_prop:s0 exact string
+ro.build.date.utc                    u:object_r:build_prop:s0 exact int
+ro.build.description                 u:object_r:build_prop:s0 exact string
+ro.build.display.id                  u:object_r:build_prop:s0 exact string
+ro.build.host                        u:object_r:build_prop:s0 exact string
+ro.build.id                          u:object_r:build_prop:s0 exact string
+ro.build.product                     u:object_r:build_prop:s0 exact string
+ro.build.system_root_image           u:object_r:build_prop:s0 exact bool
+ro.build.tags                        u:object_r:build_prop:s0 exact string
+ro.build.type                        u:object_r:build_prop:s0 exact string
+ro.build.user                        u:object_r:build_prop:s0 exact string
+ro.build.version.base_os             u:object_r:build_prop:s0 exact string
+ro.build.version.codename            u:object_r:build_prop:s0 exact string
+ro.build.version.incremental         u:object_r:build_prop:s0 exact string
+ro.build.version.preview_sdk         u:object_r:build_prop:s0 exact int
+ro.build.version.release             u:object_r:build_prop:s0 exact string
+ro.build.version.release_or_codename u:object_r:build_prop:s0 exact string
+ro.build.version.sdk                 u:object_r:build_prop:s0 exact int
+ro.build.version.security_patch      u:object_r:build_prop:s0 exact string
+
+ro.debuggable u:object_r:build_prop:s0 exact bool
+
+ro.product.cpu.abi       u:object_r:build_prop:s0 exact string
+ro.product.cpu.abilist   u:object_r:build_prop:s0 exact string
+ro.product.cpu.abilist32 u:object_r:build_prop:s0 exact string
+ro.product.cpu.abilist64 u:object_r:build_prop:s0 exact string
+
+ro.adb.secure u:object_r:build_prop:s0 exact bool
+ro.secure     u:object_r:build_prop:s0 exact int
+
+# These 5 properties are set by property_service
+ro.product.brand         u:object_r:build_prop:s0 exact string
+ro.product.device        u:object_r:build_prop:s0 exact string
+ro.product.manufacturer  u:object_r:build_prop:s0 exact string
+ro.product.model         u:object_r:build_prop:s0 exact string
+ro.product.name          u:object_r:build_prop:s0 exact string
+
+# Sanitizer properties
+ro.sanitize.address          u:object_r:build_prop:s0 exact bool
+ro.sanitize.cfi              u:object_r:build_prop:s0 exact bool
+ro.sanitize.default-ub       u:object_r:build_prop:s0 exact bool
+ro.sanitize.fuzzer           u:object_r:build_prop:s0 exact bool
+ro.sanitize.hwaddress        u:object_r:build_prop:s0 exact bool
+ro.sanitize.integer_overflow u:object_r:build_prop:s0 exact bool
+ro.sanitize.safe-stack       u:object_r:build_prop:s0 exact bool
+ro.sanitize.scudo            u:object_r:build_prop:s0 exact bool
+ro.sanitize.thread           u:object_r:build_prop:s0 exact bool
+ro.sanitize.undefined        u:object_r:build_prop:s0 exact bool
+
+# All odm build props are set by /odm/build.prop
+ro.odm.build.date                u:object_r:build_odm_prop:s0 exact string
+ro.odm.build.date.utc            u:object_r:build_odm_prop:s0 exact int
+ro.odm.build.fingerprint         u:object_r:build_odm_prop:s0 exact string
+ro.odm.build.version.incremental u:object_r:build_odm_prop:s0 exact string
+
+ro.product.odm.brand        u:object_r:build_odm_prop:s0 exact string
+ro.product.odm.device       u:object_r:build_odm_prop:s0 exact string
+ro.product.odm.manufacturer u:object_r:build_odm_prop:s0 exact string
+ro.product.odm.model        u:object_r:build_odm_prop:s0 exact string
+ro.product.odm.name         u:object_r:build_odm_prop:s0 exact string
+
+# All vendor_dlkm build props are set by /vendor_dlkm/etc/build.prop
+ro.vendor_dlkm.build.date                u:object_r:build_vendor_prop:s0 exact string
+ro.vendor_dlkm.build.date.utc            u:object_r:build_vendor_prop:s0 exact int
+ro.vendor_dlkm.build.fingerprint         u:object_r:build_vendor_prop:s0 exact string
+ro.vendor_dlkm.build.version.incremental u:object_r:build_vendor_prop:s0 exact string
+
+# All odm_dlkm build props are set by /odm_dlkm/etc/build.prop
+ro.odm_dlkm.build.date                u:object_r:build_vendor_prop:s0 exact string
+ro.odm_dlkm.build.date.utc            u:object_r:build_vendor_prop:s0 exact int
+ro.odm_dlkm.build.fingerprint         u:object_r:build_vendor_prop:s0 exact string
+ro.odm_dlkm.build.version.incremental u:object_r:build_vendor_prop:s0 exact string
+
+# All vendor build props are set by /vendor/build.prop
+ro.vendor.build.date                u:object_r:build_vendor_prop:s0 exact string
+ro.vendor.build.date.utc            u:object_r:build_vendor_prop:s0 exact int
+ro.vendor.build.fingerprint         u:object_r:build_vendor_prop:s0 exact string
+ro.vendor.build.version.incremental u:object_r:build_vendor_prop:s0 exact string
+ro.vendor.build.version.sdk         u:object_r:build_vendor_prop:s0 exact int
+
+ro.product.board               u:object_r:build_vendor_prop:s0 exact string
+ro.product.first_api_level     u:object_r:build_vendor_prop:s0 exact int
+ro.product.vendor.brand        u:object_r:build_vendor_prop:s0 exact string
+ro.product.vendor.device       u:object_r:build_vendor_prop:s0 exact string
+ro.product.vendor.manufacturer u:object_r:build_vendor_prop:s0 exact string
+ro.product.vendor.model        u:object_r:build_vendor_prop:s0 exact string
+ro.product.vendor.name         u:object_r:build_vendor_prop:s0 exact string
+
+ro.crypto.state u:object_r:vold_status_prop:s0 exact enum encrypted unencrypted unsupported
+ro.crypto.type  u:object_r:vold_status_prop:s0 exact enum block file none
+
+ro.property_service.version u:object_r:property_service_version_prop:s0 exact int
+
+ro.vendor.redirect_socket_calls u:object_r:vendor_socket_hook_prop:s0 exact bool
+
+service.bootanim.exit u:object_r:exported_system_prop:s0 exact int
+
+sys.init.userspace_reboot.in_progress u:object_r:userspace_reboot_exported_prop:s0 exact bool
+sys.use_memfd                         u:object_r:use_memfd_prop:s0 exact bool
+
+vold.decrypt u:object_r:vold_status_prop:s0 exact string
+
+aaudio.hw_burst_min_usec     u:object_r:aaudio_config_prop:s0 exact int
+aaudio.minimum_sleep_usec    u:object_r:aaudio_config_prop:s0 exact int
+aaudio.mixer_bursts          u:object_r:aaudio_config_prop:s0 exact int
+aaudio.mmap_exclusive_policy u:object_r:aaudio_config_prop:s0 exact int
+aaudio.mmap_policy           u:object_r:aaudio_config_prop:s0 exact int
+aaudio.wakeup_delay_usec     u:object_r:aaudio_config_prop:s0 exact int
+
+persist.rcs.supported u:object_r:exported_default_prop:s0 exact int
+
+ro.bionic.2nd_arch        u:object_r:cpu_variant_prop:s0 exact string
+ro.bionic.2nd_cpu_variant u:object_r:cpu_variant_prop:s0 exact string
+ro.bionic.arch            u:object_r:cpu_variant_prop:s0 exact string
+ro.bionic.cpu_variant     u:object_r:cpu_variant_prop:s0 exact string
+
+ro.board.platform u:object_r:exported_default_prop:s0 exact string
+
+ro.boot.fake_battery         u:object_r:exported_default_prop:s0 exact int
+ro.boot.fstab_suffix         u:object_r:exported_default_prop:s0 exact string
+ro.boot.hardware.revision    u:object_r:exported_default_prop:s0 exact string
+ro.boot.product.hardware.sku u:object_r:exported_default_prop:s0 exact string
+ro.boot.product.vendor.sku   u:object_r:exported_default_prop:s0 exact string
+ro.boot.slot_suffix          u:object_r:exported_default_prop:s0 exact string
+
+ro.boringcrypto.hwrand u:object_r:exported_default_prop:s0 exact bool
+
+ro.build.ab_update         u:object_r:exported_default_prop:s0 exact string
+ro.build.expect.baseband   u:object_r:exported_default_prop:s0 exact string
+ro.build.expect.bootloader u:object_r:exported_default_prop:s0 exact string
+
+ro.carrier u:object_r:exported_default_prop:s0 exact string
+
+ro.config.low_ram           u:object_r:exported_config_prop:s0 exact bool
+ro.config.vc_call_vol_steps u:object_r:exported_config_prop:s0 exact int
+
+ro.frp.pst u:object_r:exported_default_prop:s0 exact string
+
+ro.hardware.activity_recognition u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio                u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio.a2dp           u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio.hearing_aid    u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio.primary        u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio.usb            u:object_r:exported_default_prop:s0 exact string
+ro.hardware.audio_policy         u:object_r:exported_default_prop:s0 exact string
+ro.hardware.bootctrl             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.camera               u:object_r:exported_default_prop:s0 exact string
+ro.hardware.consumerir           u:object_r:exported_default_prop:s0 exact string
+ro.hardware.context_hub          u:object_r:exported_default_prop:s0 exact string
+ro.hardware.egl                  u:object_r:exported_default_prop:s0 exact string
+ro.hardware.fingerprint          u:object_r:exported_default_prop:s0 exact string
+ro.hardware.flp                  u:object_r:exported_default_prop:s0 exact string
+ro.hardware.gatekeeper           u:object_r:exported_default_prop:s0 exact string
+ro.hardware.gps                  u:object_r:exported_default_prop:s0 exact string
+ro.hardware.gralloc              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.hdmi_cec             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.hwcomposer           u:object_r:exported_default_prop:s0 exact string
+ro.hardware.input                u:object_r:exported_default_prop:s0 exact string
+ro.hardware.keystore             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.keystore_desede      u:object_r:exported_default_prop:s0 exact string
+ro.hardware.lights               u:object_r:exported_default_prop:s0 exact string
+ro.hardware.local_time           u:object_r:exported_default_prop:s0 exact string
+ro.hardware.memtrack             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.nfc                  u:object_r:exported_default_prop:s0 exact string
+ro.hardware.nfc_nci              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.nfc_tag              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.nvram                u:object_r:exported_default_prop:s0 exact string
+ro.hardware.power                u:object_r:exported_default_prop:s0 exact string
+ro.hardware.radio                u:object_r:exported_default_prop:s0 exact string
+ro.hardware.sensors              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.sound_trigger        u:object_r:exported_default_prop:s0 exact string
+ro.hardware.thermal              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.tv_input             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.type                 u:object_r:exported_default_prop:s0 exact string
+ro.hardware.vehicle              u:object_r:exported_default_prop:s0 exact string
+ro.hardware.vibrator             u:object_r:exported_default_prop:s0 exact string
+ro.hardware.virtual_device       u:object_r:exported_default_prop:s0 exact string
+ro.hardware.vulkan               u:object_r:exported_default_prop:s0 exact string
+
+ro.hwui.use_vulkan u:object_r:exported_default_prop:s0 exact bool
+
+ro.kernel.qemu             u:object_r:exported_default_prop:s0 exact bool
+ro.kernel.qemu.            u:object_r:exported_default_prop:s0
+ro.kernel.android.bootanim u:object_r:exported_default_prop:s0 exact int
+ro.kernel.ebpf.supported   u:object_r:exported_default_prop:s0 exact bool
+
+ro.oem.key1 u:object_r:exported_default_prop:s0 exact string
+
+ro.product.vndk.version u:object_r:vndk_prop:s0 exact string
+
+ro.vndk.lite    u:object_r:vndk_prop:s0 exact bool
+ro.vndk.version u:object_r:vndk_prop:s0 exact string
+
+ro.vts.coverage u:object_r:vts_config_prop:s0 exact int
+
+vts.native_server.on u:object_r:vts_status_prop:s0 exact bool
+
+wifi.active.interface     u:object_r:wifi_hal_prop:s0 exact string
+wifi.aware.interface      u:object_r:wifi_hal_prop:s0 exact string
+wifi.concurrent.interface u:object_r:wifi_hal_prop:s0 exact string
+wifi.direct.interface     u:object_r:wifi_hal_prop:s0 exact string
+wifi.interface            u:object_r:wifi_hal_prop:s0 exact string
+wlan.driver.status        u:object_r:wifi_hal_prop:s0 exact enum ok unloaded
+
+ro.boot.wificountrycode u:object_r:wifi_config_prop:s0 exact string
+
+ro.apex.updatable u:object_r:exported_default_prop:s0 exact bool
+
+# Property to enable incremental feature
+ro.incremental.enable      u:object_r:incremental_prop:s0
+
+# Properties to configure userspace reboot.
+init.userspace_reboot.is_supported u:object_r:userspace_reboot_config_prop:s0 exact bool
+init.userspace_reboot.sigkill.timeoutmillis u:object_r:userspace_reboot_config_prop:s0 exact int
+init.userspace_reboot.sigterm.timeoutmillis u:object_r:userspace_reboot_config_prop:s0 exact int
+init.userspace_reboot.started.timeoutmillis u:object_r:userspace_reboot_config_prop:s0 exact int
+init.userspace_reboot.userdata_remount.timeoutmillis u:object_r:userspace_reboot_config_prop:s0 exact int
+init.userspace_reboot.watchdog.timeoutmillis u:object_r:userspace_reboot_config_prop:s0 exact int
+
+sys.shutdown.requested u:object_r:exported_system_prop:s0 exact string
+
+# surfaceflinger properties
+ro.surface_flinger.default_composition_dataspace          u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.default_composition_pixel_format       u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.force_hwc_copy_for_virtual_displays    u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.has_HDR_display                        u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.has_wide_color_display                 u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.max_frame_buffer_acquired_buffers      u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.max_graphics_height                    u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.max_graphics_width                     u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.max_virtual_display_dimension          u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.primary_display_orientation            u:object_r:surfaceflinger_prop:s0 exact enum ORIENTATION_0 ORIENTATION_180 ORIENTATION_270 ORIENTATION_90
+ro.surface_flinger.present_time_offset_from_vsync_ns      u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.running_without_sync_framework         u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.start_graphics_allocator_service       u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.use_color_management                   u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.use_context_priority                   u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.use_vr_flinger                         u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.vsync_event_phase_offset_ns            u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.vsync_sf_event_phase_offset_ns         u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.wcg_composition_dataspace              u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.wcg_composition_pixel_format           u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.display_primary_red                    u:object_r:surfaceflinger_prop:s0 exact string
+ro.surface_flinger.display_primary_green                  u:object_r:surfaceflinger_prop:s0 exact string
+ro.surface_flinger.display_primary_blue                   u:object_r:surfaceflinger_prop:s0 exact string
+ro.surface_flinger.display_primary_white                  u:object_r:surfaceflinger_prop:s0 exact string
+ro.surface_flinger.protected_contents                     u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.set_idle_timer_ms                      u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.set_touch_timer_ms                     u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.set_display_power_timer_ms             u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.support_kernel_idle_timer              u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.use_smart_90_for_video                 u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.use_content_detection_for_refresh_rate u:object_r:surfaceflinger_prop:s0 exact bool
+ro.surface_flinger.color_space_agnostic_dataspace         u:object_r:surfaceflinger_prop:s0 exact int
+ro.surface_flinger.refresh_rate_switching                 u:object_r:surfaceflinger_prop:s0 exact bool
+
+ro.sf.disable_triple_buffer u:object_r:surfaceflinger_prop:s0 exact bool
+ro.sf.lcd_density           u:object_r:surfaceflinger_prop:s0 exact int
+
+persist.sys.sf.color_mode       u:object_r:surfaceflinger_color_prop:s0 exact int
+persist.sys.sf.color_saturation u:object_r:surfaceflinger_color_prop:s0 exact string
+persist.sys.sf.native_mode      u:object_r:surfaceflinger_color_prop:s0 exact int
+
+# Binder cache properties.  These are world-readable
+cache_key.app_inactive                   u:object_r:binder_cache_system_server_prop:s0
+cache_key.is_compat_change_enabled       u:object_r:binder_cache_system_server_prop:s0
+cache_key.get_packages_for_uid           u:object_r:binder_cache_system_server_prop:s0
+cache_key.has_system_feature             u:object_r:binder_cache_system_server_prop:s0
+cache_key.is_interactive                 u:object_r:binder_cache_system_server_prop:s0
+cache_key.is_power_save_mode             u:object_r:binder_cache_system_server_prop:s0
+cache_key.is_user_unlocked               u:object_r:binder_cache_system_server_prop:s0
+cache_key.volume_list                    u:object_r:binder_cache_system_server_prop:s0
+cache_key.display_info                   u:object_r:binder_cache_system_server_prop:s0
+cache_key.location_enabled               u:object_r:binder_cache_system_server_prop:s0
+cache_key.package_info                   u:object_r:binder_cache_system_server_prop:s0
+
+cache_key.bluetooth.                     u:object_r:binder_cache_bluetooth_server_prop:s0 prefix string
+cache_key.system_server.                 u:object_r:binder_cache_system_server_prop:s0 prefix string
+cache_key.telephony.                     u:object_r:binder_cache_telephony_server_prop:s0 prefix string
+
+gsm.sim.operator.numeric       u:object_r:telephony_status_prop:s0 exact string
+persist.radio.airplane_mode_on u:object_r:telephony_status_prop:s0 exact bool
+
+ro.com.android.dataroaming        u:object_r:telephony_config_prop:s0 exact bool
+ro.com.android.prov_mobiledata    u:object_r:telephony_config_prop:s0 exact bool
+ro.radio.noril                    u:object_r:telephony_config_prop:s0 exact string
+ro.telephony.call_ring.multiple   u:object_r:telephony_config_prop:s0 exact bool
+ro.telephony.default_cdma_sub     u:object_r:telephony_config_prop:s0 exact int
+ro.telephony.default_network      u:object_r:telephony_config_prop:s0 exact string
+ro.telephony.iwlan_operation_mode u:object_r:telephony_config_prop:s0 exact enum default legacy AP-assisted
+telephony.active_modems.max_count u:object_r:telephony_config_prop:s0 exact int
+telephony.lteOnCdmaDevice         u:object_r:telephony_config_prop:s0 exact int
+persist.dbg.volte_avail_ovr       u:object_r:telephony_config_prop:s0 exact int
+persist.dbg.vt_avail_ovr          u:object_r:telephony_config_prop:s0 exact int
+persist.dbg.wfc_avail_ovr         u:object_r:telephony_config_prop:s0 exact int
+
+# System locale list filter configuration
+ro.localization.locale_filter u:object_r:localization_prop:s0 exact string
+
+# Graphics related properties
+ro.opengles.version u:object_r:graphics_config_prop:s0 exact int
+
+ro.gfx.driver.0        u:object_r:graphics_config_prop:s0 exact string
+ro.gfx.driver.1        u:object_r:graphics_config_prop:s0 exact string
+ro.gfx.angle.supported u:object_r:graphics_config_prop:s0 exact bool
+
+graphics.gpu.profiler.support          u:object_r:graphics_config_prop:s0 exact bool
+graphics.gpu.profiler.vulkan_layer_apk u:object_r:graphics_config_prop:s0 exact string
+    )";
diff --git a/libc/system_properties/contexts_split.cpp b/libc/system_properties/contexts_split.cpp
index ccb5bcd..f71d70a 100644
--- a/libc/system_properties/contexts_split.cpp
+++ b/libc/system_properties/contexts_split.cpp
@@ -324,10 +324,16 @@
   return true;
 }
 
-prop_area* ContextsSplit::GetPropAreaForName(const char* name) {
+PrefixNode* ContextsSplit::GetPrefixNodeForName(const char* name) {
   auto entry = ListFind(prefixes_, [name](PrefixNode* l) {
     return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
   });
+
+  return entry;
+}
+
+prop_area* ContextsSplit::GetPropAreaForName(const char* name) {
+  auto entry = GetPrefixNodeForName(name);
   if (!entry) {
     return nullptr;
   }
diff --git a/libc/system_properties/include/system_properties/contexts_split.h b/libc/system_properties/include/system_properties/contexts_split.h
index acb18e3..1d954cc 100644
--- a/libc/system_properties/include/system_properties/contexts_split.h
+++ b/libc/system_properties/include/system_properties/contexts_split.h
@@ -47,7 +47,9 @@
   virtual void ResetAccess() override;
   virtual void FreeAndUnmap() override;
 
- private:
+  PrefixNode* GetPrefixNodeForName(const char* name);
+
+ protected:
   bool MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed);
   bool InitializePropertiesFromFile(const char* filename);
   bool InitializeProperties();
diff --git a/libc/system_properties/include/system_properties/prop_trace.h b/libc/system_properties/include/system_properties/prop_trace.h
new file mode 100644
index 0000000..7c65a6d
--- /dev/null
+++ b/libc/system_properties/include/system_properties/prop_trace.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include "platform/bionic/macros.h"
+
+#include "prop_info.h"
+
+// Tracing class for sysprop. To begin a trace at a specified point:
+//   SyspropTrace trace ("prop_name", "prop_value");
+// The trace will end when the constructor goes out of scope.
+// For read-only properties (ro.*), also need to pass prop_info struct.
+
+enum class PropertyAction {
+  kPropertyFind = 0,
+  kPropertySet,
+  kPropertyGetReadOnly,
+  kPropertyGetReadWrite,
+};
+
+class __LIBC_HIDDEN__ SyspropTrace {
+ public:
+  explicit SyspropTrace(const char* prop_name, const char* prop_value, const prop_info* pi,
+                        PropertyAction action);
+  ~SyspropTrace();
+
+ private:
+  const char* prop_name_;
+  const char* prop_value_;
+  const prop_info* prop_info_;
+  PropertyAction prop_action_;
+  bool output_trace_;
+
+  BIONIC_DISALLOW_COPY_AND_ASSIGN(SyspropTrace);
+};
diff --git a/libc/system_properties/prop_trace.cpp b/libc/system_properties/prop_trace.cpp
new file mode 100644
index 0000000..ac7ff94
--- /dev/null
+++ b/libc/system_properties/prop_trace.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 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 "system_properties/prop_trace.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/CachedProperty.h"
+#include "private/bionic_lock.h"
+#include "private/bionic_systrace.h"
+
+#include <async_safe/log.h>
+#include <cutils/trace.h>  // For ATRACE_TAG_SYSPROP.
+
+#define PROP_TRACE_MSG_LENGTH 1024
+
+static bool should_trace_prop(const char* prop_name) {
+  // Should not trace kTraceTagsProp to avoid infinite recursion.
+  // Because the following g_trace_enable_flags.Get() will get the property value
+  // of kTraceTagsProp again, which in turn invokes should_trace_prop() here.
+  if (prop_name == nullptr || !strcmp(prop_name, kTraceTagsProp)) {
+    return false;
+  }
+
+  return should_trace(ATRACE_TAG_SYSPROP);
+}
+
+static void sysprop_trace_end() {
+  int trace_marker_fd = get_trace_marker_fd();
+  if (trace_marker_fd == -1) {
+    return;
+  }
+
+  TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2));
+}
+
+static void get_sysprop_trace_end(const prop_info* pi, const char* prop_value,
+                                  bool read_only = false) {
+  const char* output_value;
+  char message[PROP_TRACE_MSG_LENGTH];
+
+  if (read_only) {
+    if (pi->is_long()) {
+      output_value = pi->long_value();
+    } else {
+      output_value = pi->value;
+    }
+  } else {
+    output_value = prop_value;
+  }
+
+  snprintf(message, sizeof(message), "prop_get: %s, value: %s", pi->name,
+           output_value ? output_value : "null_value");
+  output_trace(message, 'E');  // 'E' for end.
+}
+
+SyspropTrace::SyspropTrace(const char* prop_name, const char* prop_value, const prop_info* pi,
+                           PropertyAction action)
+    : prop_name_(prop_name),
+      prop_value_(prop_value),
+      prop_info_(pi),
+      prop_action_(action),
+      output_trace_(false) {
+  if (!should_trace_prop(prop_name)) {
+    return;
+  }
+
+  char message[PROP_TRACE_MSG_LENGTH];
+  if (prop_action_ == PropertyAction::kPropertyFind) {
+    snprintf(message, sizeof(message), "prop_find: %s", prop_name_);
+  } else if (prop_action_ == PropertyAction::kPropertySet) {
+    snprintf(message, sizeof(message), "prop_set: %s, value: %s", prop_name_,
+             prop_value_ ? prop_value_ : "null_value");
+  } else {
+    // For property get, the prop_value_ will be resolved then printed in the destructor.
+    snprintf(message, sizeof(message), "prop_get: %s", prop_name_);
+  }
+
+  output_trace(message, 'B');  // 'B' for begin.
+  output_trace_ = true;
+}
+
+SyspropTrace::~SyspropTrace() {
+  if (!output_trace_) {
+    return;
+  }
+  if (prop_action_ == PropertyAction::kPropertyFind ||
+      prop_action_ == PropertyAction::kPropertySet) {
+    sysprop_trace_end();
+  } else if (prop_action_ == PropertyAction::kPropertyGetReadOnly) {
+    get_sysprop_trace_end(prop_info_, prop_value_, true /* read_only */);
+  } else if (prop_action_ == PropertyAction::kPropertyGetReadWrite) {
+    get_sysprop_trace_end(prop_info_, prop_value_, false /* read_only */);
+  }
+  output_trace_ = false;
+}
diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp
index 8404778..3fd20b7 100644
--- a/libc/system_properties/system_properties.cpp
+++ b/libc/system_properties/system_properties.cpp
@@ -46,6 +46,7 @@
 #include "system_properties/context_node.h"
 #include "system_properties/prop_area.h"
 #include "system_properties/prop_info.h"
+#include "system_properties/prop_trace.h"
 
 #define SERIAL_DIRTY(serial) ((serial)&1)
 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
@@ -127,6 +128,9 @@
     return nullptr;
   }
 
+  SyspropTrace trace(name, nullptr /* prop_value */, nullptr /* prop_info */,
+                     PropertyAction::kPropertyFind);
+
   prop_area* pa = contexts_->GetPropAreaForName(name);
   if (!pa) {
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
@@ -201,6 +205,10 @@
   // Read only properties don't need to copy the value to a temporary buffer, since it can never
   // change.  We use relaxed memory order on the serial load for the same reason.
   if (is_read_only(pi->name)) {
+    // The 2nd argument is not required for read-only property tracing, as the
+    // value can be obtained via pi->value or pi->long_value().
+    SyspropTrace trace(pi->name, nullptr /* prop_value */, pi /* prop_info */,
+                       PropertyAction::kPropertyGetReadOnly);
     uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
     if (pi->is_long()) {
       callback(cookie, pi->name, pi->long_value(), serial);
@@ -211,6 +219,8 @@
   }
 
   char value_buf[PROP_VALUE_MAX];
+  SyspropTrace trace(pi->name, value_buf, pi /* prop_info */,
+                     PropertyAction::kPropertyGetReadWrite);
   uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
   callback(cookie, pi->name, value_buf, serial);
 }
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 41eaa9b..7e8e234 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -95,9 +95,22 @@
     int century;
     int relyear;
 };
+
+static char gmt[] = { "GMT" };
+static char utc[] = { "UTC" };
+/* RFC-822/RFC-2822 */
+static const char * const nast[5] = {
+       "EST",    "CST",    "MST",    "PST",    "\0\0\0"
+};
+static const char * const nadt[5] = {
+       "EDT",    "CDT",    "MDT",    "PDT",    "\0\0\0"
+};
+
 static  int _conv_num(const unsigned char **, int *, int, int);
 static  unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
         struct century_relyear *);
+static	const u_char *_find_string(const u_char *, int *, const char * const *,
+	    const char * const *, int);
 
 
 char *
@@ -113,9 +126,10 @@
 _strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
 {
     unsigned char c;
-    const unsigned char *bp;
+    const unsigned char *bp, *ep;
     size_t len = 0;
-    int alt_format, i;
+    int alt_format, i, offs;
+    int neg = 0;
 
     bp = (unsigned char *)buf;
     while ((c = *fmt) != '\0') {
@@ -432,6 +446,108 @@
                 return (NULL);
             break;
 
+		case 'Z':
+			tzset();
+			if (strncmp((const char *)bp, gmt, 3) == 0) {
+				tm->tm_isdst = 0;
+				tm->tm_gmtoff = 0;
+				tm->tm_zone = gmt;
+				bp += 3;
+			} else if (strncmp((const char *)bp, utc, 3) == 0) {
+				tm->tm_isdst = 0;
+				tm->tm_gmtoff = 0;
+				tm->tm_zone = utc;
+				bp += 3;
+			} else {
+				ep = _find_string(bp, &i,
+						 (const char * const *)tzname,
+						  NULL, 2);
+				if (ep == NULL)
+					return (NULL);
+
+				tm->tm_isdst = i;
+				tm->tm_gmtoff = -(timezone);
+				tm->tm_zone = tzname[i];
+				bp = ep;
+			}
+			continue;
+
+		case 'z':
+			/*
+			 * We recognize all ISO 8601 formats:
+			 * Z	= Zulu time/UTC
+			 * [+-]hhmm
+			 * [+-]hh:mm
+			 * [+-]hh
+			 * We recognize all RFC-822/RFC-2822 formats:
+			 * UT|GMT
+			 *          North American : UTC offsets
+			 * E[DS]T = Eastern : -4 | -5
+			 * C[DS]T = Central : -5 | -6
+			 * M[DS]T = Mountain: -6 | -7
+			 * P[DS]T = Pacific : -7 | -8
+			 */
+			while (isspace(*bp))
+				bp++;
+
+			switch (*bp++) {
+			case 'G':
+				if (*bp++ != 'M')
+					return NULL;
+				/*FALLTHROUGH*/
+			case 'U':
+				if (*bp++ != 'T')
+					return NULL;
+				/*FALLTHROUGH*/
+			case 'Z':
+				tm->tm_isdst = 0;
+				tm->tm_gmtoff = 0;
+				tm->tm_zone = utc;
+				continue;
+			case '+':
+				neg = 0;
+				break;
+			case '-':
+				neg = 1;
+				break;
+			default:
+				--bp;
+				ep = _find_string(bp, &i, nast, NULL, 4);
+				if (ep != NULL) {
+					tm->tm_gmtoff = (-5 - i) * SECSPERHOUR;
+					tm->tm_zone = (char *)nast[i];
+					bp = ep;
+					continue;
+				}
+				ep = _find_string(bp, &i, nadt, NULL, 4);
+				if (ep != NULL) {
+					tm->tm_isdst = 1;
+					tm->tm_gmtoff = (-4 - i) * SECSPERHOUR;
+					tm->tm_zone = (char *)nadt[i];
+					bp = ep;
+					continue;
+				}
+				return NULL;
+			}
+			if (!isdigit(bp[0]) || !isdigit(bp[1]))
+				return NULL;
+			offs = ((bp[0]-'0') * 10 + (bp[1]-'0')) * SECSPERHOUR;
+			bp += 2;
+			if (*bp == ':')
+				bp++;
+			if (isdigit(*bp)) {
+				offs += (*bp++ - '0') * 10 * SECSPERMIN;
+				if (!isdigit(*bp))
+					return NULL;
+				offs += (*bp++ - '0') * SECSPERMIN;
+			}
+			if (neg)
+				offs = -offs;
+			tm->tm_isdst = 0;	/* XXX */
+			tm->tm_gmtoff = offs;
+			tm->tm_zone = NULL;	/* XXX */
+			continue;
+
         /*
          * Miscellaneous conversions.
          */
@@ -468,28 +584,49 @@
     return (unsigned char*)bp;
 }
 
-
 static int
 _conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
 {
-    int result = 0;
-    int rulim = ulim;
+	int result = 0;
+	int rulim = ulim;
 
-    if (**buf < '0' || **buf > '9')
-        return (0);
+	if (**buf < '0' || **buf > '9')
+		return (0);
 
-    /* we use rulim to break out of the loop when we run out of digits */
-    do {
-        result *= 10;
-        result += *(*buf)++ - '0';
-        rulim /= 10;
-    } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
+	/* we use rulim to break out of the loop when we run out of digits */
+	do {
+		result *= 10;
+		result += *(*buf)++ - '0';
+		rulim /= 10;
+	} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
 
-    if (result < llim || result > ulim)
-        return (0);
+	if (result < llim || result > ulim)
+		return (0);
 
-    *dest = result;
-    return (1);
+	*dest = result;
+	return (1);
+}
+
+static const u_char *
+_find_string(const u_char *bp, int *tgt, const char * const *n1,
+		const char * const *n2, int c)
+{
+	int i;
+	unsigned int len;
+
+	/* check full name - then abbreviated ones */
+	for (; n1 != NULL; n1 = n2, n2 = NULL) {
+		for (i = 0; i < c; i++, n1++) {
+			len = strlen(*n1);
+			if (strncasecmp(*n1, (const char *)bp, len) == 0) {
+				*tgt = i;
+				return bp + len;
+			}
+		}
+	}
+
+	/* Nothing matched */
+	return NULL;
 }
 
 char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t l) {
diff --git a/libm/x86/e_acos.S b/libm/x86/e_acos.S
index fa61853..04b1787 100644
--- a/libm/x86/e_acos.S
+++ b/libm/x86/e_acos.S
@@ -1925,5 +1925,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,6112
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_asin.S b/libm/x86/e_asin.S
index 5d7f331..6a3ff8e 100644
--- a/libm/x86/e_asin.S
+++ b/libm/x86/e_asin.S
@@ -1999,5 +1999,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,6096
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_atan2.S b/libm/x86/e_atan2.S
index 1efdf65..e491396 100644
--- a/libm/x86/e_atan2.S
+++ b/libm/x86/e_atan2.S
@@ -1217,5 +1217,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,3024
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_cosh.S b/libm/x86/e_cosh.S
index ecea8f4..567a9d0 100644
--- a/libm/x86/e_cosh.S
+++ b/libm/x86/e_cosh.S
@@ -1345,5 +1345,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,4256
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_hypot.S b/libm/x86/e_hypot.S
index 6a143e5..8422024 100644
--- a/libm/x86/e_hypot.S
+++ b/libm/x86/e_hypot.S
@@ -216,5 +216,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,32
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_log10.S b/libm/x86/e_log10.S
index 09b2952..473cea3 100644
--- a/libm/x86/e_log10.S
+++ b/libm/x86/e_log10.S
@@ -791,5 +791,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,2160
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/e_sinh.S b/libm/x86/e_sinh.S
index d6b04b5..b9a2930 100644
--- a/libm/x86/e_sinh.S
+++ b/libm/x86/e_sinh.S
@@ -1403,5 +1403,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,4280
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/libm_reduce_pi04l.S b/libm/x86/libm_reduce_pi04l.S
index af6a7d0..25976ea 100644
--- a/libm/x86/libm_reduce_pi04l.S
+++ b/libm/x86/libm_reduce_pi04l.S
@@ -3714,5 +3714,5 @@
 	.type	__4onpi_31l,@object
 	.size	__4onpi_31l,6444
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/libm_sincos_huge.S b/libm/x86/libm_sincos_huge.S
index b43d193..4601b87 100644
--- a/libm/x86/libm_sincos_huge.S
+++ b/libm/x86/libm_sincos_huge.S
@@ -664,5 +664,5 @@
 	.size	_ones,16
 	.data
 	.hidden __libm_reduce_pi04l
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/libm_tancot_huge.S b/libm/x86/libm_tancot_huge.S
index 80f16d5..cdaa820 100644
--- a/libm/x86/libm_tancot_huge.S
+++ b/libm/x86/libm_tancot_huge.S
@@ -746,5 +746,5 @@
 	.size	_GP,144
 	.data
 	.hidden __libm_reduce_pi04l
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_atan.S b/libm/x86/s_atan.S
index c4413f1..71ca4db 100644
--- a/libm/x86/s_atan.S
+++ b/libm/x86/s_atan.S
@@ -930,5 +930,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,2704
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_cbrt.S b/libm/x86/s_cbrt.S
index 0c98c99..53d3cc2 100644
--- a/libm/x86/s_cbrt.S
+++ b/libm/x86/s_cbrt.S
@@ -734,5 +734,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,2000
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_cos.S b/libm/x86/s_cos.S
index fd5ef5d..e47c63e 100644
--- a/libm/x86/s_cos.S
+++ b/libm/x86/s_cos.S
@@ -888,5 +888,5 @@
 	.size	static_const_table,2256
 	.data
 	.hidden __libm_sincos_huge
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_expm1.S b/libm/x86/s_expm1.S
index 1f9e87b..1816f59 100644
--- a/libm/x86/s_expm1.S
+++ b/libm/x86/s_expm1.S
@@ -698,5 +698,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,1296
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_log1p.S b/libm/x86/s_log1p.S
index 7a6d845..de7b87b 100644
--- a/libm/x86/s_log1p.S
+++ b/libm/x86/s_log1p.S
@@ -823,5 +823,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,2192
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_sin.S b/libm/x86/s_sin.S
index 1e6cbd4..74d1b86 100644
--- a/libm/x86/s_sin.S
+++ b/libm/x86/s_sin.S
@@ -903,5 +903,5 @@
 	.size	static_const_table,2288
 	.data
 	.hidden __libm_sincos_huge
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_tan.S b/libm/x86/s_tan.S
index 3ee2107..7935efe 100644
--- a/libm/x86/s_tan.S
+++ b/libm/x86/s_tan.S
@@ -1762,5 +1762,5 @@
 	.size	static_const_table,5872
 	.data
 	.hidden __libm_tancot_huge
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86/s_tanh.S b/libm/x86/s_tanh.S
index 737bcbb..777519f 100644
--- a/libm/x86/s_tanh.S
+++ b/libm/x86/s_tanh.S
@@ -1357,5 +1357,5 @@
 	.type	static_const_table,@object
 	.size	static_const_table,4280
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 # End
diff --git a/libm/x86_64/e_acos.S b/libm/x86_64/e_acos.S
index d83c66b..57c910e 100644
--- a/libm/x86_64/e_acos.S
+++ b/libm/x86_64/e_acos.S
@@ -1934,7 +1934,7 @@
 	.type	ONE_BY_2,@object
 	.size	ONE_BY_2,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_asin.S b/libm/x86_64/e_asin.S
index 9f41c7c..4242543 100644
--- a/libm/x86_64/e_asin.S
+++ b/libm/x86_64/e_asin.S
@@ -2013,7 +2013,7 @@
 	.type	cv,@object
 	.size	cv,24
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_atan2.S b/libm/x86_64/e_atan2.S
index f9baea9..f0ba43c 100644
--- a/libm/x86_64/e_atan2.S
+++ b/libm/x86_64/e_atan2.S
@@ -1219,7 +1219,7 @@
 	.type	EXPMASK,@object
 	.size	EXPMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_cosh.S b/libm/x86_64/e_cosh.S
index 8cdbca6..97cb389 100644
--- a/libm/x86_64/e_cosh.S
+++ b/libm/x86_64/e_cosh.S
@@ -1349,7 +1349,7 @@
 	.type	ONEMASK,@object
 	.size	ONEMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_hypot.S b/libm/x86_64/e_hypot.S
index 089b2b4..e46669f 100644
--- a/libm/x86_64/e_hypot.S
+++ b/libm/x86_64/e_hypot.S
@@ -191,7 +191,7 @@
 	.type	static_const_table,@object
 	.size	static_const_table,32
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_log10.S b/libm/x86_64/e_log10.S
index 4f43a36..86f86ce 100644
--- a/libm/x86_64/e_log10.S
+++ b/libm/x86_64/e_log10.S
@@ -784,7 +784,7 @@
 	.type	coeff,@object
 	.size	coeff,48
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/e_sinh.S b/libm/x86_64/e_sinh.S
index 4d8db63..d5f7b16 100644
--- a/libm/x86_64/e_sinh.S
+++ b/libm/x86_64/e_sinh.S
@@ -1407,7 +1407,7 @@
 	.type	HALFMASK,@object
 	.size	HALFMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_atan.S b/libm/x86_64/s_atan.S
index 2453e10..d0e5d72 100644
--- a/libm/x86_64/s_atan.S
+++ b/libm/x86_64/s_atan.S
@@ -904,7 +904,7 @@
 	.type	SGNMASK,@object
 	.size	SGNMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_cbrt.S b/libm/x86_64/s_cbrt.S
index 4aa4373..6b00f56 100644
--- a/libm/x86_64/s_cbrt.S
+++ b/libm/x86_64/s_cbrt.S
@@ -731,7 +731,7 @@
 	.type	NEG_INF,@object
 	.size	NEG_INF,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_cos.S b/libm/x86_64/s_cos.S
index ab5a0e1..3d9e402 100644
--- a/libm/x86_64/s_cos.S
+++ b/libm/x86_64/s_cos.S
@@ -1248,7 +1248,7 @@
 	.type	NEG_ZERO,@object
 	.size	NEG_ZERO,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_expm1.S b/libm/x86_64/s_expm1.S
index 9da1d9d..4b22f5a 100644
--- a/libm/x86_64/s_expm1.S
+++ b/libm/x86_64/s_expm1.S
@@ -704,7 +704,7 @@
 	.type	HIGHMASK,@object
 	.size	HIGHMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_log1p.S b/libm/x86_64/s_log1p.S
index 1ff2d39..27fab74 100644
--- a/libm/x86_64/s_log1p.S
+++ b/libm/x86_64/s_log1p.S
@@ -806,7 +806,7 @@
 	.type	coeff2,@object
 	.size	coeff2,48
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_sin.S b/libm/x86_64/s_sin.S
index 2f93a34..fb54a2a 100644
--- a/libm/x86_64/s_sin.S
+++ b/libm/x86_64/s_sin.S
@@ -1273,7 +1273,7 @@
 	.type	NEG_ZERO,@object
 	.size	NEG_ZERO,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_tan.S b/libm/x86_64/s_tan.S
index 74cb044..4fa12e3 100644
--- a/libm/x86_64/s_tan.S
+++ b/libm/x86_64/s_tan.S
@@ -2212,7 +2212,7 @@
 	.type	NEG_ZERO,@object
 	.size	NEG_ZERO,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/libm/x86_64/s_tanh.S b/libm/x86_64/s_tanh.S
index 2c8f9bf..a76a5c2 100644
--- a/libm/x86_64/s_tanh.S
+++ b/libm/x86_64/s_tanh.S
@@ -1369,7 +1369,7 @@
 	.type	TWOMASK,@object
 	.size	TWOMASK,8
 	.data
-	.section .note.GNU-stack, ""
+	.section .note.GNU-stack, "",@progbits
 // -- Begin DWARF2 SEGMENT .eh_frame
 	.section .eh_frame,"a",@progbits
 .eh_frame_seg:
diff --git a/linker/Android.bp b/linker/Android.bp
index 08b2c7b..a51b73f 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -39,6 +39,9 @@
         "linker_wrapper.cpp",
     ],
     arch: {
+        arm64: {
+            srcs: ["arch/arm64/begin.S"],
+        },
         x86_64: {
             srcs: ["arch/x86_64/begin.S"],
         },
diff --git a/linker/linker_tls.cpp b/linker/linker_tls.cpp
index d2edbb3..97892f4 100644
--- a/linker/linker_tls.cpp
+++ b/linker/linker_tls.cpp
@@ -128,6 +128,8 @@
 void linker_finalize_static_tls() {
   g_static_tls_finished = true;
   __libc_shared_globals()->static_tls_layout.finish_layout();
+  TlsModules& modules = __libc_shared_globals()->tls_modules;
+  modules.static_module_count = modules.module_count;
 }
 
 void register_soinfo_tls(soinfo* si) {
diff --git a/tests/Android.bp b/tests/Android.bp
index 7e6e742..8760256 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -44,6 +44,7 @@
         // For glibc.
         "-D__STDC_LIMIT_MACROS",
     ],
+    header_libs: ["libcutils_headers"],
     // Ensure that the tests exercise shadow call stack support and
     // the hint space PAC/BTI instructions.
     arch: {
@@ -422,6 +423,7 @@
         "sys_uio_test.cpp",
         "sys_un_test.cpp",
         "sys_vfs_test.cpp",
+        "sys_wait_test.cpp",
         "sys_xattr_test.cpp",
         "system_properties_test.cpp",
         "system_properties_test2.cpp",
diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp
index 378aea4..56929d1 100644
--- a/tests/dirent_test.cpp
+++ b/tests/dirent_test.cpp
@@ -113,6 +113,18 @@
   ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64);
 }
 
+static int is_version_filter(const dirent* de) {
+  return !strcmp(de->d_name, "version");
+}
+
+TEST(dirent, scandir_filter) {
+  dirent** entries;
+  errno = 0;
+  ASSERT_EQ(1, scandir("/proc", &entries, is_version_filter, nullptr));
+  ASSERT_STREQ("version", entries[0]->d_name);
+  free(entries);
+}
+
 TEST(dirent, scandir_ENOENT) {
   dirent** entries;
   errno = 0;
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 6907abe..3ca0223 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -204,8 +204,9 @@
   foo myfoo;
   volatile int asize = sizeof(myfoo.a) + 1;
   memcpy(myfoo.a, "0123456789", sizeof(myfoo.a));
-  ASSERT_FORTIFY(printf("%s", memchr(myfoo.a, 'a', asize)));
-  ASSERT_FORTIFY(printf("%s", memchr(static_cast<const void*>(myfoo.a), 'a', asize)));
+  ASSERT_FORTIFY(printf("%s", static_cast<const char*>(memchr(myfoo.a, 'a', asize))));
+  ASSERT_FORTIFY(printf(
+      "%s", static_cast<const char*>(memchr(static_cast<const void*>(myfoo.a), 'a', asize))));
 #else // __BIONIC__
   GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
@@ -216,8 +217,9 @@
   foo myfoo;
   volatile int asize = sizeof(myfoo.a) + 1;
   memcpy(myfoo.a, "0123456789", sizeof(myfoo.a));
-  ASSERT_FORTIFY(printf("%s", memrchr(myfoo.a, 'a', asize)));
-  ASSERT_FORTIFY(printf("%s", memrchr(static_cast<const void*>(myfoo.a), 'a', asize)));
+  ASSERT_FORTIFY(printf("%s", static_cast<const char*>(memrchr(myfoo.a, 'a', asize))));
+  ASSERT_FORTIFY(printf(
+      "%s", static_cast<const char*>(memrchr(static_cast<const void*>(myfoo.a), 'a', asize))));
 #else // __BIONIC__
   GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 99117e4..bf65720 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -820,6 +820,24 @@
 #endif
 }
 
+TEST(grp, getgrouplist) {
+#if defined(__BIONIC__)
+  // Query the number of groups.
+  int ngroups = 0;
+  ASSERT_EQ(-1, getgrouplist("root", 123, nullptr, &ngroups));
+  ASSERT_EQ(1, ngroups);
+
+  // Query the specific groups (just the one you pass in on Android).
+  ngroups = 8;
+  gid_t groups[ngroups];
+  ASSERT_EQ(1, getgrouplist("root", 123, groups, &ngroups));
+  ASSERT_EQ(1, ngroups);
+  ASSERT_EQ(123u, groups[0]);
+#else
+  GTEST_SKIP() << "bionic-only test (groups too unpredictable)";
+#endif
+}
+
 #if defined(__BIONIC__)
 static void TestAidNamePrefix(const std::string& file_path) {
   std::string file_contents;
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index fcf4497..ef4fddd 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -79,6 +79,22 @@
     shared_libs: ["libtest_elftls_shared_var"],
 }
 
+cc_test {
+   name: "thread_exit_cb_helper.cpp",
+   defaults: ["bionic_testlib_defaults"],
+   srcs: ["thread_exit_cb_helper.cpp"],
+   cflags: ["-fno-emulated-tls"],
+}
+
+cc_test {
+   name: "tls_properties_helper",
+   defaults: ["bionic_testlib_defaults"],
+   srcs: ["tls_properties_helper.cpp"],
+   cflags: ["-fno-emulated-tls"],
+   shared_libs: ["libtest_elftls_shared_var"],
+}
+
+
 cc_test_library {
     name: "libtest_elftls_dynamic_filler_1",
     defaults: ["bionic_testlib_defaults"],
diff --git a/tests/libs/thread_exit_cb_helper.cpp b/tests/libs/thread_exit_cb_helper.cpp
new file mode 100644
index 0000000..8ec1398
--- /dev/null
+++ b/tests/libs/thread_exit_cb_helper.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Prevent tests from being compiled with glibc because thread_properties.h
+// only exists in Bionic.
+#if defined(__BIONIC__)
+
+#include <stdio.h>
+#include <sys/thread_properties.h>
+
+// Helper binary for testing thread_exit_cb registration.
+
+void exit_cb_1() {
+  printf("exit_cb_1 called ");
+}
+
+void exit_cb_2() {
+  printf("exit_cb_2 called ");
+}
+
+void exit_cb_3() {
+  printf("exit_cb_3 called");
+}
+
+void test_register_thread_exit_cb() {
+  // Register the exit-cb in reverse order (3,2,1)
+  // so that they'd be called in 1,2,3 order.
+  __libc_register_thread_exit_callback(&exit_cb_3);
+  __libc_register_thread_exit_callback(&exit_cb_2);
+  __libc_register_thread_exit_callback(&exit_cb_1);
+}
+
+int main() {
+  test_register_thread_exit_cb();
+  return 0;
+}
+#else
+int main() {
+  return 0;
+}
+#endif  // __BIONIC__
diff --git a/tests/libs/tls_properties_helper.cpp b/tests/libs/tls_properties_helper.cpp
new file mode 100644
index 0000000..3f8d118
--- /dev/null
+++ b/tests/libs/tls_properties_helper.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Prevent tests from being compiled with glibc because thread_properties.h
+// only exists in Bionic.
+#if defined(__BIONIC__)
+
+#include <sys/thread_properties.h>
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>  // for gettid
+
+// Helper binary to use TLS-related functions in thread_properties
+
+// Tests __get_static_tls_bound.
+thread_local int local_var;
+void test_static_tls_bounds() {
+  local_var = 123;
+  void* start_addr = nullptr;
+  void* end_addr = nullptr;
+
+  __libc_get_static_tls_bounds(reinterpret_cast<void**>(&start_addr),
+                               reinterpret_cast<void**>(&end_addr));
+  assert(start_addr != nullptr);
+  assert(end_addr != nullptr);
+
+  assert(&local_var >= start_addr && &local_var < end_addr);
+
+  printf("done_get_static_tls_bounds\n");
+}
+
+// Tests iterate_dynamic tls chunks.
+// Export a var from the shared so.
+__thread char large_tls_var[4 * 1024 * 1024];
+void test_iter_tls() {
+  void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
+
+  int i = 0;
+  auto cb = [&](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) {
+    printf("iterate_cb i = %d\n", i++);
+  };
+  __libc_iterate_dynamic_tls(gettid(), cb, nullptr);
+  printf("done_iterate_dynamic_tls\n");
+}
+
+int main() {
+  test_static_tls_bounds();
+  test_iter_tls();
+  return 0;
+}
+
+#else
+int main() {
+  return 0;
+}
+#endif  // __BIONIC__
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 55bd149..d692cf9 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -84,6 +84,24 @@
   free(ptr);
 }
 
+TEST(malloc, calloc_mem_init_disabled) {
+#if defined(__BIONIC__)
+  // calloc should still zero memory if mem-init is disabled.
+  // With jemalloc the mallopts will fail but that shouldn't affect the
+  // execution of the test.
+  mallopt(M_THREAD_DISABLE_MEM_INIT, 1);
+  size_t alloc_len = 100;
+  char *ptr = reinterpret_cast<char*>(calloc(1, alloc_len));
+  for (size_t i = 0; i < alloc_len; i++) {
+    ASSERT_EQ(0, ptr[i]);
+  }
+  free(ptr);
+  mallopt(M_THREAD_DISABLE_MEM_INIT, 0);
+#else
+  GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
 TEST(malloc, calloc_illegal) {
   SKIP_WITH_HWASAN;
   errno = 0;
diff --git a/tests/netinet_ether_test.cpp b/tests/netinet_ether_test.cpp
index faa3db4..af020ec 100644
--- a/tests/netinet_ether_test.cpp
+++ b/tests/netinet_ether_test.cpp
@@ -34,7 +34,7 @@
 TEST(netinet_ether, ether_aton_r__ether_ntoa_r) {
   ether_addr addr;
   memset(&addr, 0, sizeof(addr));
-  ether_addr* a = ether_aton_r("12:34:56:78:9a:bc", &addr);
+  ether_addr* a = ether_aton_r("12:34:56:78:9a:Bc", &addr);
   ASSERT_EQ(&addr, a);
   ASSERT_EQ(0x12, addr.ether_addr_octet[0]);
   ASSERT_EQ(0x34, addr.ether_addr_octet[1]);
@@ -49,3 +49,11 @@
   ASSERT_EQ(buf, p);
   ASSERT_STREQ("12:34:56:78:9a:bc", buf);
 }
+
+TEST(netinet_ether, ether_aton_r_failures) {
+  ether_addr addr;
+  ASSERT_TRUE(ether_aton_r("12:34:56:78:9a;bc", &addr) == nullptr);
+  ASSERT_TRUE(ether_aton_r("12:34:56:78:9a:bc ", &addr) == nullptr);
+  ASSERT_TRUE(ether_aton_r("g2:34:56:78:9a:bc ", &addr) == nullptr);
+  ASSERT_TRUE(ether_aton_r("1G:34:56:78:9a:bc ", &addr) == nullptr);
+}
diff --git a/tests/netinet_in_test.cpp b/tests/netinet_in_test.cpp
index 2606082..437e180 100644
--- a/tests/netinet_in_test.cpp
+++ b/tests/netinet_in_test.cpp
@@ -31,8 +31,15 @@
 static constexpr uint64_t be64 = 0xf0debc9a78563412;
 
 TEST(netinet_in, bindresvport) {
-  // This isn't something we can usually test, so just check the symbol's there.
+  // This isn't something we can usually test (because you need to be root),
+  // so just check the symbol's there.
   ASSERT_EQ(-1, bindresvport(-1, nullptr));
+
+  // Only AF_INET is supported.
+  sockaddr_in sin = {.sin_family = AF_INET6};
+  errno = 0;
+  ASSERT_EQ(-1, bindresvport(-1, &sin));
+  ASSERT_EQ(EPFNOSUPPORT, errno);
 }
 
 TEST(netinet_in, in6addr_any) {
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index 9309a7f..03e8062 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -301,3 +301,7 @@
   // don't behave as POSIX specifies. http://b/26203902.
   ASSERT_EQ(0, sched_setscheduler(getpid(), original_policy, &p));
 }
+
+TEST(sched, sched_getaffinity_failure) {
+  ASSERT_EQ(-1, sched_getaffinity(getpid(), 0, nullptr));
+}
diff --git a/tests/search_test.cpp b/tests/search_test.cpp
index 1509199..8b8359d 100644
--- a/tests/search_test.cpp
+++ b/tests/search_test.cpp
@@ -114,6 +114,11 @@
   ASSERT_EQ(3U, g_free_calls);
 }
 
+TEST(search, tdestroy_null) {
+  // It's okay to pass a null node, and your callback will not be called.
+  tdestroy(nullptr, nullptr);
+}
+
 struct pod_node {
   explicit pod_node(int i) : i(i) {}
   int i;
@@ -285,3 +290,26 @@
   AssertEntry(e, "a", "B");
   hdestroy_r(&h2);
 }
+
+TEST(search, hsearch_resizing) {
+  ASSERT_NE(0, hcreate(1));
+
+  std::vector<char*> entries;
+  // Add enough entries to ensure that we've had to resize.
+  for (char ch = ' '; ch <= '~'; ++ch) {
+    char* p;
+    asprintf(&p, "%c", ch);
+    ENTRY e;
+    e.data = e.key = p;
+    ASSERT_TRUE(hsearch(e, ENTER) != nullptr);
+    entries.push_back(p);
+  }
+
+  // Check they're all there.
+  for (auto& p : entries) {
+    ENTRY* e = hsearch(ENTRY{.key = p, .data = nullptr}, FIND);
+    AssertEntry(e, p, p);
+  }
+
+  for (auto& p : entries) free(p);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index f6eca05..c21c3b8 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -371,6 +371,11 @@
 #endif
 }
 
+TEST(STDIO_TEST, snprintf_measure) {
+  char buf[16];
+  ASSERT_EQ(11, snprintf(buf, 0, "Hello %s", "world"));
+}
+
 TEST(STDIO_TEST, snprintf_smoke) {
   char buf[BUFSIZ];
 
@@ -1155,7 +1160,6 @@
   free(p1);
 }
 
-
 TEST(STDIO_TEST, sscanf_mlc) {
   // This is so useless that clang doesn't even believe it exists...
 #pragma clang diagnostic push
@@ -1189,7 +1193,6 @@
 #pragma clang diagnostic pop
 }
 
-
 TEST(STDIO_TEST, sscanf_ms) {
   CheckScanfM(sscanf, "hello", "%ms", 1, "hello");
   CheckScanfM(sscanf, "hello", "%4ms", 1, "hell");
@@ -2533,6 +2536,16 @@
   eth.Run([&]() { exit(puts("a b c")); }, 0, "a b c\n");
 }
 
+TEST(STDIO_TEST, putchar) {
+  ExecTestHelper eth;
+  eth.Run([&]() { exit(putchar('A')); }, 65, "A");
+}
+
+TEST(STDIO_TEST, putchar_unlocked) {
+  ExecTestHelper eth;
+  eth.Run([&]() { exit(putchar('B')); }, 66, "B");
+}
+
 TEST(STDIO_TEST, unlocked) {
   TemporaryFile tf;
 
@@ -2733,3 +2746,73 @@
  ASSERT_NE(0, RENAME_WHITEOUT);
 #endif
 }
+
+TEST(STDIO_TEST, fdopen_failures) {
+  FILE* fp;
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_TRUE(fd != -1);
+
+  // Nonsense mode.
+  errno = 0;
+  fp = fdopen(fd, "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Mode that isn't a subset of the fd's actual mode.
+  errno = 0;
+  fp = fdopen(fd, "w");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Can't set append on the underlying fd.
+  errno = 0;
+  fp = fdopen(fd, "a");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+
+  // Bad fd.
+  errno = 0;
+  fp = fdopen(-1, "re");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EBADF, errno);
+
+  close(fd);
+}
+
+TEST(STDIO_TEST, fmemopen_invalid_mode) {
+  errno = 0;
+  FILE* fp = fmemopen(nullptr, 16, "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, fopen_invalid_mode) {
+  errno = 0;
+  FILE* fp = fopen("/proc/version", "nonsense");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, freopen_invalid_mode) {
+  FILE* fp = fopen("/proc/version", "re");
+  ASSERT_TRUE(fp != nullptr);
+
+  errno = 0;
+  fp = freopen("/proc/version", "nonsense", fp);
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(STDIO_TEST, asprintf_smoke) {
+  char* p = nullptr;
+  ASSERT_EQ(11, asprintf(&p, "hello %s", "world"));
+  ASSERT_STREQ("hello world", p);
+  free(p);
+}
+
+TEST(STDIO_TEST, fopen_ENOENT) {
+  errno = 0;
+  FILE* fp = fopen("/proc/does-not-exist", "re");
+  ASSERT_TRUE(fp == nullptr);
+  ASSERT_EQ(ENOENT, errno);
+}
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 3f1ec86..c7b2ad8 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -800,10 +800,25 @@
   ASSERT_EQ(T(0), fn("123", &end_p, 37));
   ASSERT_EQ(EINVAL, errno);
 
+  // Both leading + or - are always allowed (even for the strtou* family).
+  ASSERT_EQ(T(-123), fn("-123", &end_p, 10));
+  ASSERT_EQ(T(123), fn("+123", &end_p, 10));
+
   // If we see "0x" *not* followed by a hex digit, we shouldn't swallow the 'x'.
   ASSERT_EQ(T(0), fn("0xy", &end_p, 16));
   ASSERT_EQ('x', *end_p);
 
+  // Hexadecimal (both the 0x and the digits) is case-insensitive.
+  ASSERT_EQ(T(0xab), fn("0xab", &end_p, 0));
+  ASSERT_EQ(T(0xab), fn("0Xab", &end_p, 0));
+  ASSERT_EQ(T(0xab), fn("0xAB", &end_p, 0));
+  ASSERT_EQ(T(0xab), fn("0XAB", &end_p, 0));
+  ASSERT_EQ(T(0xab), fn("0xAb", &end_p, 0));
+  ASSERT_EQ(T(0xab), fn("0XAb", &end_p, 0));
+
+  // Octal lives! (Sadly.)
+  ASSERT_EQ(T(0666), fn("0666", &end_p, 0));
+
   if (std::numeric_limits<T>::is_signed) {
     // Minimum (such as -128).
     std::string min{std::to_string(std::numeric_limits<T>::min())};
@@ -878,6 +893,18 @@
   CheckStrToInt(strtoumax);
 }
 
+TEST(stdlib, atoi) {
+  // Implemented using strtol in bionic, so extensive testing unnecessary.
+  ASSERT_EQ(123, atoi("123four"));
+  ASSERT_EQ(0, atoi("hello"));
+}
+
+TEST(stdlib, atol) {
+  // Implemented using strtol in bionic, so extensive testing unnecessary.
+  ASSERT_EQ(123L, atol("123four"));
+  ASSERT_EQ(0L, atol("hello"));
+}
+
 TEST(stdlib, abs) {
   ASSERT_EQ(INT_MAX, abs(-INT_MAX));
   ASSERT_EQ(INT_MAX, abs(INT_MAX));
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index fd7a551..22be852 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -64,6 +64,11 @@
   ASSERT_STREQ("Unknown error 134", strerror(EHWPOISON + 1));
 }
 
+TEST(STRING_TEST, strerror_l) {
+  // bionic just forwards to strerror(3).
+  ASSERT_STREQ("Success", strerror_l(0, LC_GLOBAL_LOCALE));
+}
+
 #if defined(__BIONIC__)
 static void* ConcurrentStrErrorFn(void*) {
   bool equal = (strcmp("Unknown error 2002", strerror(2002)) == 0);
@@ -1607,6 +1612,13 @@
   ASSERT_TRUE(strcoll("aac", "aab") > 0);
 }
 
+TEST(STRING_TEST, strcoll_l_smoke) {
+  // bionic just forwards to strcoll(3).
+  ASSERT_TRUE(strcoll_l("aab", "aac", LC_GLOBAL_LOCALE) < 0);
+  ASSERT_TRUE(strcoll_l("aab", "aab", LC_GLOBAL_LOCALE) == 0);
+  ASSERT_TRUE(strcoll_l("aac", "aab", LC_GLOBAL_LOCALE) > 0);
+}
+
 TEST(STRING_TEST, strxfrm_smoke) {
   const char* src1 = "aab";
   char dst1[16] = {};
@@ -1628,6 +1640,16 @@
   ASSERT_TRUE(strcmp(dst1, dst2) < 0);
 }
 
+TEST(STRING_TEST, strxfrm_l_smoke) {
+  // bionic just forwards to strxfrm(3), so this is a subset of the
+  // strxfrm test.
+  const char* src1 = "aab";
+  char dst1[16] = {};
+  ASSERT_EQ(strxfrm_l(dst1, src1, 0, LC_GLOBAL_LOCALE), 3U);
+  ASSERT_STREQ(dst1, "");
+  ASSERT_EQ(strxfrm_l(dst1, src1, sizeof(dst1), LC_GLOBAL_LOCALE), 3U);
+}
+
 TEST(STRING_TEST, memccpy_smoke) {
   char dst[32];
 
diff --git a/tests/sys_procfs_test.cpp b/tests/sys_procfs_test.cpp
index 8054869..5e0a0b0 100644
--- a/tests/sys_procfs_test.cpp
+++ b/tests/sys_procfs_test.cpp
@@ -18,7 +18,7 @@
 
 #include <sys/procfs.h>
 
-TEST(sys_procfs, smoke) {
+TEST(sys_procfs, types) {
   elf_greg_t reg;
   memset(&reg, 0, sizeof(reg));
 
@@ -37,3 +37,16 @@
   static_assert(sizeof(prgregset_t) == sizeof(elf_gregset_t), "");
   static_assert(sizeof(prfpregset_t) == sizeof(elf_fpregset_t), "");
 }
+
+TEST(sys_procfs, constants) {
+  // NGREG != ELF_NGREG (https://github.com/android/ndk/issues/1347)
+  static_assert(sizeof(gregset_t) / sizeof(greg_t) == NGREG);
+
+#if defined(__arm__)
+  static_assert(sizeof(user_regs) / sizeof(elf_greg_t) == ELF_NGREG);
+#elif defined(__aarch64__)
+  static_assert(sizeof(user_pt_regs) / sizeof(elf_greg_t) == ELF_NGREG);
+#else
+  static_assert(sizeof(user_regs_struct) / sizeof(elf_greg_t) == ELF_NGREG);
+#endif
+}
diff --git a/tests/sys_thread_properties_test.cpp b/tests/sys_thread_properties_test.cpp
new file mode 100644
index 0000000..cf1a6ba
--- /dev/null
+++ b/tests/sys_thread_properties_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "gtest_globals.h"
+#include "utils.h"
+
+TEST(thread_properties_test, iterate_dts) {
+#if defined(__BIONIC__)
+  const char expected_out[] =
+      "got test_static_tls_bounds\niterate_cb i = 0\ndone_iterate_dynamic_tls\n";
+  std::string helper = GetTestLibRoot() + "tls_properties_helper/tls_properties_helper";
+  chmod(helper.c_str(), 0755);  // TODO: "x" lost in CTS, b/34945607
+
+  ExecTestHelper eth;
+  eth.SetArgs({helper.c_str(), nullptr});
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out);
+#endif
+}
+
+TEST(thread_properties_test, thread_exit_cb) {
+#if defined(__BIONIC__)
+  // tests/libs/thread_exit_cb_helper.cpp
+  const char expected_out[] = "exit_cb_1 called exit_cb_2 called exit_cb_3 called";
+  std::string helper = GetTestLibRoot() + "thread_exit_cb_helper/thread_exit_cb_helper";
+  chmod(helper.c_str(), 0755);  // TODO: "x" lost in CTS, b/34945607
+
+  ExecTestHelper eth;
+  eth.SetArgs({helper.c_str(), nullptr});
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out);
+
+#endif
+}
diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp
index a521967..f82f505 100644
--- a/tests/sys_vfs_test.cpp
+++ b/tests/sys_vfs_test.cpp
@@ -44,12 +44,26 @@
   Check(sb);
 }
 
+TEST(sys_vfs, statfs_failure) {
+  struct statfs sb;
+  errno = 0;
+  ASSERT_EQ(-1, statfs("/does-not-exist", &sb));
+  ASSERT_EQ(ENOENT, errno);
+}
+
 TEST(sys_vfs, statfs64) {
   struct statfs64 sb;
   ASSERT_EQ(0, statfs64("/proc", &sb));
   Check(sb);
 }
 
+TEST(sys_vfs, statfs64_failure) {
+  struct statfs64 sb;
+  errno = 0;
+  ASSERT_EQ(-1, statfs64("/does-not-exist", &sb));
+  ASSERT_EQ(ENOENT, errno);
+}
+
 TEST(sys_vfs, fstatfs) {
   struct statfs sb;
   int fd = open("/proc", O_RDONLY);
@@ -58,6 +72,13 @@
   Check(sb);
 }
 
+TEST(sys_vfs, fstatfs_failure) {
+  struct statfs sb;
+  errno = 0;
+  ASSERT_EQ(-1, fstatfs(-1, &sb));
+  ASSERT_EQ(EBADF, errno);
+}
+
 TEST(sys_vfs, fstatfs64) {
   struct statfs64 sb;
   int fd = open("/proc", O_RDONLY);
@@ -65,3 +86,10 @@
   close(fd);
   Check(sb);
 }
+
+TEST(sys_vfs, fstatfs64_failure) {
+  struct statfs sb;
+  errno = 0;
+  ASSERT_EQ(-1, fstatfs(-1, &sb));
+  ASSERT_EQ(EBADF, errno);
+}
diff --git a/tests/sys_wait_test.cpp b/tests/sys_wait_test.cpp
new file mode 100644
index 0000000..c006972
--- /dev/null
+++ b/tests/sys_wait_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/wait.h>
+
+TEST(sys_wait, waitid) {
+  pid_t pid = fork();
+  ASSERT_NE(pid, -1);
+
+  if (pid == 0) _exit(66);
+
+  siginfo_t si = {};
+  ASSERT_EQ(0, waitid(P_PID, pid, &si, WEXITED));
+  ASSERT_EQ(pid, si.si_pid);
+  ASSERT_EQ(66, si.si_status);
+  ASSERT_EQ(CLD_EXITED, si.si_code);
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 5a977c2..b1de0a4 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -363,6 +363,105 @@
   EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
 }
 
+TEST(time, strptime_Z) {
+#if defined(__BIONIC__)
+  // glibc doesn't handle %Z at all.
+  // The BSDs only handle hard-coded "GMT" and "UTC", plus whatever two strings
+  // are in the global `tzname` (which correspond to the current $TZ).
+  struct tm tm;
+  setenv("TZ", "Europe/Berlin", 1);
+
+  // "GMT" always works.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("GMT", "%Z", &tm));
+  EXPECT_STREQ("GMT", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(0, tm.tm_gmtoff);
+
+  // As does "UTC".
+  tm = {};
+  ASSERT_EQ('\0', *strptime("UTC", "%Z", &tm));
+  EXPECT_STREQ("UTC", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(0, tm.tm_gmtoff);
+
+  // Europe/Berlin is known as "CET" when there's no DST.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("CET", "%Z", &tm));
+  EXPECT_STREQ("CET", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(3600, tm.tm_gmtoff);
+
+  // Europe/Berlin is known as "CEST" when there's no DST.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("CEST", "%Z", &tm));
+  EXPECT_STREQ("CEST", tm.tm_zone);
+  EXPECT_EQ(1, tm.tm_isdst);
+  EXPECT_EQ(3600, tm.tm_gmtoff);
+
+  // And as long as we're in Europe/Berlin, those are the only time zone
+  // abbreviations that are recognized.
+  tm = {};
+  ASSERT_TRUE(strptime("PDT", "%Z", &tm) == nullptr);
+#endif
+}
+
+TEST(time, strptime_z) {
+  struct tm tm;
+  setenv("TZ", "Europe/Berlin", 1);
+
+  // "UT" is what RFC822 called UTC.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("UT", "%z", &tm));
+  EXPECT_STREQ("UTC", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(0, tm.tm_gmtoff);
+  // "GMT" is RFC822's other name for UTC.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("GMT", "%z", &tm));
+  EXPECT_STREQ("UTC", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(0, tm.tm_gmtoff);
+
+  // "Z" ("Zulu") is a synonym for UTC.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("Z", "%z", &tm));
+  EXPECT_STREQ("UTC", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(0, tm.tm_gmtoff);
+
+  // "PST"/"PDT" and the other common US zone abbreviations are all supported.
+  tm = {};
+  ASSERT_EQ('\0', *strptime("PST", "%z", &tm));
+  EXPECT_STREQ("PST", tm.tm_zone);
+  EXPECT_EQ(0, tm.tm_isdst);
+  EXPECT_EQ(-28800, tm.tm_gmtoff);
+  tm = {};
+  ASSERT_EQ('\0', *strptime("PDT", "%z", &tm));
+  EXPECT_STREQ("PDT", tm.tm_zone);
+  EXPECT_EQ(1, tm.tm_isdst);
+  EXPECT_EQ(-25200, tm.tm_gmtoff);
+
+  // +-hh
+  tm = {};
+  ASSERT_EQ('\0', *strptime("+01", "%z", &tm));
+  EXPECT_EQ(3600, tm.tm_gmtoff);
+  EXPECT_TRUE(tm.tm_zone == nullptr);
+  EXPECT_EQ(0, tm.tm_isdst);
+  // +-hhmm
+  tm = {};
+  ASSERT_EQ('\0', *strptime("+0130", "%z", &tm));
+  EXPECT_EQ(5400, tm.tm_gmtoff);
+  EXPECT_TRUE(tm.tm_zone == nullptr);
+  EXPECT_EQ(0, tm.tm_isdst);
+  // +-hh:mm
+  tm = {};
+  ASSERT_EQ('\0', *strptime("+01:30", "%z", &tm));
+  EXPECT_EQ(5400, tm.tm_gmtoff);
+  EXPECT_TRUE(tm.tm_zone == nullptr);
+  EXPECT_EQ(0, tm.tm_isdst);
+}
+
 void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
   itimerspec ts;
   ts.it_value.tv_sec = value_s;
@@ -1008,4 +1107,5 @@
 
 TEST(time, difftime) {
   ASSERT_EQ(1.0, difftime(1, 0));
+  ASSERT_EQ(-1.0, difftime(0, 1));
 }
diff --git a/tests/utils.h b/tests/utils.h
index c1b7f65..acd8bc6 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -78,13 +78,8 @@
 
 static inline bool running_with_native_bridge() {
 #if defined(__BIONIC__)
-#if defined(__arm__)
-  static const prop_info* pi = __system_property_find("ro.dalvik.vm.isa.arm");
+  static const prop_info* pi = __system_property_find("ro.dalvik.vm.isa." ABI_STRING);
   return pi != nullptr;
-#elif defined(__aarch64__)
-  static const prop_info* pi = __system_property_find("ro.dalvik.vm.isa.arm64");
-  return pi != nullptr;
-#endif
 #endif
   return false;
 }
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 184c3d4..adf93c3 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -42,6 +42,7 @@
 #include <llvm/ADT/SmallVector.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Option/Option.h>
+#include <llvm/Support/Host.h>
 #include <llvm/Support/VirtualFileSystem.h>
 
 #include "Arch.h"