Merge master@5406228 into git_qt-dev-plus-aosp.
am: 5da3333d1b

Change-Id: I25c9f2606c7d692fb1b7d40d8205122b27f74dda
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 1630db8..4c13bec 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -417,3 +417,17 @@
 | No workaround     | Works for static STL       | Broken  | Works |
 | `-Wl,-z,nodelete` | Works for static STL       | Works   | Works |
 | No `dlclose`      | Works                      | Works   | Works |
+
+## Use of IFUNC in libc (True for all API levels on devices running Q)
+
+Starting with Android Q (API level 29), libc uses
+[IFUNC](https://sourceware.org/glibc/wiki/GNU_IFUNC) functionality in
+the dynamic linker to choose optimized assembler routines at run time
+rather than at build time. This lets us use the same `libc.so` on all
+devices, and is similar to what other OSes already did. Because the zygote
+uses the C library, this decision is made long before we know what API
+level an app targets, so all code sees the new IFUNC-using C library.
+Most apps should be unaffected by this change, but apps that hook or try to
+detect hooking of C library functions might need to fix their code to cope
+with IFUNC relocations. The affected functions are from `<string.h>`, but
+may expand to include more functions (and more libraries) in future.
diff --git a/benchmarks/semaphore_benchmark.cpp b/benchmarks/semaphore_benchmark.cpp
index ba89137..cf51489 100644
--- a/benchmarks/semaphore_benchmark.cpp
+++ b/benchmarks/semaphore_benchmark.cpp
@@ -80,7 +80,7 @@
 
 class SemaphoreFixture : public benchmark::Fixture {
  public:
-  void SetUp(const benchmark::State&) {
+  void SetUp(const benchmark::State&) override {
     sem_init(&semaphore, 0, 0);
 
     pthread_attr_t attr;
@@ -100,7 +100,7 @@
     setup = true;
   }
 
-  ~SemaphoreFixture() {
+  ~SemaphoreFixture() override {
     if (setup) {
       // Only do this if the test was actually run.
       sched_setscheduler(0, SCHED_OTHER, &param);
diff --git a/build/run-on-host.sh b/build/run-on-host.sh
new file mode 100644
index 0000000..c3a2751
--- /dev/null
+++ b/build/run-on-host.sh
@@ -0,0 +1,47 @@
+#!/bin/bash -e
+
+source ${ANDROID_BUILD_TOP}/build/envsetup.sh
+
+TARGET_ARCH=$(get_build_var TARGET_ARCH)
+TARGET_OUT=$(get_build_var TARGET_OUT)
+TARGET_OUT_EXECUTABLES=$(get_build_var TARGET_OUT_EXECUTABLES)
+TARGET_OUT_DATA=$(get_build_var TARGET_OUT_DATA)
+HOST_OS=$(get_build_var HOST_OS)
+HOST_ARCH=$(get_build_var HOST_ARCH)
+HOST_OUT=$(get_build_var HOST_OUT)
+
+function prepare()
+{
+    BITS=$1
+    shift
+
+    NATIVETEST=${TARGET_OUT_DATA}/nativetest
+    if [ "${BITS}" = 64 ]; then
+        NATIVETEST=${NATIVETEST}64
+    fi
+
+    if [ ${TARGET_ARCH} = arm -o ${TARGET_ARCH} = mips -o ${TARGET_ARCH} = x86 ]; then
+        LINKER=${TARGET_OUT_EXECUTABLES}/linker
+    else
+        LINKER="${TARGET_OUT_EXECUTABLES}/linker64 ${TARGET_OUT_EXECUTABLES}/linker"
+    fi
+
+    if [ ${TARGET_ARCH} = x86 -o ${TARGET_ARCH} = x86_64 ]; then
+        m -j ${LINKER} ${TARGET_OUT}/etc/hosts ${TARGET_OUT_EXECUTABLES}/sh $@
+
+        if [ ! -d /system ]; then
+            echo "Attempting to create /system";
+            sudo mkdir -p -m 0777 /system;
+        fi
+        (
+            cd ${ANDROID_BUILD_TOP}
+            mkdir -p ${TARGET_OUT_DATA}/local/tmp
+            ln -fs `realpath ${TARGET_OUT}/bin` /system/
+            ln -fs `realpath ${TARGET_OUT}/etc` /system/
+            ln -fs `realpath ${TARGET_OUT}/lib` /system/
+            if [ -d "${TARGET_OUT}/lib64" ]; then
+                ln -fs `realpath ${TARGET_OUT}/lib64` /system/;
+            fi
+        )
+    fi
+}
diff --git a/docs/status.md b/docs/status.md
index 0cbcb47..d6a2f4c 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -45,14 +45,17 @@
   * `getloadavg` (BSD/GNU extension in <stdlib.h>)
 
 New libc behavior in Q (API level 29):
-  * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog`
-  * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension
-  * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff
-  * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`
+  * Whole printf family now supports the GNU `%m` extension, rather than a
+    special-case hack in `syslog`.
+  * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension.
+  * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff.
+  * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`.
   * Using `%n` with the printf family is now reported as a FORTIFY failure.
     Previous versions of Android would ignore the `%n` but not consume the
     corresponding pointer argument, leading to obscure errors. The scanf family
     is unchanged.
+  * Support in strptime for `%F`, `%G`, `%g`, `%P`, `%u`, `%V`, and `%v`.
+    (strftime already supported them all.)
   * [fdsan](fdsan.md) detects common file descriptor errors at runtime.
 
 New libc functions in P (API level 28):
@@ -74,9 +77,9 @@
   * `syncfs`
 
 New libc behavior in P (API level 28):
-  * `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
-  * `%mc`/`%ms`/`%m[` support in the scanf family
-  * `%s` support in strptime (strftime already supported it)
+  * `%C` and `%S` support in the printf family (previously only the wprintf family supported these).
+  * `%mc`/`%ms`/`%m[` support in the scanf family.
+  * `%s` support in strptime (strftime already supported it).
   * Using a `pthread_mutex_t` after it's been destroyed will be detected at
     runtime and reported as a FORTIFY failure.
   * Passing a null `FILE*` or `DIR*` to libc is now detected at runtime and
diff --git a/libc/Android.bp b/libc/Android.bp
index a27b1ce..0950662 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -77,14 +77,6 @@
     native_coverage: false,
     recovery_available: true,
 
-    arch: {
-        x86: {
-            no_libcrt: true,
-        },
-        x86_64: {
-            no_libcrt: true,
-        },
-    },
     // lld complains about duplicate symbols in libcrt and libgcc. Suppress the
     // warning since this is intended right now.
     ldflags: ["-Wl,-z,muldefs"],
@@ -2433,3 +2425,54 @@
         static_libs: ["libbase"],
     },
 }
+
+// This is a temporary library that will use scudo as the native memory
+// allocator. To use it, add it as the first shared library.
+cc_library_shared {
+    name: "libc_scudo",
+    vendor_available: true,
+    srcs: [
+        "bionic/malloc_common.cpp",
+        "bionic/malloc_common_dynamic.cpp",
+        "bionic/malloc_heapprofd.cpp",
+        "bionic/malloc_limit.cpp",
+        "bionic/scudo_wrapper.cpp",
+        "bionic/__set_errno.cpp",
+    ],
+    cflags: ["-DUSE_SCUDO"],
+    stl: "none",
+    system_shared_libs: [],
+
+    header_libs: ["libc_headers"],
+
+    static_libs: ["libasync_safe"],
+
+    allow_undefined_symbols: true,
+    shared_libs: ["libscudo_wrapper"],
+
+    arch: {
+        arm: {
+            srcs: ["arch-arm/syscalls/__rt_sigprocmask.S"],
+        },
+        arm64: {
+            srcs: ["arch-arm64/syscalls/__rt_sigprocmask.S"],
+        },
+        x86: {
+            srcs: [
+                "arch-x86/bionic/__libc_init_sysinfo.cpp",
+                "arch-x86/syscalls/__rt_sigprocmask.S",
+            ],
+        },
+        x86_64: {
+            srcs: ["arch-x86_64/syscalls/__rt_sigprocmask.S"],
+        },
+    },
+
+    // Mark this library as global so it overrides all the allocation
+    // definitions properly.
+    ldflags: ["-Wl,-z,global"],
+}
+
+subdirs = [
+    "bionic/scudo",
+]
diff --git a/libc/bionic/__bionic_get_shell_path.cpp b/libc/bionic/__bionic_get_shell_path.cpp
index 1352815..7aeed18 100644
--- a/libc/bionic/__bionic_get_shell_path.cpp
+++ b/libc/bionic/__bionic_get_shell_path.cpp
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#include "private/__bionic_get_shell_path.h"
+
 #include <errno.h>
 #include <string.h>
 #include <sys/cdefs.h>
@@ -51,7 +53,7 @@
   return "/system/bin/sh";
 }
 
-__LIBC_HIDDEN__ extern "C" const char* __bionic_get_shell_path() {
+const char* __bionic_get_shell_path() {
   static const char* sh_path = init_sh_path();
   return sh_path;
 }
diff --git a/libc/bionic/android_set_abort_message.cpp b/libc/bionic/android_set_abort_message.cpp
index 56e6771..2ea12ee 100644
--- a/libc/bionic/android_set_abort_message.cpp
+++ b/libc/bionic/android_set_abort_message.cpp
@@ -33,6 +33,7 @@
 #include <stddef.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 
 #include "private/bionic_defs.h"
 #include "private/bionic_globals.h"
@@ -82,6 +83,10 @@
     return;
   }
 
+  // Name the abort message mapping to make it easier for tools to find the
+  // mapping.
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, size, "abort message");
+
   magic_abort_msg_t* new_magic_abort_message = reinterpret_cast<magic_abort_msg_t*>(map);
   fill_abort_message_magic(new_magic_abort_message);
   new_magic_abort_message->msg.size = size;
diff --git a/libc/bionic/exec.cpp b/libc/bionic/exec.cpp
index 1cf3a58..3309585 100644
--- a/libc/bionic/exec.cpp
+++ b/libc/bionic/exec.cpp
@@ -39,6 +39,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "private/__bionic_get_shell_path.h"
 #include "private/FdPath.h"
 
 extern "C" char** environ;
@@ -111,7 +112,7 @@
   script_argv[0] = "sh";
   script_argv[1] = buf;
   memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*));
-  return execve(_PATH_BSHELL, const_cast<char**>(script_argv), envp);
+  return execve(__bionic_get_shell_path(), const_cast<char**>(script_argv), envp);
 }
 
 int execvpe(const char* name, char* const* argv, char* const* envp) {
diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
index a40501d..7f3b711 100644
--- a/libc/bionic/malloc_common.h
+++ b/libc/bionic/malloc_common.h
@@ -55,11 +55,20 @@
 
 #else // __has_feature(hwaddress_sanitizer)
 
+#if defined(USE_SCUDO)
+
+#include "scudo.h"
+#define Malloc(function)  scudo_ ## function
+
+#else
+
 #include "jemalloc.h"
 #define Malloc(function)  je_ ## function
 
 #endif
 
+#endif
+
 extern int gMallocLeakZygoteChild;
 
 static inline const MallocDispatch* GetDispatchTable() {
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 40f497e..3ccaed6 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -307,8 +307,6 @@
     atomic_store(&globals->current_dispatch_table, &globals->malloc_dispatch_table);
   }
 
-  info_log("%s: malloc %s enabled", getprogname(), prefix);
-
   // Use atexit to trigger the cleanup function. This avoids a problem
   // where another atexit function is used to cleanup allocated memory,
   // but the finalize function was already called. This particular error
@@ -316,7 +314,7 @@
   int ret_value = __cxa_atexit(MallocFiniImpl, nullptr, nullptr);
   if (ret_value != 0) {
     // We don't consider this a fatal error.
-    info_log("failed to set atexit cleanup function: %d", ret_value);
+    warning_log("failed to set atexit cleanup function: %d", ret_value);
   }
   return true;
 }
@@ -328,13 +326,6 @@
     return false;
   }
 
-  init_func_t init_func = reinterpret_cast<init_func_t>(gFunctions[FUNC_INITIALIZE]);
-  if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
-    error_log("%s: failed to enable malloc %s", getprogname(), prefix);
-    ClearGlobalFunctions();
-    return false;
-  }
-
   if (!FinishInstallHooks(globals, options, prefix)) {
     dlclose(impl_handle);
     return false;
diff --git a/libc/bionic/malloc_limit.cpp b/libc/bionic/malloc_limit.cpp
index 69a8f89..b42865b 100644
--- a/libc/bionic/malloc_limit.cpp
+++ b/libc/bionic/malloc_limit.cpp
@@ -275,7 +275,7 @@
   // being called, allow up to five ms for the signal handler to complete
   // before failing.
   bool enabled = false;
-  size_t num_tries = 10;
+  size_t num_tries = 20;
   while (true) {
     if (!atomic_exchange(&gGlobalsMutating, true)) {
       __libc_globals.mutate([](libc_globals* globals) {
diff --git a/libc/bionic/scudo.h b/libc/bionic/scudo.h
new file mode 100644
index 0000000..d9933c4
--- /dev/null
+++ b/libc/bionic/scudo.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#include <private/bionic_config.h>
+
+__BEGIN_DECLS
+
+void* scudo_aligned_alloc(size_t, size_t);
+void* scudo_calloc(size_t, size_t);
+void scudo_free(void*);
+struct mallinfo scudo_mallinfo();
+void* scudo_malloc(size_t);
+int scudo_malloc_info(int, FILE*);
+size_t scudo_malloc_usable_size(const void*);
+int scudo_mallopt(int, int);
+void* scudo_memalign(size_t, size_t);
+void* scudo_realloc(void*, size_t);
+int scudo_posix_memalign(void**, size_t, size_t);
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* scudo_pvalloc(size_t);
+void* scudo_valloc(size_t);
+#endif
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
+void scudo_malloc_disable();
+void scudo_malloc_enable();
+
+__END_DECLS
diff --git a/libc/bionic/scudo/Android.bp b/libc/bionic/scudo/Android.bp
new file mode 100644
index 0000000..8b518bb
--- /dev/null
+++ b/libc/bionic/scudo/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_library_shared {
+    name: "libscudo_wrapper",
+    vendor_available: true,
+    srcs: ["scudo.cpp"],
+
+    stl: "none",
+    system_shared_libs: [],
+    host_supported: false,
+
+    header_libs: ["libc_headers"],
+    include_dirs: [
+        "bionic/libc",
+        "bionic/libc/bionic",
+    ],
+
+    whole_static_libs: ["libasync_safe"],
+
+    arch: {
+        arm: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-arm-android.static"],
+        },
+        arm64: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-aarch64-android.static"],
+        },
+        x86: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-i686-android.static"],
+        },
+        x86_64: {
+            whole_static_libs: ["libclang_rt.scudo_minimal-x86_64-android.static"],
+        },
+    },
+
+    // Will be referencing other libc code that won't be defined here.
+    allow_undefined_symbols: true,
+
+    multilib: {
+        lib32: {
+            version_script: "exported32.map",
+        },
+        lib64: {
+            version_script: "exported64.map",
+        },
+    },
+}
diff --git a/libc/bionic/scudo/exported32.map b/libc/bionic/scudo/exported32.map
new file mode 100644
index 0000000..4b6791d
--- /dev/null
+++ b/libc/bionic/scudo/exported32.map
@@ -0,0 +1,16 @@
+LIBC_SCUDO {
+  global:
+    scudo_aligned_alloc;
+    scudo_calloc;
+    scudo_free;
+    scudo_mallinfo;
+    scudo_malloc;
+    scudo_malloc_usable_size;
+    scudo_memalign;
+    scudo_posix_memalign;
+    scudo_pvalloc;
+    scudo_realloc;
+    scudo_valloc;
+  local:
+    *;
+};
diff --git a/libc/bionic/scudo/exported64.map b/libc/bionic/scudo/exported64.map
new file mode 100644
index 0000000..1346b4b
--- /dev/null
+++ b/libc/bionic/scudo/exported64.map
@@ -0,0 +1,14 @@
+LIBC_SCUDO {
+  global:
+    scudo_aligned_alloc;
+    scudo_calloc;
+    scudo_free;
+    scudo_mallinfo;
+    scudo_malloc;
+    scudo_malloc_usable_size;
+    scudo_memalign;
+    scudo_posix_memalign;
+    scudo_realloc;
+  local:
+    *;
+};
diff --git a/libc/bionic/scudo/scudo.cpp b/libc/bionic/scudo/scudo.cpp
new file mode 100644
index 0000000..fb09b92
--- /dev/null
+++ b/libc/bionic/scudo/scudo.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+
+#include "private/bionic_macros.h"
+
+#include "scudo.h"
+
+// Disable Scudo's mismatch allocation check, as it is being triggered
+// by some third party code.
+extern "C" const char *__scudo_default_options() {
+  return "DeallocationTypeMismatch=false";
+}
+
+static inline bool AllocTooBig(size_t bytes) {
+#if defined(__LP64__)
+  if (__predict_false(bytes > 0x10000000000ULL)) {
+#else
+  if (__predict_false(bytes > 0x80000000ULL)) {
+#endif
+    return true;
+  }
+  return false;
+}
+
+void* scudo_aligned_alloc(size_t alignment, size_t size) {
+  if (alignment == 0 || !powerof2(alignment) || (size % alignment) != 0) {
+    errno = EINVAL;
+    return nullptr;
+  }
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+
+  return aligned_alloc(alignment, size);
+}
+
+void* scudo_calloc(size_t item_count, size_t item_size) {
+  size_t total;
+  if (__builtin_mul_overflow(item_count, item_size, &total) || AllocTooBig(total)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return calloc(item_count, item_size);
+}
+
+void scudo_free(void* ptr) {
+  free(ptr);
+}
+
+extern "C" size_t __sanitizer_get_current_allocated_bytes();
+extern "C" size_t __sanitizer_get_heap_size();
+
+struct mallinfo scudo_mallinfo() {
+  struct mallinfo info {};
+  info.uordblks = __sanitizer_get_current_allocated_bytes();
+  info.hblkhd = __sanitizer_get_heap_size();
+  info.usmblks = info.hblkhd;
+  return info;
+}
+
+void* scudo_malloc(size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return malloc(byte_count);
+}
+
+size_t scudo_malloc_usable_size(const void* ptr) {
+  return malloc_usable_size(ptr);
+}
+
+void* scudo_memalign(size_t alignment, size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  if (alignment != 0) {
+    if (!powerof2(alignment)) {
+      alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
+    }
+  } else {
+    alignment = 1;
+  }
+  return memalign(alignment, byte_count);
+}
+
+void* scudo_realloc(void* ptr, size_t byte_count) {
+  if (AllocTooBig(byte_count)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return realloc(ptr, byte_count);
+}
+
+int scudo_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if (alignment < sizeof(void*) || !powerof2(alignment)) {
+    return EINVAL;
+  }
+  if (AllocTooBig(size)) {
+    return ENOMEM;
+  }
+  return posix_memalign(memptr, alignment, size);
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+extern "C" void* pvalloc(size_t);
+
+void* scudo_pvalloc(size_t size) {
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return pvalloc(size);
+}
+
+extern "C" void* valloc(size_t);
+
+void* scudo_valloc(size_t size) {
+  if (AllocTooBig(size)) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return valloc(size);
+}
+#endif
+
+// Do not try and name the scudo maps by overriding __sanitizer::internal_mmap.
+// There is already a function called MmapNamed that names the maps.
+// Unfortunately, there is no easy way to override MmapNamed because
+// too much of the code is not compiled into functions available in the
+// library, and the code is complicated.
diff --git a/libc/bionic/scudo_wrapper.cpp b/libc/bionic/scudo_wrapper.cpp
new file mode 100644
index 0000000..e17f20b
--- /dev/null
+++ b/libc/bionic/scudo_wrapper.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "scudo.h"
+#include "private/bionic_globals.h"
+#include "private/WriteProtected.h"
+
+__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
+
+#if defined(__i386__)
+__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
+#endif
+
+int scudo_mallopt(int /*param*/, int /*value*/) {
+  return 0;
+}
+
+int scudo_malloc_info(int /*options*/, FILE* /*fp*/) {
+  errno = ENOTSUP;
+  return -1;
+}
+
+int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
+  return 0;
+}
+
+void scudo_malloc_disable() {
+}
+
+void scudo_malloc_enable() {
+}
diff --git a/libc/bionic/system.cpp b/libc/bionic/system.cpp
index 7411ae5..950f05c 100644
--- a/libc/bionic/system.cpp
+++ b/libc/bionic/system.cpp
@@ -27,12 +27,12 @@
  */
 
 #include <errno.h>
-#include <paths.h>
 #include <stdlib.h>
 #include <spawn.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "private/__bionic_get_shell_path.h"
 #include "private/ScopedSignalBlocker.h"
 #include "private/ScopedSignalHandler.h"
 
@@ -58,7 +58,7 @@
 
   const char* argv[] = { "sh", "-c", command, nullptr };
   pid_t child;
-  if ((errno = posix_spawn(&child, _PATH_BSHELL, nullptr, &attributes,
+  if ((errno = posix_spawn(&child, __bionic_get_shell_path(), nullptr, &attributes,
                            const_cast<char**>(argv), environ)) != 0) {
     return -1;
   }
diff --git a/libc/include/android/legacy_signal_inlines.h b/libc/include/android/legacy_signal_inlines.h
index 8219759..5ca9813 100644
--- a/libc/include/android/legacy_signal_inlines.h
+++ b/libc/include/android/legacy_signal_inlines.h
@@ -52,7 +52,7 @@
 
 static __inline int __ndk_legacy___libc_current_sigrtmin() {
   if (__libc_current_sigrtmin) return __libc_current_sigrtmin();
-  return __SIGRTMIN + 5; /* Should match __libc_current_sigrtmin. */
+  return __SIGRTMIN + 6; /* Should match __libc_current_sigrtmin. */
 }
 
 #undef SIGRTMAX
diff --git a/libc/include/sys/param.h b/libc/include/sys/param.h
index 5cde4b7..79ae067 100644
--- a/libc/include/sys/param.h
+++ b/libc/include/sys/param.h
@@ -51,8 +51,19 @@
 #endif
 #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
 
-/** Returns true if the argument is a power of two. */
-#define powerof2(x) ((((x)-1)&(x))==0)
+/**
+ * Returns true if the binary representation of the argument is all zeros
+ * or has exactly one bit set. Contrary to the macro name, this macro
+ * DOES NOT determine if the provided value is a power of 2. In particular,
+ * this function falsely returns true for powerof2(0) and some negative
+ * numbers.
+ */
+#define powerof2(x)                                               \
+  ({                                                              \
+    __typeof__(x) _x = (x);                                       \
+    __typeof__(x) _x2;                                            \
+    __builtin_add_overflow(_x, -1, &_x2) ? 1 : ((_x2 & _x) == 0); \
+  })
 
 /** Returns the lesser of its two arguments. */
 #define MIN(a,b) (((a)<(b))?(a):(b))
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 7c802c2..b79c9b6 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -172,7 +172,12 @@
             dst_file = os.path.join(dst_dir, path)
             src_file = os.path.join(src_dir, path)
             new_data = cleanupFile(dst_file, src_file, path)
-            print new_data
+            # Use sys.stdout.write instead of a simple print statement to avoid
+            # sending an extra new line character to stdout.  Running this
+            # program in non-update mode and redirecting stdout to a file should
+            # yield the same result as using update mode, where new_data is
+            # written directly to a file.
+            sys.stdout.write(new_data)
 
         sys.exit(0)
 
@@ -187,8 +192,8 @@
         if not new_data:
             continue
 
-        b.readFile(path)
-        r = b.editFile(path, new_data)
+        b.readFile(dst_file)
+        r = b.editFile(dst_file, new_data)
         if r == 0:
             r = "unchanged"
         elif r == 1:
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index dd20b5c..dbd3eac 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -135,6 +135,9 @@
     {
         "abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
     },
+    {
+        "verbose", {VERBOSE, &Config::VerifyValueEmpty},
+    },
 };
 
 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 011dc77..1b5c748 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -45,6 +45,7 @@
 constexpr uint64_t RECORD_ALLOCS = 0x200;
 constexpr uint64_t BACKTRACE_FULL = 0x400;
 constexpr uint64_t ABORT_ON_ERROR = 0x800;
+constexpr uint64_t VERBOSE = 0x1000;
 
 // In order to guarantee posix compliance, set the minimum alignment
 // to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index 6c7d8fa..617d128 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -105,8 +105,10 @@
       error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
       return false;
     }
-    info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
-             config.backtrace_signal(), getpid());
+    if (config.options() & VERBOSE) {
+      info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
+               config.backtrace_signal(), getpid());
+    }
   }
 
   if (config.options() & BACKTRACE) {
@@ -117,8 +119,10 @@
       error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
       return false;
     }
-    info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
-             config.backtrace_dump_signal(), getpid());
+    if (config.options() & VERBOSE) {
+      info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+               config.backtrace_dump_signal(), getpid());
+    }
   }
 
   backtrace_dump_ = false;
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 93b9b1e..bebc1c1 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -401,6 +401,21 @@
 **NOTE**: If leak\_track is enabled, no abort occurs if leaks have been
 detected when the process is exiting.
 
+### verbose
+As of Android Q, all info messages will be turned off by default. For example,
+in Android P and older, enabling malloc debug would result in this message
+in the log:
+
+    08-16 15:54:16.060 26947 26947 I libc    : /system/bin/app_process64: malloc debug enabled
+
+In android Q, this message will not be displayed because these info messages
+slow down process start up. However, if you want to re-enable these messages,
+add the verbose option. All of the "Run XXX" messages are also silenced unless
+the verbose option is specified. This is an example of the type
+of messages that are no longer displayed:
+
+    09-10 01:03:50.070   557   557 I malloc_debug: /system/bin/audioserver: Run: 'kill -47 557' to dump the backtrace.
+
 Additional Errors
 -----------------
 There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index aea2513..5c550c0 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -181,8 +181,10 @@
   }
   pthread_setspecific(key_, nullptr);
 
-  info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
-           config.record_allocs_signal(), getpid());
+  if (config.options() & VERBOSE) {
+    info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
+             config.record_allocs_signal(), getpid());
+  }
 
   num_entries_ = config.record_allocs_num_entries();
   entries_ = new const RecordEntry*[num_entries_];
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 093bdee..1145796 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -30,6 +30,7 @@
 #include <inttypes.h>
 #include <malloc.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/cdefs.h>
 #include <sys/param.h>
@@ -252,6 +253,10 @@
   // of different error cases.
   backtrace_startup();
 
+  if (g_debug->config().options() & VERBOSE) {
+    info_log("%s: malloc debug enabled", getprogname());
+  }
+
   return true;
 }
 
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index fb54ee5..42d1415 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -743,3 +743,21 @@
       "which does not take a value\n");
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugConfigTest, verbose) {
+  ASSERT_TRUE(InitConfig("verbose")) << getFakeLogPrint();
+  ASSERT_EQ(VERBOSE, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_verbose_fail) {
+  ASSERT_FALSE(InitConfig("verbose=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'verbose' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index 4fcd04c..71e8ebf 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -195,7 +195,7 @@
 
 TEST(MallocDebugSystemTest, smoke) {
   pid_t pid;
-  ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "backtrace", &pid));
+  ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "verbose backtrace", &pid));
 
   ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
 }
@@ -399,7 +399,7 @@
     pid_t pid;
     SCOPED_TRACE(testing::Message() << functions[i].name << " expected size " << functions[i].size);
     std::string test = std::string("MallocTests.DISABLED_") + test_prefix + functions[i].name;
-    EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "backtrace leak_track", &pid));
+    EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "verbose backtrace leak_track", &pid));
 
     std::string expected_leak = android::base::StringPrintf("leaked block of size %zu at", functions[i].size);
     EXPECT_NO_FATAL_FAILURE(FindStrings(
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 66955db..f611f3d 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -154,7 +154,7 @@
   return diff;
 }
 
-void VerifyAllocCalls(bool backtrace_enabled) {
+void VerifyAllocCalls(bool all_options) {
   size_t alloc_size = 1024;
 
   // Verify debug_malloc.
@@ -209,21 +209,28 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log;
-  if (backtrace_enabled) {
+  if (all_options) {
+    expected_log += android::base::StringPrintf(
+        "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+        SIGRTMAX - 19, getpid());
     expected_log += android::base::StringPrintf(
         "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
         SIGRTMAX - 17, getpid());
+    expected_log += android::base::StringPrintf(
+        "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+        SIGRTMAX - 18, getpid());
   }
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, fill_generic) {
-  Init("fill");
+  Init("verbose fill");
   VerifyAllocCalls(false);
 }
 
 TEST_F(MallocDebugTest, fill_on_alloc_generic) {
-  Init("fill_on_alloc");
+  Init("verbose fill_on_alloc");
   VerifyAllocCalls(false);
 }
 
@@ -241,6 +248,46 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, verbose_only) {
+  Init("verbose");
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("4 malloc_debug malloc_testing: malloc debug enabled\n", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace_enable_on_signal) {
+  Init("verbose backtrace_enable_on_signal");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+      SIGRTMAX - 19, getpid());
+  expected_log += android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_backtrace) {
+  Init("verbose backtrace");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, verbose_record_allocs) {
+  Init("verbose record_allocs");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
+      SIGRTMAX - 18, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, fill_on_free) {
   Init("fill_on_free free_track free_track_backtrace_num_frames=0");
 
@@ -302,7 +349,9 @@
 }
 
 TEST_F(MallocDebugTest, all_options) {
-  Init("guard backtrace fill expand_alloc free_track leak_track");
+  Init(
+      "guard backtrace backtrace_enable_on_signal fill expand_alloc free_track leak_track "
+      "record_allocs verify_pointers abort_on_error verbose");
   VerifyAllocCalls(true);
 }
 
@@ -667,9 +716,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
       pointer3);
   expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
@@ -1096,10 +1142,7 @@
   ASSERT_EQ(0U, backtrace_size);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
@@ -1143,10 +1186,7 @@
   debug_free(pointer);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
@@ -1226,10 +1266,7 @@
   debug_free(pointers[2]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) {
@@ -1261,10 +1298,7 @@
   initialized = false;
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 static std::string SanitizeHeapData(const std::string& data) {
@@ -1375,9 +1409,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug Dumping to file: /data/local/tmp/backtrace_heap.%d.txt\n\n", getpid());
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
@@ -1649,13 +1680,7 @@
   debug_free_malloc_leak_info(info);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
-      SIGRTMAX - 19, getpid());
-  expected_log += android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack) {
@@ -1712,10 +1737,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack_zygote) {
@@ -1774,10 +1796,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_same_stack_mix_zygote) {
@@ -1844,10 +1863,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, backtrace_frame_data_nullptr_same_size) {
@@ -1891,10 +1907,7 @@
   debug_free(pointers[3]);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, overflow) {
@@ -2022,10 +2035,7 @@
   debug_free(pointer);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
-      SIGRTMAX - 17, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
 TEST_F(MallocDebugTest, max_size) {
@@ -2193,10 +2203,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2251,10 +2258,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2293,10 +2297,7 @@
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
-  std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
 
   debug_free(pointer);
 }
@@ -2348,9 +2349,6 @@
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
-      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
-      SIGRTMAX - 18, getpid());
-  expected_log += android::base::StringPrintf(
       "6 malloc_debug Cannot create record alloc file %s: Too many symbolic links encountered\n",
       RECORD_ALLOCS_FILE);
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
diff --git a/libc/private/__bionic_get_shell_path.h b/libc/private/__bionic_get_shell_path.h
new file mode 100644
index 0000000..171c14a
--- /dev/null
+++ b/libc/private/__bionic_get_shell_path.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+extern "C" const char* __bionic_get_shell_path();
diff --git a/libc/private/sigrtmin.h b/libc/private/sigrtmin.h
index 67bd864..d78d980 100644
--- a/libc/private/sigrtmin.h
+++ b/libc/private/sigrtmin.h
@@ -40,11 +40,12 @@
 //   34 (__SIGRTMIN + 2)        libcore
 //   35 (__SIGRTMIN + 3)        debuggerd -b
 //   36 (__SIGRTMIN + 4)        heapprofd
+//   37 (__SIGRTMIN + 5)        coverage (libprofile-extras)
 //
 // If you change this, also change __ndk_legacy___libc_current_sigrtmin
 // in <android/legacy_signal_inlines.h> to match.
 
-#define __SIGRT_RESERVED 5
+#define __SIGRT_RESERVED 6
 static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
   int (*block)(sigset64_t*, int);
   int (*unblock)(sigset64_t*, int);
@@ -70,5 +71,6 @@
   unblock(&sigset, __SIGRTMIN + 2);
   unblock(&sigset, __SIGRTMIN + 3);
   unblock(&sigset, __SIGRTMIN + 4);
+  unblock(&sigset, __SIGRTMIN + 5);
   return sigset;
 }
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 8144e5f..4cec757 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -52,6 +52,7 @@
 
 #include "local.h"
 #include "glue.h"
+#include "private/__bionic_get_shell_path.h"
 #include "private/bionic_fortify.h"
 #include "private/ErrnoRestorer.h"
 #include "private/thread_private.h"
@@ -290,7 +291,7 @@
     if (fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) return nullptr;
   }
 
-  // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'x'.
+  // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'e'.
   if ((mode_flags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
     fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
   }
@@ -1218,7 +1219,7 @@
     if (dup2(fds[child], desired_child_fd) == -1) _exit(127);
     close(fds[child]);
     if (bidirectional) dup2(STDOUT_FILENO, STDIN_FILENO);
-    execl(_PATH_BSHELL, "sh", "-c", cmd, nullptr);
+    execl(__bionic_get_shell_path(), "sh", "-c", cmd, nullptr);
     _exit(127);
   }
 
diff --git a/libc/symbol_ordering b/libc/symbol_ordering
index 6fcc09e..10245db 100644
--- a/libc/symbol_ordering
+++ b/libc/symbol_ordering
@@ -3,200 +3,209 @@
 # symbols by size, we usually have less dirty pages at runtime, because small
 # symbols are grouped together.
 
-_ZZ17__find_icu_symbolPKcE9found_icu
-_ZL24gHeapprofdInitInProgress
-_ZL27gHeapprofdInitHookInstalled
+ctl_initialized
+gGlobalsMutating
+global_hashtable_initialized
+gmtcheck.gmt_is_set
+had_conf_error
+je_background_thread_enabled_state
+je_log_init_done
 je_opt_abort
 je_opt_abort_conf
+je_opt_background_thread
 je_opt_junk_alloc
 je_opt_junk_free
+je_opt_stats_print
 je_opt_utrace
 je_opt_xmalloc
 je_opt_zero
+je_tsd_booted
 malloc_disabled_tcache
-had_conf_error
 malloc_slow_flags
-je_opt_background_thread
-ctl_initialized
-je_log_init_done
 mmap_flags
 os_overcommits
-je_opt_stats_print
-je_tsd_booted
-global_hashtable_initialized
-gmtcheck.gmt_is_set
 restartloop
-_ZZ12bindresvportE4port
-ru_counter
+_ZL24gHeapprofdInitInProgress
+_ZL27gHeapprofdInitHookInstalled
+_ZL29gMallocZygoteChildProfileable
+_ZZ17__find_icu_symbolPKcE9found_icu
 ru_a
-ru_x
 ru_b
-ru_seed
+ru_counter
 ru_g
-ru_seed2
 ru_msb
-je_narenas_auto
-je_ncpus
-je_init_system_thp_mode
-je_nhbins
-je_tsd_tsd
-optreset
-_rs_forked
-daylight
-gMallocLeakZygoteChild
-_ZL18netdClientInitOnce
-je_opt_narenas
-narenas_total
-je_malloc_disable.once_control
-je_opt_metadata_thp
-je_opt_thp
-stack_nelms
-tcaches_past
-ncleanups
-error_message_count
-error_one_per_line
-_ZZ13error_at_lineE9last_line
-_ZL13g_locale_once
-_ZL30g_propservice_protocol_version
-_res_cache_once
-_res_key
-_rs_forkdetect._rs_pid
-ru_pid
-lcl_is_set
-__cxa_finalize.call_depth
-seed48.sseed
-ether_aton.addr
-je_background_thread_info
-je_malloc_message
-je_tcache_bin_info
-je_tcache_maxclass
-je_tcaches
-optarg
-suboptarg
-timezone
-_ZGVZ17__find_icu_symbolPKcE9found_icu
-_ZL17g_libicuuc_handle
-__malloc_hook
-__realloc_hook
-__free_hook
-__memalign_hook
-je_malloc_conf
-malloc_initializer
+ru_seed
+ru_seed2
+ru_x
+_ZZ12bindresvportE4port
 a0
-je_opt_dirty_decay_ms
-je_opt_muzzy_decay_ms
-dirty_decay_ms_default.0
-muzzy_decay_ms_default.0
+__atexit
+atexit_mutex
 b0
 ctl_arenas
 ctl_stats
-je_hooks_arena_new_hook
-os_page
-tcaches_avail
-_ZN9prop_area8pa_size_E
-_ZN9prop_area13pa_data_size_E
-_ZL6g_lock
-_ZL6g_tags
-_ZZ8c16rtombE15__private_state
-_ZZ8c32rtombE15__private_state
+__cxa_finalize.call_depth
+daylight
+dirty_decay_ms_default.0
 environ
+error_message_count
+error_one_per_line
 error_print_progname
-_ZZ13error_at_lineE9last_file
-_ZZ14__icu_charTypejE10u_charType
-_ZGVZ14__icu_charTypejE10u_charType
-_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
-_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
-__progname
-_ZZ8mbrtoc16E15__private_state
-_ZZ8mbrtoc32E15__private_state
-_ZL14syslog_log_tag
-__system_property_area__
-_ZZ7mbrtowcE15__private_state
-_ZZ10mbsnrtowcsE15__private_state
-_ZZ7wcrtombE15__private_state
-_ZZ10wcsnrtombsE15__private_state
-_ZZ8iswcntrlE10u_charType
-_ZGVZ8iswcntrlE10u_charType
-_ZZ8iswdigitE9u_isdigit
-_ZGVZ8iswdigitE9u_isdigit
-_ZZ8iswpunctE9u_ispunct
-_ZGVZ8iswpunctE9u_ispunct
-_ZZ8towlowerE9u_tolower
-_ZGVZ8towlowerE9u_tolower
-_ZZ8towupperE9u_toupper
-_ZGVZ8towupperE9u_toupper
+__free_hook
+g_atexit_lock
+gGlobalsMutateLock
 global_hashtable
+gMallocLeakZygoteChild
+gmtptr
 handlers
-p5s
-ut
-rs
-rsx
+je_background_thread_info
+je_hooks_arena_new_hook
+je_init_system_thp_mode
+je_malloc_conf
+je_malloc_disable.once_control
+je_malloc_message
+je_narenas_auto
+je_ncpus
+je_nhbins
+je_opt_dirty_decay_ms
+je_opt_metadata_thp
+je_opt_muzzy_decay_ms
+je_opt_narenas
+je_opt_thp
+je_tcache_bin_info
+je_tcache_maxclass
+je_tcaches
+je_tsd_tsd
+lastenv
+lcl_is_set
+lclptr
+locallock
+malloc_disabled_lock
+__malloc_hook
+malloc_initializer
 mbrlen.mbs
 mbtowc.mbs
-wctomb.mbs
-ru_reseed
+__memalign_hook
+muzzy_decay_ms_default.0
+narenas_total
+ncleanups
+optarg
+optreset
+os_page
+p5s
+__progname
+random_mutex
+__realloc_hook
+_res_cache_list_lock
+_res_cache_once
+_res_key
+__res_randomid.__libc_mutex_random
+rs
+_rs_forkdetect._rs_pid
+_rs_forked
+rsx
+ru_pid
 ru_prf
-tmpnam.tmpcount
-lastenv
-strtok.last
+ru_reseed
 __stack_chk_guard
-lclptr
-gmtptr
-_ZGVZ14tzset_unlockedE20persist_sys_timezone
+stack_nelms
+strtok.last
+suboptarg
+__system_property_area__
+tcaches_avail
+tcaches_past
+timezone
+tmpnam.tmpcount
+ut
+wctomb.mbs
+_ZL11g_arc4_lock
+_ZL13g_locale_once
 _ZL13g_thread_list
-__atexit
+_ZL14syslog_log_tag
+_ZL16gHeapprofdHandle
+_ZL17g_libicuuc_handle
+_ZL18netdClientInitOnce
+_ZL30g_propservice_protocol_version
+_ZN9prop_area13pa_data_size_E
+_ZN9prop_area8pa_size_E
+_ZZ10mbsnrtowcsE15__private_state
+_ZZ10wcsnrtombsE15__private_state
+_ZZ13error_at_lineE9last_file
+_ZZ13error_at_lineE9last_line
+_ZZ14__icu_charTypejE10u_charType
+_ZZ23__bionic_get_shell_pathE7sh_path
+_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZZ7mbrtowcE15__private_state
+_ZZ7wcrtombE15__private_state
+_ZZ8c16rtombE15__private_state
+_ZZ8c32rtombE15__private_state
+_ZZ8iswcntrlE10u_charType
+_ZZ8iswdigitE9u_isdigit
+_ZZ8iswpunctE9u_ispunct
+_ZZ8mbrtoc16E15__private_state
+_ZZ8mbrtoc32E15__private_state
+_ZZ8towlowerE9u_tolower
+_ZZ8towupperE9u_toupper
+ether_aton.addr
+seed48.sseed
+__dtoa_locks
+_ZGVZ14__icu_charTypejE10u_charType
+_ZGVZ14tzset_unlockedE20persist_sys_timezone
+_ZGVZ17__find_icu_symbolPKcE9found_icu
+_ZGVZ23__bionic_get_shell_pathE7sh_path
+_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZGVZ8iswcntrlE10u_charType
+_ZGVZ8iswdigitE9u_isdigit
+_ZGVZ8iswpunctE9u_ispunct
+_ZGVZ8towlowerE9u_tolower
+_ZGVZ8towupperE9u_toupper
+_ZL10gAllocated
+_ZL11gAllocLimit
+_ZL13g_atfork_list
+_ZL6g_lock
+_ZL6g_tags
 je_opt_stats_print_opts
 nuls
 precsize_ntoa.retbuf
 __p_secstodate.output
-_ZL13g_atfork_list
-inet_ntoa.b
 ether_ntoa.buf
-__sym_ntos.unname
-__sym_ntop.unname
-__p_type.typebuf
+inet_ntoa.b
 __p_class.classbuf
-malloc_disabled_lock
-_ZL11g_arc4_lock
-_res_cache_list_lock
+__p_type.typebuf
+__sym_ntop.unname
+__sym_ntos.unname
+_ZL10gFunctions
+_ZL12vendor_group
+_ZL13vendor_passwd
+freelist
 __p_option.nbuf
 __p_time.nbuf
-atexit_mutex
-random_mutex
-__res_randomid.__libc_mutex_random
-locallock
-g_atexit_lock
-_ZL10gFunctions
-_ZL13vendor_passwd
-_ZL12vendor_group
-tm
 _ZL18g_thread_list_lock
-buf_asctime
-__dtoa_locks
-freelist
-__loc_ntoa.tmpbuf
+tm
 _ZL8g_locale
+ctl_mtx
+init_lock
 je_arenas_lock
 je_background_thread_lock
-init_lock
-ctl_mtx
 tcaches_mtx
 je_tsd_init_head
+buf_asctime
+__loc_ntoa.tmpbuf
+utmp
 _ZZ14tzset_unlockedE20persist_sys_timezone
 arena_binind_div_info
 __hexdig_D2A
 lcl_TZname
-utmp
 inet_nsap_ntoa_tmpbuf
-_ZL17system_properties
 _ZL7key_map
+_ZL17system_properties
 private_mem
+_res_cache_list
 __libc_globals
 tmpnam.buf
-_res_cache_list
-_nres
-je_extent_mutex_pool
-je_arenas
 je_extents_rtree
+_nres
+je_arenas
+je_extent_mutex_pool
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 0e9a7d3..41eaa9b 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -172,6 +172,12 @@
                 return (NULL);
             break;
 
+        case 'F':  /* The date as "%Y-%m-%d". */
+            _LEGAL_ALT(0);
+            if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
+                return (NULL);
+            continue;
+
         case 'R':   /* The time as "%H:%M". */
             _LEGAL_ALT(0);
             if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -190,6 +196,12 @@
                 return (NULL);
             break;
 
+        case 'v':  /* The date as "%e-%b-%Y". */
+            _LEGAL_ALT(0);
+            if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
+                return (NULL);
+            break;
+
         case 'X':   /* The time, using the locale's format. */
             _LEGAL_ALT(_ALT_E);
             if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
@@ -305,6 +317,7 @@
             tm->tm_mon--;
             break;
 
+        case 'P':
         case 'p':   /* The locale's equivalent of AM/PM. */
             _LEGAL_ALT(0);
             /* AM? */
@@ -377,6 +390,33 @@
                 return (NULL);
             break;
 
+        case 'u':  /* The day of week, monday = 1. */
+            _LEGAL_ALT(_ALT_O);
+            if (!(_conv_num(&bp, &i, 1, 7)))
+                return (NULL);
+            tm->tm_wday = i % 7;
+            continue;
+
+        case 'g':  /* The year corresponding to the ISO week
+                    * number but without the century.
+                    */
+            if (!(_conv_num(&bp, &i, 0, 99)))
+                return (NULL);
+            continue;
+
+        case 'G':  /* The year corresponding to the ISO week
+                    * number with century.
+                    */
+            do
+                bp++;
+            while (isdigit(*bp));
+            continue;
+
+        case 'V':  /* The ISO 8601:1988 week number as decimal */
+            if (!(_conv_num(&bp, &i, 0, 53)))
+                return (NULL);
+            continue;
+
         case 'Y':   /* The year. */
             _LEGAL_ALT(_ALT_E);
             if (!(_conv_num(&bp, &i, 0, 9999)))
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 2e171d6..a41aa2d 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -110,6 +110,72 @@
     },
 }
 
+cc_library {
+    name: "libdl_android",
+
+    defaults: ["linux_bionic_supported"],
+
+    // NOTE: --exclude-libs=libgcc.a makes sure that any symbols libdl.so pulls from
+    // libgcc.a are made static to libdl.so.  This in turn ensures that libraries that
+    // a) pull symbols from libgcc.a and b) depend on libdl.so will not rely on libdl.so
+    // to provide those symbols, but will instead pull them from libgcc.a.  Specifically,
+    // we use this property to make sure libc.so has its own copy of the code from
+    // libgcc.a it uses.
+    //
+    // DO NOT REMOVE --exclude-libs!
+
+    ldflags: [
+        "-Wl,--exclude-libs=libgcc.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-x86-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+    ],
+
+    // for x86, exclude libgcc_eh.a for the same reasons as above
+    arch: {
+        x86: {
+            ldflags: [
+                "-Wl,--exclude-libs=libgcc_eh.a",
+            ],
+        },
+        x86_64: {
+            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+        },
+    },
+
+    srcs: [ "libdl_android.cpp" ],
+    version_script: "libdl_android.map.txt",
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wunused",
+        "-Werror",
+    ],
+
+    stl: "none",
+
+    nocrt: true,
+    system_shared_libs: [],
+
+    // Opt out of native_coverage when opting out of system_shared_libs
+    native_coverage: false,
+
+    // This is placeholder library the actual implementation is (currently)
+    // provided by the linker.
+    shared_libs: ["ld-android"],
+
+    sanitize: {
+        never: true,
+    },
+
+    stubs: {
+        symbol_file: "libdl_android.map.txt",
+        versions: ["10000"],
+    },
+}
+
 ndk_library {
     name: "libdl",
     symbol_file: "libdl.map.txt",
diff --git a/libdl/libdl.cpp b/libdl/libdl.cpp
index a468f81..1ee4012 100644
--- a/libdl/libdl.cpp
+++ b/libdl/libdl.cpp
@@ -25,6 +25,9 @@
 extern "C" {
 
 __attribute__((__weak__, visibility("default")))
+void __loader_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size);
+
+__attribute__((__weak__, visibility("default")))
 void* __loader_dlopen(const char* filename, int flags, const void* caller_addr);
 
 __attribute__((__weak__, visibility("default")))
@@ -67,39 +70,15 @@
                                   const void* caller_addr);
 
 __attribute__((__weak__, visibility("default")))
-void __loader_android_set_application_target_sdk_version(int target);
-
-__attribute__((__weak__, visibility("default")))
 int __loader_android_get_application_target_sdk_version();
 
-__attribute__((__weak__, visibility("default")))
-bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
-                                               const char* library_search_path);
-
-__attribute__((__weak__, visibility("default")))
-struct android_namespace_t* __loader_android_create_namespace(
-                                const char* name,
-                                const char* ld_library_path,
-                                const char* default_library_path,
-                                uint64_t type,
-                                const char* permitted_when_isolated_path,
-                                struct android_namespace_t* parent,
-                                const void* caller_addr);
-
-__attribute__((__weak__, visibility("default")))
-bool __loader_android_link_namespaces(
-                                struct android_namespace_t* namespace_from,
-                                struct android_namespace_t* namespace_to,
-                                const char* shared_libs_sonames);
-
-__attribute__((__weak__, visibility("default")))
-void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
-
-__attribute__((__weak__, visibility("default")))
-struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
-
 // Proxy calls to bionic loader
 __attribute__((__weak__))
+void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
+  __loader_android_get_LD_LIBRARY_PATH(buffer, buffer_size);
+}
+
+__attribute__((__weak__))
 void* dlopen(const char* filename, int flag) {
   const void* caller_addr = __builtin_return_address(0);
   return __loader_dlopen(filename, flag, caller_addr);
@@ -149,71 +128,16 @@
 }
 
 __attribute__((__weak__))
-void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
-  __loader_android_get_LD_LIBRARY_PATH(buffer, buffer_size);
-}
-
-__attribute__((__weak__))
-void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
-  __loader_android_update_LD_LIBRARY_PATH(ld_library_path);
-}
-
-__attribute__((__weak__))
 void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo) {
   const void* caller_addr = __builtin_return_address(0);
   return __loader_android_dlopen_ext(filename, flag, extinfo, caller_addr);
 }
 
 __attribute__((__weak__))
-void android_set_application_target_sdk_version(int target) {
-  __loader_android_set_application_target_sdk_version(target);
-}
-
-__attribute__((__weak__))
 int android_get_application_target_sdk_version() {
   return __loader_android_get_application_target_sdk_version();
 }
 
-__attribute__((__weak__))
-bool android_init_anonymous_namespace(const char* shared_libs_sonames,
-                                      const char* library_search_path) {
-  return __loader_android_init_anonymous_namespace(shared_libs_sonames, library_search_path);
-}
-
-__attribute__((__weak__))
-struct android_namespace_t* android_create_namespace(const char* name,
-                                                     const char* ld_library_path,
-                                                     const char* default_library_path,
-                                                     uint64_t type,
-                                                     const char* permitted_when_isolated_path,
-                                                     struct android_namespace_t* parent) {
-  const void* caller_addr = __builtin_return_address(0);
-  return __loader_android_create_namespace(name,
-                                           ld_library_path,
-                                           default_library_path,
-                                           type,
-                                           permitted_when_isolated_path,
-                                           parent,
-                                           caller_addr);
-}
-
-__attribute__((__weak__))
-bool android_link_namespaces(struct android_namespace_t* namespace_from,
-                             struct android_namespace_t* namespace_to,
-                             const char* shared_libs_sonames) {
-  return __loader_android_link_namespaces(namespace_from, namespace_to, shared_libs_sonames);
-}
-
-__attribute__((__weak__))
-void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
-  __loader_android_dlwarning(obj, f);
-}
-
-__attribute__((__weak__))
-struct android_namespace_t* android_get_exported_namespace(const char* name) {
-  return __loader_android_get_exported_namespace(name);
-}
-
 #if defined(__arm__)
 // An arm32 unwinding table has an R_ARM_NONE relocation to
 // __aeabi_unwind_cpp_pr0. This shared library will never invoke the unwinder,
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 1514827..473bdf2 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -41,19 +41,8 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
-LIBC_Q { # introduced=29
-  global:
-    android_create_namespace; # apex
-    android_dlwarning; # apex
-    android_get_LD_LIBRARY_PATH; # apex
-    android_get_exported_namespace; # apex
-    android_init_anonymous_namespace; # apex
-    android_link_namespaces; # apex
-    android_set_application_target_sdk_version; # apex
-} LIBC_OMR1;
-
 LIBC_PLATFORM {
   global:
+    android_get_LD_LIBRARY_PATH;
     __cfi_init;
-    android_update_LD_LIBRARY_PATH;
-} LIBC_Q;
+} LIBC_OMR1;
diff --git a/libdl/libdl_android.cpp b/libdl/libdl_android.cpp
new file mode 100644
index 0000000..9ad8250
--- /dev/null
+++ b/libdl/libdl_android.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 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 <dlfcn.h>
+#include <link.h>
+#include <stdlib.h>
+#include <android/dlext.h>
+
+// These functions are exported by the loader
+// TODO(dimitry): replace these with reference to libc.so
+
+extern "C" {
+
+__attribute__((__weak__, visibility("default")))
+void __loader_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size);
+
+__attribute__((__weak__, visibility("default")))
+    void __loader_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
+
+__attribute__((__weak__, visibility("default")))
+void __loader_android_set_application_target_sdk_version(int target);
+
+__attribute__((__weak__, visibility("default")))
+bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
+                                               const char* library_search_path);
+
+__attribute__((__weak__, visibility("default")))
+struct android_namespace_t* __loader_android_create_namespace(
+                                const char* name,
+                                const char* ld_library_path,
+                                const char* default_library_path,
+                                uint64_t type,
+                                const char* permitted_when_isolated_path,
+                                struct android_namespace_t* parent,
+                                const void* caller_addr);
+
+__attribute__((__weak__, visibility("default")))
+bool __loader_android_link_namespaces(
+                                struct android_namespace_t* namespace_from,
+                                struct android_namespace_t* namespace_to,
+                                const char* shared_libs_sonames);
+
+__attribute__((__weak__, visibility("default")))
+void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
+
+__attribute__((__weak__, visibility("default")))
+struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
+
+// Proxy calls to bionic loader
+__attribute__((__weak__))
+void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
+  __loader_android_get_LD_LIBRARY_PATH(buffer, buffer_size);
+}
+
+__attribute__((__weak__))
+void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
+  __loader_android_update_LD_LIBRARY_PATH(ld_library_path);
+}
+
+__attribute__((__weak__))
+void android_set_application_target_sdk_version(int target) {
+  __loader_android_set_application_target_sdk_version(target);
+}
+
+__attribute__((__weak__))
+bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+                                      const char* library_search_path) {
+  return __loader_android_init_anonymous_namespace(shared_libs_sonames, library_search_path);
+}
+
+__attribute__((__weak__))
+struct android_namespace_t* android_create_namespace(const char* name,
+                                                     const char* ld_library_path,
+                                                     const char* default_library_path,
+                                                     uint64_t type,
+                                                     const char* permitted_when_isolated_path,
+                                                     struct android_namespace_t* parent) {
+  const void* caller_addr = __builtin_return_address(0);
+  return __loader_android_create_namespace(name,
+                                           ld_library_path,
+                                           default_library_path,
+                                           type,
+                                           permitted_when_isolated_path,
+                                           parent,
+                                           caller_addr);
+}
+
+__attribute__((__weak__))
+bool android_link_namespaces(struct android_namespace_t* namespace_from,
+                             struct android_namespace_t* namespace_to,
+                             const char* shared_libs_sonames) {
+  return __loader_android_link_namespaces(namespace_from, namespace_to, shared_libs_sonames);
+}
+
+__attribute__((__weak__))
+void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
+  __loader_android_dlwarning(obj, f);
+}
+
+__attribute__((__weak__))
+struct android_namespace_t* android_get_exported_namespace(const char* name) {
+  return __loader_android_get_exported_namespace(name);
+}
+
+#if defined(__arm__)
+// An arm32 unwinding table has an R_ARM_NONE relocation to
+// __aeabi_unwind_cpp_pr0. This shared library will never invoke the unwinder,
+// so it doesn't actually need the routine. Define a dummy version here,
+// because the real version calls libc functions (e.g. memcpy, abort), which
+// would create a dependency cycle with libc.so.
+__attribute__((visibility("hidden")))
+void __aeabi_unwind_cpp_pr0() {
+  __builtin_trap();
+}
+#endif
+
+} // extern "C"
diff --git a/libdl/libdl_android.map.txt b/libdl/libdl_android.map.txt
new file mode 100644
index 0000000..7afcd9c
--- /dev/null
+++ b/libdl/libdl_android.map.txt
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LIBDL_ANDROID {
+  global:
+    android_create_namespace; # apex
+    android_dlwarning; # apex
+    android_get_LD_LIBRARY_PATH; # apex
+    android_update_LD_LIBRARY_PATH;
+    android_get_exported_namespace; # apex
+    android_init_anonymous_namespace; # apex
+    android_link_namespaces; # apex
+    android_set_application_target_sdk_version; # apex
+  local:
+    *;
+};
diff --git a/linker/linker.cpp b/linker/linker.cpp
index c60ab6a..306b800 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3987,7 +3987,7 @@
   /* Handle serializing/sharing the RELRO segment */
   if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
     if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
-                                       extinfo->relro_fd) < 0) {
+                                       extinfo->relro_fd, relro_fd_offset) < 0) {
       DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
              get_realpath(), strerror(errno));
       return false;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1aaa17f..3534287 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -831,16 +831,17 @@
  *   phdr_count  -> number of entries in tables
  *   load_bias   -> load bias
  *   fd          -> writable file descriptor to use
+ *   file_offset -> pointer to offset into file descriptor to use/update
  * Return:
  *   0 on error, -1 on failure (error code in errno).
  */
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
                                    size_t phdr_count,
                                    ElfW(Addr) load_bias,
-                                   int fd) {
+                                   int fd,
+                                   size_t* file_offset) {
   const ElfW(Phdr)* phdr = phdr_table;
   const ElfW(Phdr)* phdr_limit = phdr + phdr_count;
-  ssize_t file_offset = 0;
 
   for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
     if (phdr->p_type != PT_GNU_RELRO) {
@@ -856,11 +857,11 @@
       return -1;
     }
     void* map = mmap(reinterpret_cast<void*>(seg_page_start), size, PROT_READ,
-                     MAP_PRIVATE|MAP_FIXED, fd, file_offset);
+                     MAP_PRIVATE|MAP_FIXED, fd, *file_offset);
     if (map == MAP_FAILED) {
       return -1;
     }
-    file_offset += size;
+    *file_offset += size;
   }
   return 0;
 }
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 9761bc8..5d1cfc2 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -119,7 +119,7 @@
                                  ElfW(Addr) load_bias);
 
 int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
-                                   ElfW(Addr) load_bias, int fd);
+                                   ElfW(Addr) load_bias, int fd, size_t* file_offset);
 
 int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count,
                              ElfW(Addr) load_bias, int fd, size_t* file_offset);
diff --git a/tests/Android.bp b/tests/Android.bp
index c200ef4..3d5feb2 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -159,6 +159,7 @@
         "sys_epoll_test.cpp",
         "sys_mman_test.cpp",
         "sys_msg_test.cpp",
+        "sys_param_test.cpp",
         "sys_personality_test.cpp",
         "sys_prctl_test.cpp",
         "sys_procfs_test.cpp",
@@ -431,6 +432,11 @@
 cc_defaults {
     name: "bionic_unit_tests_defaults",
     host_supported: false,
+    gtest: false,
+
+    defaults: [
+        "bionic_tests_defaults",
+    ],
 
     whole_static_libs: [
         "libBionicTests",
@@ -442,12 +448,14 @@
         "libtinyxml2",
         "liblog",
         "libbase",
+        "libgtest_isolated",
     ],
 
     srcs: [
         // TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
         "__cxa_thread_atexit_test.cpp",
         "gtest_globals.cpp",
+        "gtest_main.cpp",
         "thread_local_test.cpp",
     ],
 
@@ -466,7 +474,9 @@
         android: {
             shared_libs: [
                 "ld-android",
+                "libandroidicu",
                 "libdl",
+                "libdl_android",
                 "libdl_preempt_test_1",
                 "libdl_preempt_test_2",
                 "libdl_test_df_1_global",
@@ -493,29 +503,6 @@
             ],
         },
     },
-}
-
-cc_test {
-    name: "bionic-unit-tests",
-    gtest: false,
-    defaults: [
-        "bionic_unit_tests_defaults",
-        "bionic_tests_defaults",
-    ],
-
-    srcs: [
-        "gtest_main.cpp",
-    ],
-
-    static_libs: [
-        "libgtest_isolated",
-    ],
-
-    target: {
-        android: {
-            shared_libs: ["libandroidicu"],
-        },
-    },
 
     required: [
         "cfi_test_helper",
@@ -660,6 +647,24 @@
     ],
 }
 
+cc_test {
+    name: "bionic-unit-tests",
+    defaults: [
+        "bionic_unit_tests_defaults",
+    ],
+}
+
+cc_test {
+    name: "bionic-unit-tests-scudo",
+    defaults: [
+        "bionic_unit_tests_defaults",
+    ],
+
+    shared_libs: [
+        "libc_scudo",
+    ],
+}
+
 // -----------------------------------------------------------------------------
 // Tests for the device linked against bionic's static library. Run with:
 //   adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
@@ -702,10 +707,6 @@
 
     static_executable: true,
     stl: "libc++_static",
-
-    // libclang_rt.builtins does not work with libm
-    // http://b/117167374
-    no_libcrt: true,
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/__aeabi_read_tp_test.cpp b/tests/__aeabi_read_tp_test.cpp
index 6974658..7209a75 100644
--- a/tests/__aeabi_read_tp_test.cpp
+++ b/tests/__aeabi_read_tp_test.cpp
@@ -38,6 +38,6 @@
 #if defined(__arm__)
   ASSERT_EQ(__aeabi_read_tp(), static_cast<void*>(__get_tls()));
 #else
-  GTEST_LOG_(INFO) << "__aeabi_read_tp is only available on arm32.\n";
+  GTEST_SKIP() << "__aeabi_read_tp is only available on arm32";
 #endif
 }
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
index 4940e3a..6c4758e 100644
--- a/tests/async_safe_test.cpp
+++ b/tests/async_safe_test.cpp
@@ -104,7 +104,7 @@
   async_safe_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
   EXPECT_STREQ("a68719476736,6,7,8z", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -114,7 +114,7 @@
   async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
   EXPECT_STREQ("2147483647", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -124,7 +124,7 @@
   async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
   EXPECT_STREQ("-2147483648", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -138,7 +138,7 @@
   EXPECT_STREQ("2147483647", buf);
 #endif
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -152,7 +152,7 @@
   EXPECT_STREQ("-2147483648", buf);
 #endif
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -162,7 +162,7 @@
   async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
   EXPECT_STREQ("9223372036854775807", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -172,7 +172,7 @@
   async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
   EXPECT_STREQ("-9223372036854775808", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -196,6 +196,6 @@
   ASSERT_EQ(4, async_safe_format_buffer(buf, 2, "xxxx"));
   EXPECT_STREQ("x", buf);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index 468ce3d..9e46394 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -138,7 +138,7 @@
 
 TEST(dl, preinit_system_calls) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array, b/124007027
+  SKIP_WITH_HWASAN << "hwasan not initialized in preinit_array, b/124007027";
   std::string helper = GetTestlibRoot() +
       "/preinit_syscall_test_helper/preinit_syscall_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
@@ -150,7 +150,7 @@
 
 TEST(dl, preinit_getauxval) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // hwasan not initialized in preinit_array, b/124007027
+  SKIP_WITH_HWASAN << "hwasan not initialized in preinit_array, b/124007027";
   std::string helper = GetTestlibRoot() +
       "/preinit_getauxval_test_helper/preinit_getauxval_test_helper";
   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
@@ -242,7 +242,7 @@
 // whose search paths include the 'ns2/' subdir.
 TEST(dl, exec_with_ld_config_file) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
+  SKIP_WITH_HWASAN << "libclang_rt.hwasan is not found with custom ld config";
   if (!is_debuggable_build()) {
     // LD_CONFIG_FILE is not supported on user build
     return;
@@ -265,7 +265,7 @@
 // additional namespaces other than the default namespace.
 TEST(dl, exec_with_ld_config_file_with_ld_preload) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // libclang_rt.hwasan is not found with custom ld config
+  SKIP_WITH_HWASAN << "libclang_rt.hwasan is not found with custom ld config";
   if (!is_debuggable_build()) {
     // LD_CONFIG_FILE is not supported on user build
     return;
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index f5e0c9c..3af52d4 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -67,7 +67,7 @@
 
 class DlExtTest : public ::testing::Test {
 protected:
-  virtual void SetUp() {
+  void SetUp() override {
     handle_ = nullptr;
     // verify that we don't have the library loaded already
     void* h = dlopen(kLibName, RTLD_NOW | RTLD_NOLOAD);
@@ -78,7 +78,7 @@
     ASSERT_EQ(std::string("dlopen failed: library \"") + kLibNameNoRelro + "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     if (handle_ != nullptr) {
       ASSERT_DL_ZERO(dlclose(handle_));
     }
@@ -418,7 +418,7 @@
 
 class DlExtRelroSharingTest : public DlExtTest {
 protected:
-  virtual void SetUp() {
+  void SetUp() override {
     DlExtTest::SetUp();
     void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     ASSERT_TRUE(start != MAP_FAILED);
@@ -428,7 +428,7 @@
     extinfo_.relro_fd = -1;
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     DlExtTest::TearDown();
   }
 
@@ -450,7 +450,21 @@
         fprintf(stderr, "in child: %s\n", dlerror());
         exit(1);
       }
-      exit(0);
+      fn f = reinterpret_cast<fn>(dlsym(handle, "getRandomNumber"));
+      ASSERT_DL_NOTNULL(f);
+      EXPECT_EQ(4, f());
+
+      if (recursive) {
+        fn f = reinterpret_cast<fn>(dlsym(handle, "getBiggerRandomNumber"));
+        ASSERT_DL_NOTNULL(f);
+        EXPECT_EQ(8, f());
+      }
+
+      uint32_t* taxicab_number =
+              reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
+      ASSERT_DL_NOTNULL(taxicab_number);
+      EXPECT_EQ(1729U, *taxicab_number);
+      exit(testing::Test::HasFailure());
     }
 
     // continuing in parent
@@ -540,10 +554,7 @@
 }
 
 TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
-  if (geteuid() != 0) {
-    GTEST_LOG_(INFO) << "This test must be run as root.\n";
-    return;
-  }
+  if (geteuid() != 0) GTEST_SKIP() << "This test must be run as root";
 
   TemporaryFile tf; // Use tf to get an unique filename.
   ASSERT_NOERROR(close(tf.fd));
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index ff5b1a9..f3be988 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -260,8 +260,7 @@
 TEST(dlfcn, dlopen_vdso) {
 #if __has_include(<sys/auxv.h>)
   if (getauxval(AT_SYSINFO_EHDR) == 0) {
-    GTEST_LOG_(INFO) << "getauxval(AT_SYSINFO_EHDR) == 0, skipping this test.";
-    return;
+    GTEST_SKIP() << "getauxval(AT_SYSINFO_EHDR) == 0, skipping this test";
   }
 #endif
 
@@ -976,9 +975,9 @@
 #if defined(__BIONIC__)
   ASSERT_EQ(handle1, handle2);
 #else
-  GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
-                      "it loads a separate copy of the main executable "
-                      "on dlopen by absolute path.";
+  GTEST_SKIP() << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
+                  "it loads a separate copy of the main executable "
+                  "on dlopen by absolute path";
 #endif
 }
 
@@ -1003,7 +1002,10 @@
 #define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
 
 TEST(dlfcn, dladdr_libc) {
-#if defined(__BIONIC__)
+#if defined(__GLIBC__)
+  GTEST_SKIP() << "glibc returns libc.so's ldconfig path, which is a symlink (not a realpath)";
+#endif
+
   Dl_info info;
   void* addr = reinterpret_cast<void*>(puts); // well-known libc function
   ASSERT_TRUE(dladdr(addr, &info) != 0);
@@ -1025,10 +1027,6 @@
   // TODO: add check for dfi_fbase
   ASSERT_STREQ("puts", info.dli_sname);
   ASSERT_EQ(addr, info.dli_saddr);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
-      "for libc.so, which is symlink itself (not a realpath).\n";
-#endif
 }
 
 TEST(dlfcn, dladdr_invalid) {
@@ -1066,7 +1064,7 @@
   ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
   ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
+  GTEST_SKIP() << "mips toolchain does not support '--hash-style=gnu'";
 #endif
 }
 
@@ -1184,13 +1182,13 @@
 // that calls dlopen(libc...). This is to test the situation
 // described in b/7941716.
 TEST(dlfcn, dlopen_dlopen_from_ctor) {
-#if defined(__BIONIC__)
+#if defined(__GLIBC__)
+  GTEST_SKIP() << "glibc segfaults if you try to call dlopen from a constructor";
+#endif
+
   void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
   dlclose(handle);
-#else
-  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
-#endif
 }
 
 static std::string g_fini_call_order_str;
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
index 36bdc3b..88225d8 100644
--- a/tests/elftls_dl_test.cpp
+++ b/tests/elftls_dl_test.cpp
@@ -146,7 +146,7 @@
     ASSERT_EQ(nullptr, missing_weak_dyn_tls_addr());
   }).join();
 #else
-  GTEST_LOG_(INFO) << "This test is only run on TLSDESC-based targets.\n";
+  GTEST_SKIP() << "This test is only run on TLSDESC-based targets";
 #endif
 }
 
@@ -215,7 +215,7 @@
 
 #undef LOAD_LIB
 #else
-  GTEST_LOG_(INFO) << "This test is skipped for glibc because it tests Bionic internals.";
+  GTEST_SKIP() << "test doesn't apply to glibc";
 #endif
 }
 
@@ -266,6 +266,6 @@
     dlclose(lib);
   }
 #else
-  GTEST_LOG_(INFO) << "This test is skipped for glibc because it tests Bionic internals.";
+  GTEST_SKIP() << "test doesn't apply to glibc";
 #endif
 }
diff --git a/tests/endian_test.cpp b/tests/endian_test.cpp
index 85d56f0..3d6dc4d 100644
--- a/tests/endian_test.cpp
+++ b/tests/endian_test.cpp
@@ -46,7 +46,7 @@
   ASSERT_EQ(be32, htonl(le32));
   ASSERT_EQ(be64, htonq(le64));
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have these macros";
+  GTEST_SKIP() << "glibc doesn't have htons/htonl/htonq in <endian.h>";
 #endif
 }
 
@@ -56,7 +56,7 @@
   ASSERT_EQ(le32, ntohl(be32));
   ASSERT_EQ(le64, ntohq(be64));
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have these macros";
+  GTEST_SKIP() << "glibc doesn't have ntohs/ntohl/ntohq in <endian.h>";
 #endif
 }
 
@@ -90,7 +90,7 @@
   ASSERT_EQ(le32, betoh32(be32));
   ASSERT_EQ(le64, betoh64(be64));
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have these macros";
+  GTEST_SKIP() << "glibc doesn't have betoh16/betoh32/betoh64";
 #endif
 }
 
@@ -100,6 +100,6 @@
   ASSERT_EQ(le32, letoh32(le32));
   ASSERT_EQ(le64, letoh64(le64));
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have these macros";
+  GTEST_SKIP() << "glibc doesn't have letoh16/letoh32/letoh64";
 #endif
 }
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index bc33251..489b701 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -143,7 +143,7 @@
   ASSERT_FORTIFY(stpcpy(myfoo.empty, src));
   free(src);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "stpcpy not available";
 #endif // __BIONIC__
 }
 
@@ -155,7 +155,7 @@
   ASSERT_FORTIFY(strcpy(myfoo.empty, src));
   free(src);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -167,7 +167,7 @@
   ASSERT_FORTIFY(strcpy(myfoo.empty, src));
   free(src);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -179,7 +179,7 @@
   ASSERT_FORTIFY(strcpy(myfoo.one, src));
   free(src);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -191,7 +191,7 @@
   ASSERT_FORTIFY(printf("%s", strchr(myfoo.a, 'a')));
   ASSERT_FORTIFY(printf("%s", strchr(static_cast<const char*>(myfoo.a), 'a')));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -203,7 +203,7 @@
   ASSERT_FORTIFY(printf("%s", strrchr(myfoo.a, 'a')));
   ASSERT_FORTIFY(printf("%s", strrchr(static_cast<const char*>(myfoo.a), 'a')));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -215,7 +215,7 @@
   ASSERT_FORTIFY(printf("%s", memchr(myfoo.a, 'a', asize)));
   ASSERT_FORTIFY(printf("%s", memchr(static_cast<const void*>(myfoo.a), 'a', asize)));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -227,7 +227,7 @@
   ASSERT_FORTIFY(printf("%s", memrchr(myfoo.a, 'a', asize)));
   ASSERT_FORTIFY(printf("%s", memrchr(static_cast<const void*>(myfoo.a), 'a', asize)));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -238,7 +238,7 @@
   size_t n = strlen(myfoo.a);
   ASSERT_FORTIFY(strlcpy(myfoo.one, myfoo.a, n));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "strlcpy not available";
 #endif // __BIONIC__
 }
 
@@ -250,7 +250,7 @@
   size_t n = strlen(myfoo.a);
   ASSERT_FORTIFY(strlcat(myfoo.one, myfoo.a, n));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "strlcat not available";
 #endif // __BIONIC__
 }
 
@@ -315,7 +315,7 @@
   ASSERT_FORTIFY(strcpy(buf, orig));
   free(orig);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -327,7 +327,7 @@
   ASSERT_FORTIFY(strcpy(buf, orig));
   free(orig);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -339,7 +339,7 @@
   ASSERT_FORTIFY(strcpy(buf, orig));
   free(orig);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -351,7 +351,7 @@
   ASSERT_FORTIFY(strcpy(buf, orig));
   free(orig);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -361,7 +361,7 @@
   memcpy(buf, "0123456789", sizeof(buf));
   ASSERT_FORTIFY(printf("%zd", strlen(buf)));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -371,7 +371,7 @@
   memcpy(buf, "0123456789", sizeof(buf));
   ASSERT_FORTIFY(printf("%s", strchr(buf, 'a')));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -381,7 +381,7 @@
   memcpy(buf, "0123456789", sizeof(buf));
   ASSERT_FORTIFY(printf("%s", strrchr(buf, 'a')));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif // __BIONIC__
 }
 
@@ -393,7 +393,7 @@
   size_t n = strlen(bufa);
   ASSERT_FORTIFY(strlcpy(bufb, bufa, n));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "strlcpy not available";
 #endif // __BIONIC__
 }
 
@@ -406,7 +406,7 @@
   size_t n = strlen(bufa);
   ASSERT_FORTIFY(strlcat(bufb, bufa, n));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "strlcat not available";
 #endif // __BIONIC__
 }
 
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
index aa21817..f4ec7f5 100644
--- a/tests/getauxval_test.cpp
+++ b/tests/getauxval_test.cpp
@@ -61,5 +61,5 @@
     return;
   }
 #endif
-  GTEST_LOG_(INFO) << "This test is only meaningful for 32-bit ARM code on 64-bit devices.\n";
+  GTEST_SKIP() << "This test is only meaningful for 32-bit ARM code on 64-bit devices";
 }
diff --git a/tests/getcwd_test.cpp b/tests/getcwd_test.cpp
index 791ffae..97b1d4f 100644
--- a/tests/getcwd_test.cpp
+++ b/tests/getcwd_test.cpp
@@ -51,7 +51,7 @@
 }
 
 TEST(getcwd, auto_too_large) {
-  SKIP_WITH_HWASAN; // allocation size too large
+  SKIP_WITH_HWASAN << "allocation size too large";
   // If we ask the library to allocate an unreasonably large buffer, ERANGE.
   errno = 0;
   char* cwd = getcwd(nullptr, static_cast<size_t>(-1));
diff --git a/tests/grp_pwd_file_test.cpp b/tests/grp_pwd_file_test.cpp
index 66866fb..adcdbd6 100644
--- a/tests/grp_pwd_file_test.cpp
+++ b/tests/grp_pwd_file_test.cpp
@@ -103,7 +103,7 @@
   EXPECT_FALSE(passwd_file.FindById(3, nullptr));
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -123,7 +123,7 @@
   EXPECT_FALSE(group_file.FindById(3, nullptr));
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -161,7 +161,7 @@
   EXPECT_FALSE(passwd_file.FindById(50, nullptr));
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -197,7 +197,7 @@
   EXPECT_FALSE(group_file.FindById(799, nullptr));
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -219,7 +219,7 @@
   FindAndCheckPasswdEntry(&passwd_file, "vendor_name", 3, 4, "dir", "shell");
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -241,6 +241,6 @@
   FindAndCheckGroupEntry(&group_file, "vendor_name", 2);
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index eb8fe2a..b46839b 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -138,17 +138,13 @@
 
 #else // !defined(__BIONIC__)
 
-static void print_no_getpwnam_test_info() {
-  GTEST_LOG_(INFO) << "This test is about uid/username translation for Android, which does nothing on libc other than bionic.\n";
-}
-
 static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */,
                              bool /* check_username */) {
-  print_no_getpwnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 }
 
 static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */) {
-  print_no_getpwnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 }
 
 #endif
@@ -311,7 +307,7 @@
 
   expect_ids(uids);
 #else
-  print_no_getpwnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -382,16 +378,12 @@
 
 #else // !defined(__BIONIC__)
 
-static void print_no_getgrnam_test_info() {
-  GTEST_LOG_(INFO) << "This test is about gid/group_name translation for Android, which does nothing on libc other than bionic.\n";
-}
-
 static void check_get_group(const char*, gid_t, bool) {
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 }
 
 static void check_get_group(const char*, gid_t) {
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 }
 
 #endif
@@ -501,7 +493,7 @@
   check_group(grp[0], "root", 0);
   check_group(grp[1], "system", 1000);
 #else
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -521,7 +513,7 @@
   check_group(grp[0], "root", 0);
   check_group(grp[1], "system", 1000);
 #else
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -561,7 +553,7 @@
 
   expect_ids(gids);
 #else
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -590,7 +582,7 @@
 
   TestAidNamePrefix("/vendor/etc/passwd");
 #else
-  print_no_getpwnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -602,6 +594,6 @@
 
   TestAidNamePrefix("/vendor/etc/group");
 #else
-  print_no_getgrnam_test_info();
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
diff --git a/tests/libgen_test.cpp b/tests/libgen_test.cpp
index d5b5eb6..24f7923 100644
--- a/tests/libgen_test.cpp
+++ b/tests/libgen_test.cpp
@@ -78,7 +78,7 @@
   TestBasename(".", ".", 1, buf, sizeof(buf), 0);
   TestBasename("..", "..", 2, buf, sizeof(buf), 0);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "basename_r is only available on 32-bit bionic";
 #endif // __BIONIC__
 }
 
@@ -95,6 +95,6 @@
   TestDirname(".", ".", 1, buf, sizeof(buf), 0);
   TestDirname("..", ".", 1, buf, sizeof(buf), 0);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "dirname_r is only available on 32-bit bionic";
 #endif // __BIONIC__
 }
diff --git a/tests/link_test.cpp b/tests/link_test.cpp
index 1bdee9f..cf5fc0b 100644
--- a/tests/link_test.cpp
+++ b/tests/link_test.cpp
@@ -231,6 +231,6 @@
   }
   ASSERT_TRUE(found);
 #else
-  GTEST_LOG_(INFO) << "dl_unwind_find_exidx is an ARM-only API\n";
+  GTEST_SKIP() << "dl_unwind_find_exidx is an ARM-only API";
 #endif
 }
diff --git a/tests/malloc_iterate_test.cpp b/tests/malloc_iterate_test.cpp
index 76583eb..9d4fe04 100644
--- a/tests/malloc_iterate_test.cpp
+++ b/tests/malloc_iterate_test.cpp
@@ -150,7 +150,7 @@
 
   FreePtrs(&test_data);
 #else
-  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -169,7 +169,7 @@
 
   FreePtrs(&test_data);
 #else
-  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -193,7 +193,7 @@
 
   ASSERT_EQ(0UL, test_data.total_allocated_bytes);
 #else
-  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -222,6 +222,6 @@
   ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid.";
   ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls.";
 #else
-  GTEST_LOG_(INFO) << "Skipping, this is a bionic only test.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 8d5db54..706de15 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -94,7 +94,7 @@
 }
 
 TEST(malloc, memalign_multiple) {
-  SKIP_WITH_HWASAN; // hwasan requires power of 2 alignment.
+  SKIP_WITH_HWASAN << "hwasan requires power of 2 alignment";
   // Memalign test where the alignment is any value.
   for (size_t i = 0; i <= 12; i++) {
     for (size_t alignment = 1 << i; alignment < (1U << (i+1)); alignment++) {
@@ -532,24 +532,24 @@
 
 TEST(malloc, mallopt_decay) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // hwasan does not implement mallopt
+  SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
   errno = 0;
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1));
   ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0));
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
 TEST(malloc, mallopt_purge) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // hwasan does not implement mallopt
+  SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
   errno = 0;
   ASSERT_EQ(1, mallopt(M_PURGE, 0));
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -567,7 +567,7 @@
   ASSERT_TRUE(reallocarray(nullptr, b, a) == nullptr);
   ASSERT_EQ(ENOMEM, errno);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
+  GTEST_SKIP() << "reallocarray not available";
 #endif
 }
 
@@ -577,13 +577,13 @@
   ASSERT_TRUE(p != nullptr);
   ASSERT_GE(malloc_usable_size(p), 64U);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with reallocarray.\n";
+  GTEST_SKIP() << "reallocarray not available";
 #endif
 }
 
 TEST(malloc, mallinfo) {
 #if defined(__BIONIC__)
-  SKIP_WITH_HWASAN; // hwasan does not implement mallinfo
+  SKIP_WITH_HWASAN << "hwasan does not implement mallinfo";
   static size_t sizes[] = {
     8, 32, 128, 4096, 32768, 131072, 1024000, 10240000, 20480000, 300000000
   };
@@ -622,7 +622,7 @@
         << kMaxAllocs << " allocations.";
   }
 #else
-  GTEST_LOG_(INFO) << "Host glibc does not pass this test, skipping.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif
 }
 
@@ -633,7 +633,7 @@
   EXPECT_EQ(false, android_mallopt(unrecognized_option, nullptr, 0));
   EXPECT_EQ(ENOTSUP, errno);
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -679,7 +679,7 @@
     EXPECT_EQ(ENOTSUP, errno);
   }
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -728,7 +728,7 @@
               testing::ExitedWithCode(0), "");
 #endif
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
 
@@ -740,7 +740,7 @@
   limit = 32 * 1024 * 1024;
   ASSERT_FALSE(android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &limit, sizeof(limit)));
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
 
@@ -805,7 +805,7 @@
 
   VerifyMaxPointers(max_pointers);
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
 
@@ -833,7 +833,7 @@
 
   VerifyMaxPointers(max_pointers);
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
 
@@ -853,7 +853,7 @@
 
   VerifyMaxPointers(max_pointers);
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
 
@@ -915,6 +915,6 @@
     ASSERT_EQ(0, WEXITSTATUS(status));
   }
 #else
-  GTEST_LOG_(INFO) << "This tests a bionic extension.\n";
+  GTEST_SKIP() << "bionic extension";
 #endif
 }
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index f816fad..1dd45b4 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -388,7 +388,7 @@
   ASSERT_TRUE(__isnormal(123.0));
   ASSERT_FALSE(__isnormal(double_subnormal()));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have __isnormal.\n";
+  GTEST_SKIP() << "glibc doesn't have __isnormal";
 #endif // __BIONIC__
 }
 
@@ -397,7 +397,7 @@
   ASSERT_TRUE(__isnormalf(123.0f));
   ASSERT_FALSE(__isnormalf(float_subnormal()));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have __isnormalf.\n";
+  GTEST_SKIP() << "glibc doesn't have __isnormalf";
 #endif // __BIONIC__
 }
 
@@ -406,7 +406,7 @@
   ASSERT_TRUE(isnormalf(123.0f));
   ASSERT_FALSE(isnormalf(float_subnormal()));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have isnormalf.\n";
+  GTEST_SKIP() << "glibc doesn't have isnormalf";
 #endif // __BIONIC__
 }
 
@@ -415,7 +415,7 @@
   ASSERT_TRUE(__isnormall(123.0L));
   ASSERT_FALSE(__isnormall(ldouble_subnormal()));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have __isnormall.\n";
+  GTEST_SKIP() << "glibc doesn't have __isnormall";
 #endif // __BIONIC__
 }
 
@@ -424,7 +424,7 @@
   ASSERT_TRUE(isnormall(123.0L));
   ASSERT_FALSE(isnormall(ldouble_subnormal()));
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have isnormall.\n";
+  GTEST_SKIP() << "glibc doesn't have isnormall";
 #endif // __BIONIC__
 }
 
@@ -1396,7 +1396,7 @@
   ASSERT_DOUBLE_EQ(log(24.0), gamma_r(5.0, &sign));
   ASSERT_EQ(1, sign);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have gamma_r.\n";
+  GTEST_SKIP() << "glibc doesn't have gamma_r";
 #endif // __BIONIC__
 }
 
@@ -1406,7 +1406,7 @@
   ASSERT_FLOAT_EQ(logf(24.0f), gammaf_r(5.0f, &sign));
   ASSERT_EQ(1, sign);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "glibc doesn't have gammaf_r.\n";
+  GTEST_SKIP() << "glibc doesn't have gammaf_r";
 #endif // __BIONIC__
 }
 
diff --git a/tests/membarrier_test.cpp b/tests/membarrier_test.cpp
index 9e871c7..6f650e7 100644
--- a/tests/membarrier_test.cpp
+++ b/tests/membarrier_test.cpp
@@ -46,8 +46,7 @@
 
 TEST(membarrier, global_barrier) {
   if (!HasMembarrier(MEMBARRIER_CMD_GLOBAL)) {
-    GTEST_LOG_(INFO) << "MEMBARRIER_CMD_GLOBAL not supported, skipping test.";
-    return;
+    GTEST_SKIP() << "MEMBARRIER_CMD_GLOBAL not supported";
   }
   ASSERT_EQ(0, syscall(__NR_membarrier, MEMBARRIER_CMD_GLOBAL, 0));
 }
@@ -78,14 +77,10 @@
 static void TestRegisterAndBarrierCommands(int membarrier_cmd_register,
                                            int membarrier_cmd_barrier) {
   if (!HasMembarrier(membarrier_cmd_register)) {
-    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register)
-        << " not supported, skipping test.";
-    return;
+    GTEST_SKIP() << MembarrierCommandToName(membarrier_cmd_register) << " not supported";
   }
   if (!HasMembarrier(membarrier_cmd_barrier)) {
-    GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier)
-        << " not supported, skipping test.";
-    return;
+    GTEST_SKIP() << MembarrierCommandToName(membarrier_cmd_barrier) << " not supported";
   }
 
   ScopedErrnoCleaner errno_cleaner;
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 973ca53..7b64401 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -190,7 +190,7 @@
   ASSERT_EQ(EINVAL, pthread_setspecific(key, nullptr));
   ASSERT_EQ(EINVAL, pthread_key_delete(key));
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic pthread key implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -986,8 +986,7 @@
   test_pthread_rwlock_reader_wakeup_writer(
       [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedwrlock_monotonic_np(lock, &ts); });
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
-                      "only supported on bionic";
+  GTEST_SKIP() << "pthread_rwlock_timedwrlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1035,8 +1034,7 @@
   test_pthread_rwlock_writer_wakeup_reader(
       [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedrdlock_monotonic_np(lock, &ts); });
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
-                      "only supported on bionic";
+  GTEST_SKIP() << "pthread_rwlock_timedrdlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1096,8 +1094,7 @@
   pthread_rwlock_timedrdlock_timeout_helper(CLOCK_MONOTONIC,
                                             pthread_rwlock_timedrdlock_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
-                      "only supported on bionic";
+  GTEST_SKIP() << "pthread_rwlock_timedrdlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1133,8 +1130,7 @@
   pthread_rwlock_timedwrlock_timeout_helper(CLOCK_MONOTONIC,
                                             pthread_rwlock_timedwrlock_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
-                      "only supported on bionic";
+  GTEST_SKIP() << "pthread_rwlock_timedwrlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1364,7 +1360,7 @@
   ASSERT_EQ(0, pthread_condattr_getpshared(&attr, &pshared));
   ASSERT_EQ(PTHREAD_PROCESS_SHARED, pshared);
 #else  // !defined(__BIONIC__)
-  GTEST_LOG_(INFO) << "This tests a bionic implementation detail.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // !defined(__BIONIC__)
 }
 
@@ -1480,8 +1476,7 @@
   progress = SIGNALED;
   ASSERT_EQ(0, pthread_cond_signal(&cond));
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
-                      "supported on bionic";
+  GTEST_SKIP() << "pthread_cond_timedwait_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1516,8 +1511,7 @@
 #if defined(__BIONIC__)
   pthread_cond_timedwait_timeout_helper(CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
-                      "supported on bionic";
+  GTEST_SKIP() << "pthread_cond_timedwait_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -1739,7 +1733,7 @@
 
   ASSERT_EQ(t_gettid_result, t_pthread_gettid_np_result);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "pthread_gettid_np not available";
 #endif
 }
 
@@ -1934,7 +1928,7 @@
   }
   ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
 #else
-  GTEST_LOG_(INFO) << "This test does nothing as pi mutex count isn't limited.\n";
+  GTEST_SKIP() << "pi mutex count not limited to 64Ki";
 #endif
 }
 
@@ -2121,7 +2115,7 @@
   // Bionic's pthread_mutex implementation on 32-bit devices uses 16 bits to represent owner tid.
   ASSERT_LE(pid_max, 65536);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing as 32-bit tid is supported by pthread_mutex.\n";
+  GTEST_SKIP() << "pthread_mutex supports 32-bit tid";
 #endif
 }
 
@@ -2164,8 +2158,7 @@
 #if defined(__BIONIC__)
   pthread_mutex_timedlock_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
-                      "supported on bionic";
+  GTEST_SKIP() << "pthread_mutex_timedlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -2216,8 +2209,7 @@
 #if defined(__BIONIC__)
   pthread_mutex_timedlock_pi_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
-                      "supported on bionic";
+  GTEST_SKIP() << "pthread_mutex_timedlock_monotonic_np not available";
 #endif  // __BIONIC__
 }
 
@@ -2240,7 +2232,7 @@
   ASSERT_EXIT(pthread_mutex_destroy(&m), ::testing::KilledBySignal(SIGABRT),
               "pthread_mutex_destroy called on a destroyed mutex");
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic pthread mutex implementation details.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -2297,7 +2289,7 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(rwlock));
 
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic implementation details.";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -2312,7 +2304,7 @@
   pthread_mutex_t* null_value = nullptr;
   ASSERT_EQ(EINVAL, pthread_mutex_lock(null_value));
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+  GTEST_SKIP() << "32-bit bionic-only test";
 #endif
 }
 
@@ -2327,7 +2319,7 @@
   pthread_mutex_t* null_value = nullptr;
   ASSERT_EQ(EINVAL, pthread_mutex_unlock(null_value));
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+  GTEST_SKIP() << "32-bit bionic-only test";
 #endif
 }
 
@@ -2336,7 +2328,7 @@
   pthread_mutex_t* null_value = nullptr;
   ASSERT_EXIT(pthread_mutex_lock(null_value), testing::KilledBySignal(SIGSEGV), "");
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+  GTEST_SKIP() << "64-bit bionic-only test";
 #endif
 }
 
@@ -2345,7 +2337,7 @@
   pthread_mutex_t* null_value = nullptr;
   ASSERT_EXIT(pthread_mutex_unlock(null_value), testing::KilledBySignal(SIGSEGV), "");
 #else
-  GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+  GTEST_SKIP() << "64-bit bionic-only test";
 #endif
 }
 
@@ -2658,10 +2650,7 @@
 TEST(pthread, pthread_attr_setinheritsched_PTHREAD_INHERIT_SCHED_takes_effect) {
   sched_param param = { .sched_priority = sched_get_priority_min(SCHED_FIFO) };
   int rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
-  if (rc == EPERM) {
-    GTEST_LOG_(INFO) << "pthread_setschedparam failed with EPERM, skipping test\n";
-    return;
-  }
+  if (rc == EPERM) GTEST_SKIP() << "pthread_setschedparam failed with EPERM";
   ASSERT_EQ(0, rc);
 
   pthread_attr_t attr;
@@ -2682,10 +2671,7 @@
 TEST(pthread, pthread_attr_setinheritsched_PTHREAD_EXPLICIT_SCHED_takes_effect) {
   sched_param param = { .sched_priority = sched_get_priority_min(SCHED_FIFO) };
   int rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
-  if (rc == EPERM) {
-    GTEST_LOG_(INFO) << "pthread_setschedparam failed with EPERM, skipping test\n";
-    return;
-  }
+  if (rc == EPERM) GTEST_SKIP() << "pthread_setschedparam failed with EPERM";
   ASSERT_EQ(0, rc);
 
   pthread_attr_t attr;
@@ -2707,10 +2693,7 @@
 TEST(pthread, pthread_attr_setinheritsched__takes_effect_despite_SCHED_RESET_ON_FORK) {
   sched_param param = { .sched_priority = sched_get_priority_min(SCHED_FIFO) };
   int rc = pthread_setschedparam(pthread_self(), SCHED_FIFO | SCHED_RESET_ON_FORK, &param);
-  if (rc == EPERM) {
-    GTEST_LOG_(INFO) << "pthread_setschedparam failed with EPERM, skipping test\n";
-    return;
-  }
+  if (rc == EPERM) GTEST_SKIP() << "pthread_setschedparam failed with EPERM";
   ASSERT_EQ(0, rc);
 
   pthread_attr_t attr;
diff --git a/tests/pty_test.cpp b/tests/pty_test.cpp
index 75f228c..29f86f1 100644
--- a/tests/pty_test.cpp
+++ b/tests/pty_test.cpp
@@ -109,8 +109,7 @@
   cpu_set_t cpus;
   ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
   if (CPU_COUNT(&cpus) < 2) {
-    GTEST_LOG_(INFO) << "This test tests bug happens only on multiprocessors.";
-    return;
+    GTEST_SKIP() << "This bug only happens on multiprocessors";
   }
   constexpr uint32_t TEST_DATA_COUNT = 2000000;
 
diff --git a/tests/run-on-host.sh b/tests/run-on-host.sh
index c47bc4f..c8a30f5 100755
--- a/tests/run-on-host.sh
+++ b/tests/run-on-host.sh
@@ -3,32 +3,33 @@
 . $(dirname $0)/../build/run-on-host.sh
 
 if [ "$1" = glibc ]; then
-    m -j bionic-unit-tests-glibc
-    (
-        cd ${ANDROID_BUILD_TOP}
-        export ANDROID_DATA=${TARGET_OUT_DATA}
-        export ANDROID_ROOT=${TARGET_OUT}
-        ${HOST_OUT}/nativetest64/bionic-unit-tests-glibc/bionic-unit-tests-glibc $@
-    )
-    exit 0
+  shift
+  m -j bionic-unit-tests-glibc
+  (
+    cd ${ANDROID_BUILD_TOP}
+    export ANDROID_DATA=${TARGET_OUT_DATA}
+    export ANDROID_ROOT=${TARGET_OUT}
+    ${HOST_OUT}/nativetest64/bionic-unit-tests-glibc/bionic-unit-tests-glibc $@
+  )
+  exit 0
 elif [ "$1" != 32 -a "$1" != 64 ]; then
-    echo "Usage: $0 [ 32 | 64 | glibc ] [gtest flags]"
-    exit 1
+  echo "Usage: $0 [ 32 | 64 | glibc ] [gtest flags]"
+  exit 1
 fi
 
 if [ ${HOST_OS}-${HOST_ARCH} = linux-x86 -o ${HOST_OS}-${HOST_ARCH} = linux-x86_64 ]; then
 
-    prepare $1 bionic-unit-tests
+  prepare $1 bionic-unit-tests
 
-    if [ ${TARGET_ARCH} = x86 -o ${TARGET_ARCH} = x86_64 ]; then
-        (
-            cd ${ANDROID_BUILD_TOP}
-            export ANDROID_DATA=${TARGET_OUT_DATA}
-            export ANDROID_DNS_MODE=local
-            export ANDROID_ROOT=${TARGET_OUT}
-            ${NATIVETEST}/bionic-unit-tests/bionic-unit-tests $@
-        )
-    else
-        echo "$0 not supported on TARGET_ARCH=$TARGET_ARCH"
-    fi
+  if [ ${TARGET_ARCH} = x86 -o ${TARGET_ARCH} = x86_64 ]; then
+    (
+      cd ${ANDROID_BUILD_TOP}
+      export ANDROID_DATA=${TARGET_OUT_DATA}
+      export ANDROID_DNS_MODE=local
+      export ANDROID_ROOT=${TARGET_OUT}
+      ${NATIVETEST}/bionic-unit-tests/bionic-unit-tests $@
+    )
+  else
+    echo "$0 not supported on TARGET_ARCH=$TARGET_ARCH"
+  fi
 fi
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index 9184026..9309a7f 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -47,7 +47,7 @@
 // See https://sourceware.org/bugzilla/show_bug.cgi?id=10311 for more details.
 TEST(sched, clone) {
   // In order to enumerate all possible tests for CTS, create an empty test.
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc is broken";
 }
 #endif
 
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 690e886..7addf6d 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -141,8 +141,7 @@
 #if defined(__BIONIC__)
   sem_timedwait_helper(CLOCK_MONOTONIC, sem_timedwait_monotonic_np);
 #else   // __BIONIC__
-  GTEST_LOG_(INFO)
-      << "This test does nothing since sem_timedwait_monotonic_np is only supported on bionic";
+  GTEST_SKIP() << "sem_timedwait_monotonic_np is only supported on bionic";
 #endif  // __BIONIC__
 }
 
@@ -218,7 +217,7 @@
   ASSERT_EQ(0, pthread_join(thread, &result));
   ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(result));
 #else
-  GTEST_LOG_(INFO) << "This test tests sem_wait's compatibility for old sdk versions";
+  GTEST_SKIP() << "This test tests sem_wait's compatibility for old sdk versions";
 #endif
 }
 
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 77b004f..1ae174a 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -582,7 +582,7 @@
   ASSERT_TRUE(sys_signame[0] == nullptr);
   ASSERT_STREQ("HUP", sys_signame[SIGHUP]);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "glibc doesn't have sys_signame";
 #endif
 }
 
diff --git a/tests/stack_protector_test.cpp b/tests/stack_protector_test.cpp
index 7a85cc3..9fe7bb1 100644
--- a/tests/stack_protector_test.cpp
+++ b/tests/stack_protector_test.cpp
@@ -95,7 +95,7 @@
   ASSERT_NE(0, gettid());
   ASSERT_NE(0U, __stack_chk_guard);
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have a global __stack_chk_guard.\n";
+  GTEST_SKIP() << "glibc doesn't have a global __stack_chk_guard";
 #endif
 }
 
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index d84fda0..fce600a 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -193,7 +193,7 @@
 
 TEST(stdio_ext, __fseterr) {
 #if defined(__GLIBC__)
-  GTEST_LOG_(INFO) << "glibc doesn't have __fseterr, but gnulib will use it";
+  GTEST_SKIP() << "glibc doesn't have __fseterr, but gnulib will use it";
 #else
   FILE* fp = fopen("/dev/null", "w");
 
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index ad6ed45..65a942c 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -330,7 +330,7 @@
   int i = 1234;
   EXPECT_DEATH(snprintf(buf, sizeof(buf), "a %n b", &i), "%n not allowed on Android");
 #else
-  GTEST_LOG_(INFO) << "This test does nothing on glibc.\n";
+  GTEST_SKIP() << "glibc does allow %n";
 #endif
 }
 
@@ -1897,7 +1897,7 @@
   ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
   ASSERT_EQ(EINVAL, errno);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing on glibc.\n";
+  GTEST_SKIP() << "glibc is broken";
 #endif
 }
 
@@ -2157,7 +2157,7 @@
 
   fclose(fp);
 #else
-  GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
+  GTEST_SKIP() << "glibc uses fopencookie instead";
 #endif
 }
 
@@ -2167,7 +2167,7 @@
   ASSERT_EQ(nullptr, funopen(nullptr, nullptr, nullptr, nullptr, nullptr));
   ASSERT_EQ(EINVAL, errno);
 #else
-  GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
+  GTEST_SKIP() << "glibc uses fopencookie instead";
 #endif
 }
 
@@ -2195,7 +2195,7 @@
   EXPECT_EQ(0, fgetpos64(fp64, &pos64)) << strerror(errno);
   EXPECT_EQ(0xfedcba12345678, pos64);
 #else
-  GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n";
+  GTEST_SKIP() << "glibc uses fopencookie instead";
 #endif
 }
 
@@ -2234,7 +2234,7 @@
   EXPECT_EQ(offset, static_cast<off64_t>(pos));
   EXPECT_EQ(offset, static_cast<off64_t>(pos64));
 #else
-  GTEST_LOG_(INFO) << "glibc's fpos_t is opaque.\n";
+  GTEST_SKIP() << "glibc's fpos_t is opaque";
 #endif
 }
 
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index b27ca87..335d33b 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -85,7 +85,7 @@
 
   ASSERT_STREQ("Unknown error 1001", strerror1001);
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "Skipping test, requires a thread safe strerror.";
+  GTEST_SKIP() << "thread-safe strerror not available";
 #endif // __BIONIC__
 }
 
@@ -578,7 +578,7 @@
     }
   }
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform.";
+  GTEST_SKIP() << "strlcat not available";
 #endif
 }
 
@@ -610,7 +610,7 @@
                  (memcmp(state.ptr2, state.ptr + state.MAX_LEN, state.MAX_LEN) != 0));
   }
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform.";
+  GTEST_SKIP() << "strlcpy not available";
 #endif
 }
 
@@ -1139,7 +1139,7 @@
 #if defined(STRLCPY_SUPPORTED)
   RunSrcDstBufferAlignTest(LARGE, DoStrlcpyTest);
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform.";
+  GTEST_SKIP() << "strlcpy not available";
 #endif
 }
 
@@ -1147,7 +1147,7 @@
 #if defined(STRLCPY_SUPPORTED)
   RunSrcDstBufferOverreadTest(DoStrlcpyTest);
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcpy not supported on this platform.";
+  GTEST_SKIP() << "strlcpy not available";
 #endif
 }
 
@@ -1275,7 +1275,7 @@
 #if defined(STRLCAT_SUPPORTED)
   RunSrcDstBufferAlignTest(MEDIUM, DoStrlcatTest, LargeSetIncrement);
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform.";
+  GTEST_SKIP() << "strlcat not available";
 #endif
 }
 
@@ -1283,7 +1283,7 @@
 #if defined(STRLCAT_SUPPORTED)
   RunSrcDstBufferOverreadTest(DoStrlcatTest);
 #else
-  GTEST_LOG_(INFO) << "Skipping test, strlcat not supported on this platform.";
+  GTEST_SKIP() << "strlcat not available";
 #endif
 }
 
diff --git a/tests/sys_msg_test.cpp b/tests/sys_msg_test.cpp
index 8b3623e..200f654 100644
--- a/tests/sys_msg_test.cpp
+++ b/tests/sys_msg_test.cpp
@@ -35,8 +35,7 @@
 
 TEST(sys_msg, smoke) {
   if (msgctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
-    GTEST_LOG_(INFO) << "no <sys/msg.h> support in this kernel\n";
-    return;
+    GTEST_SKIP() << "no <sys/msg.h> support in this kernel";
   }
 
   // Create a queue.
diff --git a/tests/sys_param_test.cpp b/tests/sys_param_test.cpp
new file mode 100644
index 0000000..e4bbf42
--- /dev/null
+++ b/tests/sys_param_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <sys/param.h>
+
+TEST(sys_param_test, powerof2_positives) {
+  ASSERT_TRUE(powerof2(1));
+  ASSERT_TRUE(powerof2(2));
+  ASSERT_TRUE(powerof2(4));
+  ASSERT_TRUE(powerof2(8));
+  ASSERT_FALSE(powerof2(3));
+  ASSERT_FALSE(powerof2(5));
+  ASSERT_FALSE(powerof2(7));
+  ASSERT_FALSE(powerof2(9));
+  ASSERT_FALSE(powerof2(10));
+}
+
+TEST(sys_param_test, powerof2_zero) {
+  // 0 isn't a power of 2, but for compatibility, we assume it is.
+  ASSERT_TRUE(powerof2(0));
+  uint32_t zero = 0;
+  ASSERT_TRUE(powerof2(zero));
+}
+
+TEST(sys_param_test, powerof2_negatives) {
+  // negative numbers can never be a power of 2, but for compatibility,
+  // we assume they can be.
+  int32_t min32 = INT32_MIN;
+  int64_t min64 = INT64_MIN;
+  ASSERT_TRUE(powerof2(min32));
+  ASSERT_FALSE(powerof2(min32 + 1));
+  ASSERT_TRUE(powerof2(min64));
+  ASSERT_FALSE(powerof2(min64 + 1));
+}
diff --git a/tests/sys_prctl_test.cpp b/tests/sys_prctl_test.cpp
index cd23c0a..6d1fa1d 100644
--- a/tests/sys_prctl_test.cpp
+++ b/tests/sys_prctl_test.cpp
@@ -61,7 +61,7 @@
 
   ASSERT_EQ(0, munmap(p, page_size * 3));
 #else
-  GTEST_LOG_(INFO) << "This test does nothing as it tests an Android specific kernel feature.";
+  GTEST_SKIP() << "PR_SET_VMA not available";
 #endif
 }
 
@@ -112,7 +112,6 @@
   EXPECT_EQ(-1, err);
   EXPECT_EQ(EINVAL, errno);
 #else
-  GTEST_LOG_(INFO)
-      << "Skipping test that requires host support for PR_CAP_AMBIENT.";
+  GTEST_SKIP() << "PR_CAP_AMBIENT not available";
 #endif
 }
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index 04dcd4e..90539fe 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -62,14 +62,13 @@
 
 enum class HwFeature { Watchpoint, Breakpoint };
 
-static bool is_hw_feature_supported(pid_t child, HwFeature feature) {
+static void check_hw_feature_supported(pid_t child, HwFeature feature) {
 #if defined(__arm__)
   long capabilities;
   long result = ptrace(PTRACE_GETHBPREGS, child, 0, &capabilities);
   if (result == -1) {
     EXPECT_EQ(EIO, errno);
-    GTEST_LOG_(INFO) << "Hardware debug support disabled at kernel configuration time.";
-    return false;
+    GTEST_SKIP() << "Hardware debug support disabled at kernel configuration time";
   }
   uint8_t hb_count = capabilities & 0xff;
   capabilities >>= 8;
@@ -77,19 +76,12 @@
   capabilities >>= 8;
   uint8_t max_wp_size = capabilities & 0xff;
   if (max_wp_size == 0) {
-    GTEST_LOG_(INFO)
-        << "Kernel reports zero maximum watchpoint size. Hardware debug support missing.";
-    return false;
+    GTEST_SKIP() << "Kernel reports zero maximum watchpoint size";
+  } else if (feature == HwFeature::Watchpoint && wp_count == 0) {
+    GTEST_SKIP() << "Kernel reports zero hardware watchpoints";
+  } else if (feature == HwFeature::Breakpoint && hb_count == 0) {
+    GTEST_SKIP() << "Kernel reports zero hardware breakpoints";
   }
-  if (feature == HwFeature::Watchpoint && wp_count == 0) {
-    GTEST_LOG_(INFO) << "Kernel reports zero hardware watchpoints";
-    return false;
-  }
-  if (feature == HwFeature::Breakpoint && hb_count == 0) {
-    GTEST_LOG_(INFO) << "Kernel reports zero hardware breakpoints";
-    return false;
-  }
-  return true;
 #elif defined(__aarch64__)
   user_hwdebug_state dreg_state;
   iovec iov;
@@ -99,20 +91,13 @@
   long result = ptrace(PTRACE_GETREGSET, child,
                        feature == HwFeature::Watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK, &iov);
   if (result == -1) {
-    EXPECT_EQ(EINVAL, errno);
-    return false;
+    ASSERT_EQ(EINVAL, errno);
   }
-  return (dreg_state.dbg_info & 0xff) > 0;
-#elif defined(__i386__) || defined(__x86_64__)
+  if ((dreg_state.dbg_info & 0xff) == 0) GTEST_SKIP() << "hardware support missing";
+#else
   // We assume watchpoints and breakpoints are always supported on x86.
   UNUSED(child);
   UNUSED(feature);
-  return true;
-#else
-  // TODO: mips support.
-  UNUSED(child);
-  UNUSED(feature);
-  return false;
 #endif
 }
 
@@ -190,10 +175,7 @@
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
 
-  if (!is_hw_feature_supported(child, HwFeature::Watchpoint)) {
-    GTEST_LOG_(INFO) << "Skipping test because hardware support is not available.\n";
-    return;
-  }
+  check_hw_feature_supported(child, HwFeature::Watchpoint);
 
   set_watchpoint(child, uintptr_t(untag_address(&data)) + offset, size);
 
@@ -360,10 +342,7 @@
   ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
   ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
 
-  if (!is_hw_feature_supported(child, HwFeature::Breakpoint)) {
-    GTEST_LOG_(INFO) << "Skipping test because hardware support is not available.\n";
-    return;
-  }
+  check_hw_feature_supported(child, HwFeature::Breakpoint);
 
   set_breakpoint(child);
 
@@ -423,7 +402,7 @@
     }
   }
 
-  ~PtraceResumptionTest() {
+  ~PtraceResumptionTest() override {
   }
 
   void AssertDeath(int signo);
diff --git a/tests/sys_random_test.cpp b/tests/sys_random_test.cpp
index 78cbf4a..2e2665b 100644
--- a/tests/sys_random_test.cpp
+++ b/tests/sys_random_test.cpp
@@ -43,7 +43,7 @@
   ASSERT_EQ(0, getentropy(buf2, sizeof(buf2)));
   ASSERT_TRUE(memcmp(buf1, buf2, sizeof(buf1)) != 0);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
 
@@ -53,7 +53,7 @@
   ASSERT_EQ(-1, getentropy(nullptr, 1));
   ASSERT_EQ(EFAULT, errno);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
 
@@ -66,7 +66,7 @@
   ASSERT_EQ(-1, getentropy(buf, sizeof(buf)));
   ASSERT_EQ(EIO, errno);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
 
@@ -79,7 +79,7 @@
   ASSERT_EQ(64, getrandom(buf2, sizeof(buf2), 0));
   ASSERT_TRUE(memcmp(buf1, buf2, sizeof(buf1)) != 0);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
 
@@ -89,7 +89,7 @@
   ASSERT_EQ(-1, getrandom(nullptr, 256, 0));
   ASSERT_EQ(EFAULT, errno);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
 
@@ -100,6 +100,6 @@
   ASSERT_EQ(-1, getrandom(buf, sizeof(buf), ~0));
   ASSERT_EQ(EINVAL, errno);
 #else
-  GTEST_LOG_(INFO) << "This test requires a C library with <sys/random.h>.\n";
+  GTEST_SKIP() << "<sys/random.h> not available";
 #endif
 }
diff --git a/tests/sys_resource_test.cpp b/tests/sys_resource_test.cpp
index 0b6b6ef..b1e8b1a 100644
--- a/tests/sys_resource_test.cpp
+++ b/tests/sys_resource_test.cpp
@@ -30,7 +30,7 @@
 
 class SysResourceTest : public ::testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
     ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
     ASSERT_EQ(0, prlimit(0, RLIMIT_CORE, nullptr, &pr_l32_));
diff --git a/tests/sys_sem_test.cpp b/tests/sys_sem_test.cpp
index dff34c8..b98926b 100644
--- a/tests/sys_sem_test.cpp
+++ b/tests/sys_sem_test.cpp
@@ -35,8 +35,7 @@
 
 TEST(sys_sem, smoke) {
   if (semctl(-1, 0, IPC_RMID) == -1 && errno == ENOSYS) {
-    GTEST_LOG_(INFO) << "no <sys/sem.h> support in this kernel\n";
-    return;
+    GTEST_SKIP() << "no <sys/sem.h> support in this kernel";
   }
 
   // Create a semaphore.
diff --git a/tests/sys_shm_test.cpp b/tests/sys_shm_test.cpp
index 15abe05..fd5d424 100644
--- a/tests/sys_shm_test.cpp
+++ b/tests/sys_shm_test.cpp
@@ -34,8 +34,7 @@
 
 TEST(sys_shm, smoke) {
   if (shmctl(-1, IPC_STAT, nullptr) == -1 && errno == ENOSYS) {
-    GTEST_LOG_(INFO) << "no <sys/shm.h> support in this kernel\n";
-    return;
+    GTEST_SKIP() << "no <sys/shm.h> support in this kernel";
   }
 
   // Create a segment.
diff --git a/tests/sys_stat_test.cpp b/tests/sys_stat_test.cpp
index 70ad451..97bf580 100644
--- a/tests/sys_stat_test.cpp
+++ b/tests/sys_stat_test.cpp
@@ -82,7 +82,7 @@
     unlink(path.c_str());
   } else {
     // SELinux policy forbids us from creating FIFOs. http://b/17646702.
-    GTEST_LOG_(INFO) << "This test only performs a test when run as root.";
+    GTEST_SKIP() << "SELinux policy forbids non-root from creating FIFOs";
   }
 }
 
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 3b50896..245e42f 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -121,7 +121,7 @@
     ASSERT_EQ(5, system_properties.Get(name, propvalue));
     ASSERT_STREQ(propvalue, "value");
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -156,7 +156,7 @@
     ASSERT_EQ(6, system_properties.Get("property_other", propvalue));
     ASSERT_STREQ(propvalue, "value6");
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -202,7 +202,7 @@
         ASSERT_EQ(0, memcmp(prop_value, prop_value_ret, PROP_VALUE_MAX));
     }
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -219,7 +219,7 @@
     ASSERT_EQ(0, system_properties.Foreach(foreach_test_callback, &count));
     ASSERT_EQ(3U, count);
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -248,7 +248,7 @@
       ASSERT_TRUE(system_properties.FindNth(i) == nullptr);
     }
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -307,7 +307,7 @@
         }
     }
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -328,7 +328,7 @@
     ASSERT_EQ(-1, system_properties.Add("name", 4, "value", PROP_VALUE_MAX));
     ASSERT_EQ(-1, system_properties.Update(NULL, "value", PROP_VALUE_MAX));
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -344,7 +344,7 @@
     ASSERT_EQ(0, system_properties.Update(const_cast<prop_info*>(pi), "value2", 6));
     ASSERT_NE(serial, system_properties.Serial(pi));
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -375,7 +375,7 @@
 
     thread.join();
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -408,7 +408,7 @@
 
     thread.join();
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -436,7 +436,7 @@
 
   ASSERT_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), "");
 #else // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -508,7 +508,7 @@
   }
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
 
@@ -523,6 +523,6 @@
   ASSERT_NE(0, system_properties.Add(name.c_str(), name.size(), value.c_str(), value.size()));
 
 #else   // __BIONIC__
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
diff --git a/tests/system_properties_test2.cpp b/tests/system_properties_test2.cpp
index e6e7ef2..c061faa 100644
--- a/tests/system_properties_test2.cpp
+++ b/tests/system_properties_test2.cpp
@@ -124,7 +124,7 @@
     ASSERT_EQ(expected_name, legacy_name);
     ASSERT_STREQ("value2", propvalue);
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
 
@@ -143,6 +143,6 @@
     }
 
 #else // __BIONIC__
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_SKIP() << "bionic-only test";
 #endif // __BIONIC__
 }
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 50830ee..c890358 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -296,6 +296,69 @@
   EXPECT_STREQ("09:41:53", buf);
 }
 
+TEST(time, strptime_F) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("2019-03-26", "%F", &tm));
+  EXPECT_EQ(119, tm.tm_year);
+  EXPECT_EQ(2, tm.tm_mon);
+  EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_P_p) {
+  setenv("TZ", "UTC", 1);
+
+  // For parsing, %P and %p are the same: case doesn't matter.
+
+  struct tm tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("AM", "%p", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+
+  tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("am", "%p", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+
+  tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("AM", "%P", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+
+  tm = {.tm_hour = 12};
+  ASSERT_EQ('\0', *strptime("am", "%P", &tm));
+  EXPECT_EQ(0, tm.tm_hour);
+}
+
+TEST(time, strptime_u) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("2", "%u", &tm));
+  EXPECT_EQ(2, tm.tm_wday);
+}
+
+TEST(time, strptime_v) {
+  setenv("TZ", "UTC", 1);
+
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("26-Mar-1980", "%v", &tm));
+  EXPECT_EQ(80, tm.tm_year);
+  EXPECT_EQ(2, tm.tm_mon);
+  EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_V_G_g) {
+  setenv("TZ", "UTC", 1);
+
+  // %V (ISO-8601 week number), %G (year of week number, without century), and
+  // %g (year of week number) have no effect when parsed, and are supported
+  // solely so that it's possible for strptime(3) to parse everything that
+  // strftime(3) can output.
+  struct tm tm = {};
+  ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm));
+  struct tm zero = {};
+  EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
+}
+
 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;
@@ -912,6 +975,6 @@
   ASSERT_EQ(0, timespec_get(&ts, 123));
   ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC));
 #else
-  GTEST_LOG_(INFO) << "glibc doesn't have timespec_get until 2.21\n";
+  GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
 #endif
 }
diff --git a/tests/utils.h b/tests/utils.h
index cc1aa8c..fe41019 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -64,7 +64,7 @@
   return &__hwasan_init != 0;
 }
 
-#define SKIP_WITH_HWASAN if (running_with_hwasan()) { return; }
+#define SKIP_WITH_HWASAN if (running_with_hwasan()) GTEST_SKIP()
 
 static inline void* untag_address(void* addr) {
 #if defined(__LP64__)
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 9aef800..9b4fc4f 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -713,7 +713,7 @@
   ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr));
   ASSERT_EQ(EINVAL, errno);
 #else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
+  GTEST_SKIP() << "This test is bionic-specific";
 #endif
 }
 
diff --git a/tests/wctype_test.cpp b/tests/wctype_test.cpp
index 06e1571..85a46aa 100644
--- a/tests/wctype_test.cpp
+++ b/tests/wctype_test.cpp
@@ -111,7 +111,7 @@
     EXPECT_EQ(wint_t(L'δ'), towlower(L'δ'));
     EXPECT_EQ(wint_t(L'δ'), towlower(L'Δ'));
   } else {
-    GTEST_LOG_(INFO) << "skipping unicode towlower tests";
+    GTEST_SKIP() << "icu not available";
   }
 }
 
@@ -127,7 +127,7 @@
     EXPECT_EQ(wint_t(L'δ'), towlower_l(L'δ', l.l));
     EXPECT_EQ(wint_t(L'δ'), towlower_l(L'Δ', l.l));
   } else {
-    GTEST_LOG_(INFO) << "skipping unicode towlower_l tests";
+    GTEST_SKIP() << "icu not available";
   }
 }
 
@@ -142,7 +142,7 @@
     EXPECT_EQ(wint_t(L'Δ'), towupper(L'δ'));
     EXPECT_EQ(wint_t(L'Δ'), towupper(L'Δ'));
   } else {
-    GTEST_LOG_(INFO) << "skipping unicode towupper tests";
+    GTEST_SKIP() << "icu not available";
   }
 }
 
@@ -158,7 +158,7 @@
     EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'δ', l.l));
     EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'Δ', l.l));
   } else {
-    GTEST_LOG_(INFO) << "skipping unicode towupper_l tests";
+    GTEST_SKIP() << "icu not available";
   }
 }
 
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 6062240..3927480 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -62,7 +62,7 @@
       : header_database(header_database), type(type) {
   }
 
-  virtual void HandleTranslationUnit(ASTContext& ctx) override {
+  void HandleTranslationUnit(ASTContext& ctx) override {
     header_database->parseAST(type, ctx);
   }
 };