Merge "sys_msg_test: Fix msgsnd() argument passing" into main
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index ffb5921..75e607c 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -72,6 +72,7 @@
 
     target: {
         android: {
+            header_libs: ["bionic_libc_platform_headers"],
             static_libs: [
                 "libmeminfo",
                 "libprocinfo",
diff --git a/benchmarks/ScopedDecayTimeRestorer.h b/benchmarks/ScopedDecayTimeRestorer.h
new file mode 100644
index 0000000..5835b43
--- /dev/null
+++ b/benchmarks/ScopedDecayTimeRestorer.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <malloc.h>
+
+#if defined(__BIONIC__)
+
+#include "platform/bionic/malloc.h"
+
+class ScopedDecayTimeRestorer {
+ public:
+  ScopedDecayTimeRestorer() {
+    bool value;
+    if (android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value))) {
+      saved_value_ = value ? 1 : 0;
+    }
+  }
+
+  virtual ~ScopedDecayTimeRestorer() { mallopt(M_DECAY_TIME, saved_value_); }
+
+ private:
+  int saved_value_ = 0;
+};
+
+#endif
diff --git a/benchmarks/malloc_benchmark.cpp b/benchmarks/malloc_benchmark.cpp
index 258343f..8f467d2 100644
--- a/benchmarks/malloc_benchmark.cpp
+++ b/benchmarks/malloc_benchmark.cpp
@@ -36,11 +36,14 @@
 #include <vector>
 
 #include <benchmark/benchmark.h>
+#include "ScopedDecayTimeRestorer.h"
 #include "util.h"
 
 #if defined(__BIONIC__)
 
 static void RunMalloptPurge(benchmark::State& state, int purge_value) {
+  ScopedDecayTimeRestorer restorer;
+
   static size_t sizes[] = {8, 16, 32, 64, 128, 1024, 4096, 16384, 65536, 131072, 1048576};
   static int pagesize = getpagesize();
   mallopt(M_DECAY_TIME, 1);
@@ -69,7 +72,6 @@
 
     mallopt(purge_value, 0);
   }
-  mallopt(M_DECAY_TIME, 0);
 }
 
 static void RunThreadsThroughput(benchmark::State& state, size_t size, size_t num_threads) {
diff --git a/benchmarks/malloc_sql_benchmark.cpp b/benchmarks/malloc_sql_benchmark.cpp
index 383325c..d5b17f6 100644
--- a/benchmarks/malloc_sql_benchmark.cpp
+++ b/benchmarks/malloc_sql_benchmark.cpp
@@ -31,6 +31,7 @@
 #include <unistd.h>
 
 #include <benchmark/benchmark.h>
+#include "ScopedDecayTimeRestorer.h"
 #include "util.h"
 
 #if defined(__BIONIC__)
@@ -104,6 +105,8 @@
 #include "malloc_sql.h"
 
 static void BM_malloc_sql_trace_default(benchmark::State& state) {
+  ScopedDecayTimeRestorer restorer;
+
   // The default is expected to be a zero decay time.
   mallopt(M_DECAY_TIME, 0);
 
@@ -115,14 +118,14 @@
 BIONIC_BENCHMARK(BM_malloc_sql_trace_default);
 
 static void BM_malloc_sql_trace_decay1(benchmark::State& state) {
+  ScopedDecayTimeRestorer restorer;
+
   mallopt(M_DECAY_TIME, 1);
 
   for (auto _ : state) {
     BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
                     kMaxSqlAllocSlots);
   }
-
-  mallopt(M_DECAY_TIME, 0);
 }
 BIONIC_BENCHMARK(BM_malloc_sql_trace_decay1);
 
diff --git a/benchmarks/stdlib_benchmark.cpp b/benchmarks/stdlib_benchmark.cpp
index 14b380a..9be72e7 100644
--- a/benchmarks/stdlib_benchmark.cpp
+++ b/benchmarks/stdlib_benchmark.cpp
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include <benchmark/benchmark.h>
+#include "ScopedDecayTimeRestorer.h"
 #include "util.h"
 
 static void MallocFree(benchmark::State& state) {
@@ -40,6 +41,8 @@
 
 static void BM_stdlib_malloc_free_default(benchmark::State& state) {
 #if defined(__BIONIC__)
+  ScopedDecayTimeRestorer restorer;
+
   // The default is expected to be a zero decay time.
   mallopt(M_DECAY_TIME, 0);
 #endif
@@ -50,11 +53,11 @@
 
 #if defined(__BIONIC__)
 static void BM_stdlib_malloc_free_decay1(benchmark::State& state) {
+  ScopedDecayTimeRestorer restorer;
+
   mallopt(M_DECAY_TIME, 1);
 
   MallocFree(state);
-
-  mallopt(M_DECAY_TIME, 0);
 }
 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_decay1, "AT_COMMON_SIZES");
 #endif
@@ -75,6 +78,8 @@
 
 static void BM_stdlib_calloc_free_default(benchmark::State& state) {
 #if defined(__BIONIC__)
+  ScopedDecayTimeRestorer restorer;
+
   // The default is expected to be a zero decay time.
   mallopt(M_DECAY_TIME, 0);
 #endif
@@ -113,8 +118,9 @@
 }
 
 void BM_stdlib_malloc_forty_default(benchmark::State& state) {
-
 #if defined(__BIONIC__)
+  ScopedDecayTimeRestorer restorer;
+
   // The default is expected to be a zero decay time.
   mallopt(M_DECAY_TIME, 0);
 #endif
@@ -125,17 +131,19 @@
 
 #if defined(__BIONIC__)
 void BM_stdlib_malloc_forty_decay1(benchmark::State& state) {
+  ScopedDecayTimeRestorer restorer;
+
   mallopt(M_DECAY_TIME, 1);
 
   MallocMultiple(state, state.range(0), 40);
-
-  mallopt(M_DECAY_TIME, 0);
 }
 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_forty_decay1, "AT_COMMON_SIZES");
 #endif
 
 void BM_stdlib_malloc_multiple_8192_allocs_default(benchmark::State& state) {
 #if defined(__BIONIC__)
+  ScopedDecayTimeRestorer restorer;
+
   // The default is expected to be a zero decay time.
   mallopt(M_DECAY_TIME, 0);
 #endif
@@ -146,11 +154,11 @@
 
 #if defined(__BIONIC__)
 void BM_stdlib_malloc_multiple_8192_allocs_decay1(benchmark::State& state) {
+  ScopedDecayTimeRestorer restorer;
+
   mallopt(M_DECAY_TIME, 1);
 
   MallocMultiple(state, 8192, state.range(0));
-
-  mallopt(M_DECAY_TIME, 0);
 }
 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_multiple_8192_allocs_decay1, "AT_SMALL_SIZES");
 #endif
diff --git a/libc/Android.bp b/libc/Android.bp
index fe5f6de..1fd8847 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -136,6 +136,8 @@
     },
 
     apex_available: ["com.android.runtime"],
+
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
 }
 
 libc_scudo_product_variables = {
@@ -251,7 +253,6 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "tzcode/**/*.c",
         "tzcode/bionic.cpp",
@@ -302,7 +303,6 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "dns/**/*.c*",
 
@@ -345,7 +345,6 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-freebsd/lib/libc/stdlib/getopt_long.c",
         "upstream-freebsd/lib/libc/stdlib/hcreate.c",
@@ -411,7 +410,6 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-freebsd/lib/libc/gen/glob.c",
     ],
@@ -439,7 +437,6 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-netbsd/common/lib/libc/stdlib/random.c",
         "upstream-netbsd/lib/libc/gen/nice.c",
@@ -497,7 +494,6 @@
 cc_library_static {
     name: "libc_openbsd_ndk",
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-openbsd/lib/libc/gen/alarm.c",
         "upstream-openbsd/lib/libc/gen/ctype_.c",
@@ -616,7 +612,6 @@
 cc_library_static {
     name: "libc_openbsd_large_stack",
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "stdio/vfprintf.cpp",
         "stdio/vfwprintf.cpp",
@@ -651,73 +646,50 @@
         // These two depend on getentropy, which isn't in libc_ndk.a.
         "upstream-openbsd/lib/libc/crypt/arc4random.c",
         "upstream-openbsd/lib/libc/crypt/arc4random_uniform.c",
-
-        // May be overriden by per-arch optimized versions
-        "upstream-openbsd/lib/libc/string/memchr.c",
-        "upstream-openbsd/lib/libc/string/memrchr.c",
-        "upstream-openbsd/lib/libc/string/stpcpy.c",
-        "upstream-openbsd/lib/libc/string/stpncpy.c",
-        "upstream-openbsd/lib/libc/string/strcat.c",
-        "upstream-openbsd/lib/libc/string/strcpy.c",
-        "upstream-openbsd/lib/libc/string/strlcat.c",
-        "upstream-openbsd/lib/libc/string/strlcpy.c",
-        "upstream-openbsd/lib/libc/string/strncat.c",
-        "upstream-openbsd/lib/libc/string/strncmp.c",
-        "upstream-openbsd/lib/libc/string/strncpy.c",
     ],
 
+    // Each architecture has optimized versions of some routines,
+    // and only includes the portable C versions of ones it's missing.
     arch: {
         arm: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/strcpy.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
+            srcs: [
+                "upstream-openbsd/lib/libc/string/memchr.c",
+                "upstream-openbsd/lib/libc/string/memrchr.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
+                "upstream-openbsd/lib/libc/string/strncat.c",
+                "upstream-openbsd/lib/libc/string/strncmp.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
             ],
         },
         arm64: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/memchr.c",
-                "upstream-openbsd/lib/libc/string/memrchr.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/strcpy.c",
-                "upstream-openbsd/lib/libc/string/strncmp.c",
+            srcs: [
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strcat.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
+                "upstream-openbsd/lib/libc/string/strncat.c",
+                "upstream-openbsd/lib/libc/string/strncpy.c",
             ],
         },
         riscv64: {
             srcs: [
-                "upstream-freebsd/lib/libc/string/memcmp.c",
-                "upstream-freebsd/lib/libc/string/memcpy.c",
-                "upstream-freebsd/lib/libc/string/memmove.c",
-                "upstream-freebsd/lib/libc/string/memset.c",
-                "upstream-openbsd/lib/libc/string/strcmp.c",
-                "upstream-openbsd/lib/libc/string/strlen.c",
+                "upstream-openbsd/lib/libc/string/memrchr.c",
+                "upstream-openbsd/lib/libc/string/stpncpy.c",
+                "upstream-openbsd/lib/libc/string/strlcat.c",
+                "upstream-openbsd/lib/libc/string/strlcpy.c",
             ],
         },
         x86: {
-            exclude_srcs: [
+            // This space intentionally left blank.
+        },
+        x86_64: {
+            srcs: [
                 "upstream-openbsd/lib/libc/string/memchr.c",
                 "upstream-openbsd/lib/libc/string/memrchr.c",
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/stpncpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-                "upstream-openbsd/lib/libc/string/strcpy.c",
-                "upstream-openbsd/lib/libc/string/strncmp.c",
-                "upstream-openbsd/lib/libc/string/strncpy.c",
                 "upstream-openbsd/lib/libc/string/strlcat.c",
                 "upstream-openbsd/lib/libc/string/strlcpy.c",
-                "upstream-openbsd/lib/libc/string/strncat.c",
-            ],
-        },
-
-        x86_64: {
-            exclude_srcs: [
-                "upstream-openbsd/lib/libc/string/stpcpy.c",
-                "upstream-openbsd/lib/libc/string/stpncpy.c",
-                "upstream-openbsd/lib/libc/string/strcat.c",
-                "upstream-openbsd/lib/libc/string/strcpy.c",
-                "upstream-openbsd/lib/libc/string/strncat.c",
-                "upstream-openbsd/lib/libc/string/strncmp.c",
-                "upstream-openbsd/lib/libc/string/strncpy.c",
             ],
         },
     },
@@ -745,7 +717,6 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-openbsd/android/gdtoa_support.cpp",
         "upstream-openbsd/lib/libc/gdtoa/dmisc.c",
@@ -861,26 +832,12 @@
         // The following must not be statically linked into libc_ndk.a, because
         // debuggerd will look for the abort message in libc.so's copy.
         "bionic/android_set_abort_message.cpp",
-
-        "bionic/strchr.cpp",
-        "bionic/strchrnul.cpp",
-        "bionic/strnlen.c",
-        "bionic/strrchr.cpp",
     ],
 
     arch: {
         arm: {
             asflags: libc_common_flags + ["-mno-restrict-it"],
             srcs: [
-                "arch-arm/generic/bionic/memcmp.S",
-                "arch-arm/generic/bionic/memmove.S",
-                "arch-arm/generic/bionic/memset.S",
-                "arch-arm/generic/bionic/stpcpy.c",
-                "arch-arm/generic/bionic/strcat.c",
-                "arch-arm/generic/bionic/strcmp.S",
-                "arch-arm/generic/bionic/strcpy.S",
-                "arch-arm/generic/bionic/strlen.c",
-
                 "arch-arm/bionic/__aeabi_read_tp.S",
                 "arch-arm/bionic/__bionic_clone.S",
                 "arch-arm/bionic/__restore.S",
@@ -893,6 +850,20 @@
                 "arch-arm/bionic/syscall.S",
                 "arch-arm/bionic/vfork.S",
 
+                "bionic/strchr.cpp",
+                "bionic/strchrnul.cpp",
+                "bionic/strnlen.c",
+                "bionic/strrchr.cpp",
+
+                "arch-arm/generic/bionic/memcmp.S",
+                "arch-arm/generic/bionic/memmove.S",
+                "arch-arm/generic/bionic/memset.S",
+                "arch-arm/generic/bionic/stpcpy.c",
+                "arch-arm/generic/bionic/strcat.c",
+                "arch-arm/generic/bionic/strcmp.S",
+                "arch-arm/generic/bionic/strcpy.S",
+                "arch-arm/generic/bionic/strlen.c",
+
                 "arch-arm/cortex-a15/bionic/memcpy.S",
                 "arch-arm/cortex-a15/bionic/memmove.S",
                 "arch-arm/cortex-a15/bionic/memset.S",
@@ -930,12 +901,6 @@
                 "arch-arm64/bionic/syscall.S",
                 "arch-arm64/bionic/vfork.S",
             ],
-            exclude_srcs: [
-                "bionic/strchr.cpp",
-                "bionic/strchrnul.cpp",
-                "bionic/strnlen.c",
-                "bionic/strrchr.cpp",
-            ],
         },
 
         riscv64: {
@@ -946,26 +911,43 @@
                 "arch-riscv64/bionic/syscall.S",
                 "arch-riscv64/bionic/vfork.S",
 
-                "arch-riscv64/string/memchr_vext.S",
-                "arch-riscv64/string/memcmp_vext.S",
-                "arch-riscv64/string/memcpy_vext.S",
-                "arch-riscv64/string/memmove_vext.S",
-                "arch-riscv64/string/memset_vext.S",
-                "arch-riscv64/string/stpcpy_vext.S",
-                "arch-riscv64/string/strcat_vext.S",
-                "arch-riscv64/string/strchr_vext.S",
-                "arch-riscv64/string/strcmp_vext.S",
-                "arch-riscv64/string/strcpy_vext.S",
-                "arch-riscv64/string/strlen_vext.S",
-                "arch-riscv64/string/strncat_vext.S",
-                "arch-riscv64/string/strncmp_vext.S",
-                "arch-riscv64/string/strncpy_vext.S",
-                "arch-riscv64/string/strnlen_vext.S",
+                // TODO(b/306514350): Remove this and replace with the optimized
+                // version once the bug is resolved.
+                "upstream-freebsd/lib/libc/string/memcmp.c",
+
+                "bionic/strchrnul.cpp",
+                "bionic/strrchr.cpp",
+
+                "arch-riscv64/string/memchr.S",
+                "arch-riscv64/string/memcpy.S",
+                "arch-riscv64/string/memmove.S",
+                "arch-riscv64/string/memset.S",
+                "arch-riscv64/string/stpcpy.S",
+                "arch-riscv64/string/strcat.S",
+                "arch-riscv64/string/strchr.S",
+                "arch-riscv64/string/strcmp.S",
+                "arch-riscv64/string/strcpy.S",
+                "arch-riscv64/string/strlen.S",
+                "arch-riscv64/string/strncat.S",
+                "arch-riscv64/string/strncmp.S",
+                "arch-riscv64/string/strncpy.S",
+                "arch-riscv64/string/strnlen.S",
             ],
         },
 
         x86: {
             srcs: [
+                "arch-x86/bionic/__bionic_clone.S",
+                "arch-x86/bionic/_exit_with_stack_teardown.S",
+                "arch-x86/bionic/libcrt_compat.c",
+                "arch-x86/bionic/__restore.S",
+                "arch-x86/bionic/setjmp.S",
+                "arch-x86/bionic/syscall.S",
+                "arch-x86/bionic/vfork.S",
+                "arch-x86/bionic/__x86.get_pc_thunk.S",
+
+                "bionic/strchrnul.cpp",
+
                 "arch-x86/generic/string/memcmp.S",
                 "arch-x86/generic/string/strcmp.S",
                 "arch-x86/generic/string/strncmp.S",
@@ -1013,25 +995,22 @@
 
                 "arch-x86/string/sse4-memcmp-slm.S",
                 "arch-x86/string/sse4-wmemcmp-slm.S",
-
-                "arch-x86/bionic/__bionic_clone.S",
-                "arch-x86/bionic/_exit_with_stack_teardown.S",
-                "arch-x86/bionic/libcrt_compat.c",
-                "arch-x86/bionic/__restore.S",
-                "arch-x86/bionic/setjmp.S",
-                "arch-x86/bionic/syscall.S",
-                "arch-x86/bionic/vfork.S",
-                "arch-x86/bionic/__x86.get_pc_thunk.S",
-            ],
-
-            exclude_srcs: [
-                "bionic/strchr.cpp",
-                "bionic/strnlen.c",
-                "bionic/strrchr.cpp",
             ],
         },
         x86_64: {
             srcs: [
+                "arch-x86_64/bionic/__bionic_clone.S",
+                "arch-x86_64/bionic/_exit_with_stack_teardown.S",
+                "arch-x86_64/bionic/__restore_rt.S",
+                "arch-x86_64/bionic/setjmp.S",
+                "arch-x86_64/bionic/syscall.S",
+                "arch-x86_64/bionic/vfork.S",
+
+                "bionic/strchr.cpp",
+                "bionic/strchrnul.cpp",
+                "bionic/strnlen.c",
+                "bionic/strrchr.cpp",
+
                 "arch-x86_64/string/avx2-memset-kbl.S",
                 "arch-x86_64/string/sse2-memmove-slm.S",
                 "arch-x86_64/string/sse2-memset-slm.S",
@@ -1045,13 +1024,6 @@
                 "arch-x86_64/string/sse4-memcmp-slm.S",
                 "arch-x86_64/string/ssse3-strcmp-slm.S",
                 "arch-x86_64/string/ssse3-strncmp-slm.S",
-
-                "arch-x86_64/bionic/__bionic_clone.S",
-                "arch-x86_64/bionic/_exit_with_stack_teardown.S",
-                "arch-x86_64/bionic/__restore_rt.S",
-                "arch-x86_64/bionic/setjmp.S",
-                "arch-x86_64/bionic/syscall.S",
-                "arch-x86_64/bionic/vfork.S",
             ],
         },
     },
@@ -1569,9 +1541,6 @@
         arm64: {
             srcs: ["arch-arm64/static_function_dispatch.S"],
         },
-        riscv64: {
-            srcs: ["arch-riscv64/static_function_dispatch.S"]
-        },
     },
 }
 
@@ -1600,9 +1569,6 @@
         arm64: {
             srcs: ["arch-arm64/dynamic_function_dispatch.cpp"],
         },
-        riscv64: {
-            srcs: ["arch-riscv64/dynamic_function_dispatch.cpp"]
-        },
     },
 }
 
@@ -2921,7 +2887,6 @@
 
 cc_library_host_static {
     name: "libfts",
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "bionic/fts.c",
         "upstream-openbsd/lib/libc/stdlib/recallocarray.c",
@@ -2964,7 +2929,6 @@
 cc_library_host_static {
     name: "libb64",
     visibility: ["//external/musl"],
-    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: ["upstream-openbsd/lib/libc/net/base64.c"],
     export_include_dirs: ["b64/include"],
     local_include_dirs: [
diff --git a/libc/NOTICE b/libc/NOTICE
index d464e1d..b345544 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -2077,38 +2077,6 @@
 
 Copyright (c) 1990, 1993
    The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Mike Hibler and Chris Torek.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. 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.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
-
--------------------------------------------------------------------
-
-Copyright (c) 1990, 1993
-   The Regents of the University of California.  All rights reserved.
 (c) UNIX System Laboratories, Inc.
 All or some portions of this file are derived from material licensed
 to the University of California by American Telephone and Telegraph
diff --git a/libc/arch-riscv64/dynamic_function_dispatch.cpp b/libc/arch-riscv64/dynamic_function_dispatch.cpp
deleted file mode 100644
index 5866fe4..0000000
--- a/libc/arch-riscv64/dynamic_function_dispatch.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2023 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 <private/bionic_ifuncs.h>
-#include <stddef.h>
-#include <sys/auxv.h>
-
-#if defined(__riscv_v)
-extern "C" {
-
-typedef void* memchr_func(const void*, int, size_t);
-DEFINE_IFUNC_FOR(memchr) {
-  RETURN_FUNC(memchr_func, memchr_vext);
-}
-
-typedef int memcmp_func(const void*, const void*, size_t);
-DEFINE_IFUNC_FOR(memcmp) {
-  RETURN_FUNC(memcmp_func, memcmp_vext);
-}
-
-typedef void* memcpy_func(void*, const void*, size_t);
-DEFINE_IFUNC_FOR(memcpy) {
-  RETURN_FUNC(memcpy_func, memcpy_vext);
-}
-
-typedef void* memmove_func(void*, const void*, size_t);
-DEFINE_IFUNC_FOR(memmove) {
-  RETURN_FUNC(memmove_func, memmove_vext);
-}
-
-typedef void* memset_func(void*, int, size_t);
-DEFINE_IFUNC_FOR(memset) {
-  RETURN_FUNC(memset_func, memset_vext);
-}
-
-typedef char* stpcpy_func(char*, const char*);
-DEFINE_IFUNC_FOR(stpcpy) {
-  RETURN_FUNC(stpcpy_func, stpcpy_vext);
-}
-
-typedef char* strcat_func(char*, const char*);
-DEFINE_IFUNC_FOR(strcat) {
-  RETURN_FUNC(strcat_func, strcat_vext);
-}
-
-typedef char* strchr_func(const char*, int);
-DEFINE_IFUNC_FOR(strchr) {
-  RETURN_FUNC(strchr_func, strchr_vext);
-}
-
-typedef int strcmp_func(const char*, const char*);
-DEFINE_IFUNC_FOR(strcmp) {
-  RETURN_FUNC(strcmp_func, strcmp_vext);
-}
-
-typedef char* strcpy_func(char*, const char*);
-DEFINE_IFUNC_FOR(strcpy) {
-  RETURN_FUNC(strcpy_func, strcpy_vext);
-}
-
-typedef size_t strlen_func(const char*);
-DEFINE_IFUNC_FOR(strlen) {
-  RETURN_FUNC(strlen_func, strlen_vext);
-}
-
-typedef char* strncat_func(char*, const char*, size_t);
-DEFINE_IFUNC_FOR(strncat) {
-  RETURN_FUNC(strncat_func, strncat_vext);
-}
-
-typedef int strncmp_func(const char*, const char*, size_t);
-DEFINE_IFUNC_FOR(strncmp) {
-  RETURN_FUNC(strncmp_func, strncmp_vext);
-}
-
-typedef char* strncpy_func(char*, const char*, size_t);
-DEFINE_IFUNC_FOR(strncpy) {
-  RETURN_FUNC(strncpy_func, strncpy_vext);
-}
-
-typedef size_t strnlen_func(const char*, size_t);
-DEFINE_IFUNC_FOR(strnlen) {
-  RETURN_FUNC(strnlen_func, strnlen_vext);
-}
-
-}  // extern "C"
-#endif
diff --git a/libc/arch-riscv64/string/memchr_vext.S b/libc/arch-riscv64/string/memchr.S
similarity index 97%
rename from libc/arch-riscv64/string/memchr_vext.S
rename to libc/arch-riscv64/string/memchr.S
index ed76a05..8833436 100644
--- a/libc/arch-riscv64/string/memchr_vext.S
+++ b/libc/arch-riscv64/string/memchr.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define iResult a0
@@ -70,7 +68,7 @@
 #define vData v0
 #define vMask v8
 
-ENTRY(memchr_vext)
+ENTRY(memchr)
 
 L(loop):
     vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma
@@ -95,6 +93,4 @@
     add iResult, pSrc, iTemp
     ret
 
-END(memchr_vext)
-
-#endif
+END(memchr)
diff --git a/libc/arch-riscv64/string/memcmp_vext.S b/libc/arch-riscv64/string/memcmp_vext.S
deleted file mode 100644
index 1bb381c..0000000
--- a/libc/arch-riscv64/string/memcmp_vext.S
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2023 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.
- */
-/*
- * Copyright (c) 2023 SiFive, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. The name of the company may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY SIFIVE INC ``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 SIFIVE INC 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.
- */
-
-#if defined(__riscv_v)
-
-#include <private/bionic_asm.h>
-
-#define iResult a0
-
-#define pSrc1 a0
-#define pSrc2 a1
-#define iNum a2
-
-#define iVL a3
-#define iTemp a4
-#define iTemp1 a5
-#define iTemp2 a6
-
-#define ELEM_LMUL_SETTING m8
-#define vData1 v0
-#define vData2 v8
-#define vMask v16
-
-ENTRY(memcmp_vext)
-
-L(loop):
-    vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma
-
-    vle8.v vData1, (pSrc1)
-    vle8.v vData2, (pSrc2)
-
-    vmsne.vv vMask, vData1, vData2
-    sub iNum, iNum, iVL
-    vfirst.m iTemp, vMask
-
-    /* skip the loop if we find the different
-       value between pSrc1 and pSrc2.  */
-    bgez iTemp, L(found)
-
-    add pSrc1, pSrc1, iVL
-    add pSrc2, pSrc2, iVL
-
-    bnez iNum, L(loop)
-
-    li iResult, 0
-    ret
-
-L(found):
-    add pSrc1, pSrc1, iTemp
-    add pSrc2, pSrc2, iTemp
-    lbu iTemp1, 0(pSrc1)
-    lbu iTemp2, 0(pSrc2)
-    sub iResult, iTemp1, iTemp2
-    ret
-
-END(memcmp_vext)
-
-#endif
diff --git a/libc/arch-riscv64/string/memcpy_vext.S b/libc/arch-riscv64/string/memcpy.S
similarity index 97%
rename from libc/arch-riscv64/string/memcpy_vext.S
rename to libc/arch-riscv64/string/memcpy.S
index 668973f..def1d9b 100644
--- a/libc/arch-riscv64/string/memcpy_vext.S
+++ b/libc/arch-riscv64/string/memcpy.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -67,7 +65,7 @@
 #define ELEM_LMUL_SETTING m8
 #define vData v0
 
-ENTRY(memcpy_vext)
+ENTRY(memcpy)
 
     mv pDstPtr, pDst
 
@@ -84,6 +82,4 @@
 
     ret
 
-END(memcpy_vext)
-
-#endif
+END(memcpy)
diff --git a/libc/arch-riscv64/string/memmove_vext.S b/libc/arch-riscv64/string/memmove.S
similarity index 97%
rename from libc/arch-riscv64/string/memmove_vext.S
rename to libc/arch-riscv64/string/memmove.S
index 03f10c5..fa70f76 100644
--- a/libc/arch-riscv64/string/memmove_vext.S
+++ b/libc/arch-riscv64/string/memmove.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -69,7 +67,7 @@
 #define ELEM_LMUL_SETTING m8
 #define vData v0
 
-ENTRY(memmove_vext)
+ENTRY(memmove)
 
     mv pDstPtr, pDst
 
@@ -101,6 +99,4 @@
     bnez iNum, L(backward_copy_loop)
     ret
 
-END(memmove_vext)
-
-#endif
+END(memmove)
diff --git a/libc/arch-riscv64/string/memset_vext.S b/libc/arch-riscv64/string/memset.S
similarity index 97%
rename from libc/arch-riscv64/string/memset_vext.S
rename to libc/arch-riscv64/string/memset.S
index 554d6bd..5aa525e 100644
--- a/libc/arch-riscv64/string/memset_vext.S
+++ b/libc/arch-riscv64/string/memset.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -68,7 +66,7 @@
 #define ELEM_LMUL_SETTING m8
 #define vData v0
 
-ENTRY(memset_vext)
+ENTRY(memset)
 
     mv pDstPtr, pDst
 
@@ -84,6 +82,4 @@
 
     ret
 
-END(memset_vext)
-
-#endif
+END(memset)
diff --git a/libc/arch-riscv64/string/stpcpy_vext.S b/libc/arch-riscv64/string/stpcpy.S
similarity index 97%
rename from libc/arch-riscv64/string/stpcpy_vext.S
rename to libc/arch-riscv64/string/stpcpy.S
index e089938..c5d0945 100644
--- a/libc/arch-riscv64/string/stpcpy_vext.S
+++ b/libc/arch-riscv64/string/stpcpy.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDstPtr a0
@@ -70,7 +68,7 @@
 #define vStr1 v8
 #define vStr2 v16
 
-ENTRY(stpcpy_vext)
+ENTRY(stpcpy)
 L(stpcpy_loop):
     vsetvli iVL, zero, e8, ELEM_LMUL_SETTING, ta, ma
     vle8ff.v vStr1, (pSrc)
@@ -87,6 +85,4 @@
     sub pDstPtr, pDstPtr, iCurrentVL
     add pDstPtr, pDstPtr, iActiveElemPos
     ret
-END(stpcpy_vext)
-
-#endif
+END(stpcpy)
diff --git a/libc/arch-riscv64/string/strcat_vext.S b/libc/arch-riscv64/string/strcat.S
similarity index 97%
rename from libc/arch-riscv64/string/strcat_vext.S
rename to libc/arch-riscv64/string/strcat.S
index 05e0dfc..5abf295 100644
--- a/libc/arch-riscv64/string/strcat_vext.S
+++ b/libc/arch-riscv64/string/strcat.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -71,7 +69,7 @@
 #define vStr1 v8
 #define vStr2 v16
 
-ENTRY(strcat_vext)
+ENTRY(strcat)
 
     mv pDstPtr, pDst
 
@@ -106,6 +104,4 @@
 
     ret
 
-END(strcat_vext)
-
-#endif
+END(strcat)
diff --git a/libc/arch-riscv64/string/strchr_vext.S b/libc/arch-riscv64/string/strchr.S
similarity index 97%
rename from libc/arch-riscv64/string/strchr_vext.S
rename to libc/arch-riscv64/string/strchr.S
index 4c7bac1..ea13c5d 100644
--- a/libc/arch-riscv64/string/strchr_vext.S
+++ b/libc/arch-riscv64/string/strchr.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pStr a0
@@ -71,7 +69,7 @@
 #define vMaskEnd v8
 #define vMaskCh v9
 
-ENTRY(strchr_vext)
+ENTRY(strchr)
 
 L(strchr_loop):
     vsetvli iVL, zero, e8, ELEM_LMUL_SETTING, ta, ma
@@ -93,6 +91,4 @@
     add pStr, pStr, iChOffset
     ret
 
-END(strchr_vext)
-
-#endif
+END(strchr)
diff --git a/libc/arch-riscv64/string/strcmp_vext.S b/libc/arch-riscv64/string/strcmp.S
similarity index 98%
rename from libc/arch-riscv64/string/strcmp_vext.S
rename to libc/arch-riscv64/string/strcmp.S
index b793c9a..3332c83 100644
--- a/libc/arch-riscv64/string/strcmp_vext.S
+++ b/libc/arch-riscv64/string/strcmp.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define iResult a0
@@ -76,7 +74,7 @@
 #define vMask1 v16
 #define vMask2 v17
 
-ENTRY(strcmp_vext)
+ENTRY(strcmp)
 
     # increase the lmul using the following sequences:
     # 1/2, 1/2, 1, 2, 4, 4, 4, ...
@@ -168,6 +166,4 @@
     sub iResult, iTemp1, iTemp2
     ret
 
-END(strcmp_vext)
-
-#endif
+END(strcmp)
diff --git a/libc/arch-riscv64/string/strcpy_vext.S b/libc/arch-riscv64/string/strcpy.S
similarity index 97%
rename from libc/arch-riscv64/string/strcpy_vext.S
rename to libc/arch-riscv64/string/strcpy.S
index ab8da48..b89b1a8 100644
--- a/libc/arch-riscv64/string/strcpy_vext.S
+++ b/libc/arch-riscv64/string/strcpy.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -71,7 +69,7 @@
 #define vStr1 v8
 #define vStr2 v16
 
-ENTRY(strcpy_vext)
+ENTRY(strcpy)
 
     mv pDstPtr, pDst
 
@@ -90,6 +88,4 @@
 
     ret
 
-END(strcpy_vext)
-
-#endif
+END(strcpy)
diff --git a/libc/arch-riscv64/string/strlen_vext.S b/libc/arch-riscv64/string/strlen.S
similarity index 98%
rename from libc/arch-riscv64/string/strlen_vext.S
rename to libc/arch-riscv64/string/strlen.S
index 694f95c..7f7d2dd 100644
--- a/libc/arch-riscv64/string/strlen_vext.S
+++ b/libc/arch-riscv64/string/strlen.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define iResult a0
@@ -68,7 +66,7 @@
 #define vStr v0
 #define vMaskEnd v2
 
-ENTRY(strlen_vext)
+ENTRY(strlen)
 
     mv pCopyStr, pStr
 L(loop):
@@ -87,5 +85,3 @@
     ret
 
 END(strlen)
-
-#endif
diff --git a/libc/arch-riscv64/string/strncat_vext.S b/libc/arch-riscv64/string/strncat.S
similarity index 97%
rename from libc/arch-riscv64/string/strncat_vext.S
rename to libc/arch-riscv64/string/strncat.S
index 9fcd37d..01cb14f 100644
--- a/libc/arch-riscv64/string/strncat_vext.S
+++ b/libc/arch-riscv64/string/strncat.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -72,7 +70,7 @@
 #define vStr1 v8
 #define vStr2 v16
 
-ENTRY(strncat_vext)
+ENTRY(strncat)
 
     mv pDstPtr, pDst
 
@@ -116,6 +114,4 @@
 L(fill_zero_end):
     ret
 
-END(strncat_vext)
-
-#endif
+END(strncat)
diff --git a/libc/arch-riscv64/string/strncmp_vext.S b/libc/arch-riscv64/string/strncmp.S
similarity index 97%
rename from libc/arch-riscv64/string/strncmp_vext.S
rename to libc/arch-riscv64/string/strncmp.S
index ec3ec50..b9e6ee2 100644
--- a/libc/arch-riscv64/string/strncmp_vext.S
+++ b/libc/arch-riscv64/string/strncmp.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define iResult a0
@@ -73,7 +71,7 @@
 #define vMask1 v8
 #define vMask2 v9
 
-ENTRY(strncmp_vext)
+ENTRY(strncmp)
 
     beqz iLength, L(zero_length)
 
@@ -118,6 +116,4 @@
     li iResult, 0
     ret
 
-END(strncmp_vext)
-
-#endif
+END(strncmp)
diff --git a/libc/arch-riscv64/string/strncpy_vext.S b/libc/arch-riscv64/string/strncpy.S
similarity index 97%
rename from libc/arch-riscv64/string/strncpy_vext.S
rename to libc/arch-riscv64/string/strncpy.S
index eff6293..651a064 100644
--- a/libc/arch-riscv64/string/strncpy_vext.S
+++ b/libc/arch-riscv64/string/strncpy.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pDst a0
@@ -73,7 +71,7 @@
 #define vStr1 v8
 #define vStr2 v16
 
-ENTRY(strncpy_vext)
+ENTRY(strncpy)
 
     mv pDstPtr, pDst
 
@@ -113,6 +111,4 @@
 
     ret
 
-END(strncpy_vext)
-
-#endif
+END(strncpy)
diff --git a/libc/arch-riscv64/string/strnlen_vext.S b/libc/arch-riscv64/string/strnlen.S
similarity index 97%
rename from libc/arch-riscv64/string/strnlen_vext.S
rename to libc/arch-riscv64/string/strnlen.S
index ca07231..66366f0 100644
--- a/libc/arch-riscv64/string/strnlen_vext.S
+++ b/libc/arch-riscv64/string/strnlen.S
@@ -53,8 +53,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if defined(__riscv_v)
-
 #include <private/bionic_asm.h>
 
 #define pStr a0
@@ -68,7 +66,7 @@
 #define vStr v0
 #define vMaskEnd v8
 
-ENTRY(strnlen_vext)
+ENTRY(strnlen)
 
     mv pCopyStr, pStr
     mv iRetValue, iMaxlen
@@ -88,6 +86,4 @@
 L(end_strnlen_loop):
     ret
 
-END(strnlen_vext)
-
-#endif
+END(strnlen)
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index e159fdc..3c4884b 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -110,12 +110,27 @@
   if (param == M_BIONIC_ZERO_INIT) {
     return SetHeapZeroInitialize(value);
   }
+
   // The rest we pass on...
+  int retval;
   auto dispatch_table = GetDispatchTable();
   if (__predict_false(dispatch_table != nullptr)) {
-    return dispatch_table->mallopt(param, value);
+    retval = dispatch_table->mallopt(param, value);
+  } else {
+    retval = Malloc(mallopt)(param, value);
   }
-  return Malloc(mallopt)(param, value);
+
+  // Track the M_DECAY_TIME mallopt calls.
+  if (param == M_DECAY_TIME && retval == 1) {
+    __libc_globals.mutate([value](libc_globals* globals) {
+      if (value == 0) {
+        atomic_store(&globals->decay_time_enabled, false);
+      } else {
+        atomic_store(&globals->decay_time_enabled, true);
+      }
+    });
+  }
+  return retval;
 }
 
 extern "C" void* malloc(size_t bytes) {
@@ -341,6 +356,14 @@
     *reinterpret_cast<bool*>(arg) = atomic_load(&__libc_globals->memtag_stack);
     return true;
   }
+  if (opcode == M_GET_DECAY_TIME_ENABLED) {
+    if (arg == nullptr || arg_size != sizeof(bool)) {
+      errno = EINVAL;
+      return false;
+    }
+    *reinterpret_cast<bool*>(arg) = atomic_load(&__libc_globals->decay_time_enabled);
+    return true;
+  }
   errno = ENOTSUP;
   return false;
 }
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 802a94f..792a114 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -543,6 +543,14 @@
     *reinterpret_cast<bool*>(arg) = atomic_load(&__libc_globals->memtag_stack);
     return true;
   }
+  if (opcode == M_GET_DECAY_TIME_ENABLED) {
+    if (arg == nullptr || arg_size != sizeof(bool)) {
+      errno = EINVAL;
+      return false;
+    }
+    *reinterpret_cast<bool*>(arg) = atomic_load(&__libc_globals->decay_time_enabled);
+    return true;
+  }
   // Try heapprofd's mallopt, as it handles options not covered here.
   return HeapprofdMallopt(opcode, arg, arg_size);
 }
diff --git a/libc/bionic/system_property_api.cpp b/libc/bionic/system_property_api.cpp
index a641f12..8fdea59 100644
--- a/libc/bionic/system_property_api.cpp
+++ b/libc/bionic/system_property_api.cpp
@@ -29,6 +29,7 @@
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
+#include <async_safe/CHECK.h>
 #include <system_properties/prop_area.h>
 #include <system_properties/system_properties.h>
 
@@ -45,7 +46,7 @@
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int __system_properties_init() {
-  return system_properties.Init(PROP_FILENAME) ? 0 : -1;
+  return system_properties.Init(PROP_DIRNAME) ? 0 : -1;
 }
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
@@ -55,8 +56,8 @@
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 int __system_property_area_init() {
-  bool fsetxattr_failed = false;
-  return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
+  bool fsetxattr_fail = false;
+  return system_properties.AreaInit(PROP_DIRNAME, &fsetxattr_fail) && !fsetxattr_fail ? 0 : -1;
 }
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
@@ -129,3 +130,9 @@
 int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
   return system_properties.Foreach(propfn, cookie);
 }
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+int __system_properties_zygote_reload(void) {
+  CHECK(getpid() == gettid());
+  return system_properties.Reload(false) ? 0 : -1;
+}
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index 943d4c6..30dea89 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -41,7 +41,7 @@
 __BEGIN_DECLS
 
 #define PROP_SERVICE_NAME "property_service"
-#define PROP_FILENAME "/dev/__properties__"
+#define PROP_DIRNAME "/dev/__properties__"
 
 #define PROP_MSG_SETPROP 1
 #define PROP_MSG_SETPROP2 0x00020001
@@ -129,6 +129,18 @@
  */
 int __system_properties_init(void);
 
+/*
+ * Reloads the system properties from disk.
+ * Not intended for use by any apps except the Zygote. Should only be called from the main thread.
+ *
+ * NOTE: Any pointers received from methods such as __system_property_find should be assumed to be
+ * invalid after this method is called.
+ *
+ * Returns 0 on success, -1 if the system properties failed to re-initialize (same conditions as
+ * __system properties_init)
+ */
+int __system_properties_zygote_reload(void); __INTRODUCED_IN(__ANDROID_API_V__)
+
 /* Deprecated: use __system_property_wait instead. */
 uint32_t __system_property_wait_any(uint32_t __old_serial);
 
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 824682b..156e9ee 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1600,6 +1600,7 @@
     tzalloc;
     tzfree;
     wcsrtombs_l;
+    __system_properties_zygote_reload; # apex
 } LIBC_U;
 
 LIBC_PRIVATE {
diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h
index 0a6546e..a06b8ee 100644
--- a/libc/platform/bionic/malloc.h
+++ b/libc/platform/bionic/malloc.h
@@ -104,6 +104,13 @@
   // Query whether memtag stack is enabled for this process.
   M_MEMTAG_STACK_IS_ON = 11,
 #define M_MEMTAG_STACK_IS_ON M_MEMTAG_STACK_IS_ON
+  // Query whether the current process has the decay time enabled so that
+  // the memory from allocations are not immediately released to the OS.
+  // Result is assigned to the arg pointer's destination.
+  //   arg = bool*
+  //   arg_size = sizeof(bool)
+  M_GET_DECAY_TIME_ENABLED = 12,
+#define M_GET_DECAY_TIME_ENABLED M_GET_DECAY_TIME_ENABLED
 };
 
 #pragma clang diagnostic push
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index d9c4234..15b570d 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -49,6 +49,7 @@
   long setjmp_cookie;
   uintptr_t heap_pointer_tag;
   _Atomic(bool) memtag_stack;
+  _Atomic(bool) decay_time_enabled;
 
   // In order to allow a complete switch between dispatch tables without
   // the need for copying each function by function in the structure,
diff --git a/libc/system_properties/contexts_serialized.cpp b/libc/system_properties/contexts_serialized.cpp
index f05aaa0..73c9136 100644
--- a/libc/system_properties/contexts_serialized.cpp
+++ b/libc/system_properties/contexts_serialized.cpp
@@ -38,6 +38,7 @@
 #include <new>
 
 #include <async_safe/log.h>
+#include <private/android_filesystem_config.h>
 
 #include "system_properties/system_properties.h"
 
@@ -59,25 +60,28 @@
   context_nodes_mmap_size_ = context_nodes_mmap_size;
 
   for (size_t i = 0; i < num_context_nodes; ++i) {
-    new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), filename_);
+    new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), dirname_);
   }
 
   return true;
 }
 
 bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
-  PropertiesFilename filename(filename_, "properties_serial");
   if (access_rw) {
     serial_prop_area_ = prop_area::map_prop_area_rw(
-        filename.c_str(), "u:object_r:properties_serial:s0", fsetxattr_failed);
+        serial_filename_.c_str(), "u:object_r:properties_serial:s0", fsetxattr_failed);
   } else {
-    serial_prop_area_ = prop_area::map_prop_area(filename.c_str());
+    serial_prop_area_ = prop_area::map_prop_area(serial_filename_.c_str());
   }
   return serial_prop_area_;
 }
 
-bool ContextsSerialized::InitializeProperties() {
-  if (!property_info_area_file_.LoadDefaultPath()) {
+// Note: load_default_path is only used for testing, as it will cause properties to be loaded from
+// one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
+bool ContextsSerialized::InitializeProperties(bool load_default_path) {
+  if (load_default_path && !property_info_area_file_.LoadDefaultPath()) {
+    return false;
+  } else if (!load_default_path && !property_info_area_file_.LoadPath(tree_filename_.c_str())) {
     return false;
   }
 
@@ -89,14 +93,20 @@
   return true;
 }
 
-bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
-  filename_ = filename;
-  if (!InitializeProperties()) {
+// Note: load_default_path is only used for testing, as it will cause properties to be loaded from
+// one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
+bool ContextsSerialized::Initialize(bool writable, const char* dirname, bool* fsetxattr_failed,
+                                    bool load_default_path) {
+  dirname_ = dirname;
+  tree_filename_ = PropertiesFilename(dirname, "property_info");
+  serial_filename_ = PropertiesFilename(dirname, "properties_serial");
+
+  if (!InitializeProperties(load_default_path)) {
     return false;
   }
 
   if (writable) {
-    mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
+    mkdir(dirname_, S_IRWXU | S_IXGRP | S_IXOTH);
     bool open_failed = false;
     if (fsetxattr_failed) {
       *fsetxattr_failed = false;
diff --git a/libc/system_properties/contexts_split.cpp b/libc/system_properties/contexts_split.cpp
index 3579f55..78bdc64 100644
--- a/libc/system_properties/contexts_split.cpp
+++ b/libc/system_properties/contexts_split.cpp
@@ -281,7 +281,7 @@
   return true;
 }
 
-bool ContextsSplit::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
+bool ContextsSplit::Initialize(bool writable, const char* filename, bool* fsetxattr_failed, bool) {
   filename_ = filename;
   if (!InitializeProperties()) {
     return false;
diff --git a/libc/system_properties/include/system_properties/contexts.h b/libc/system_properties/include/system_properties/contexts.h
index 670f808..df8c5a2 100644
--- a/libc/system_properties/include/system_properties/contexts.h
+++ b/libc/system_properties/include/system_properties/contexts.h
@@ -36,7 +36,8 @@
   virtual ~Contexts() {
   }
 
-  virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) = 0;
+  virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed,
+                          bool load_default_path = false) = 0;
   virtual prop_area* GetPropAreaForName(const char* name) = 0;
   virtual prop_area* GetSerialPropArea() = 0;
   virtual void ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) = 0;
diff --git a/libc/system_properties/include/system_properties/contexts_pre_split.h b/libc/system_properties/include/system_properties/contexts_pre_split.h
index 6e695e9..a6cd039 100644
--- a/libc/system_properties/include/system_properties/contexts_pre_split.h
+++ b/libc/system_properties/include/system_properties/contexts_pre_split.h
@@ -38,7 +38,7 @@
   }
 
   // We'll never initialize this legacy option as writable, so don't even check the arg.
-  virtual bool Initialize(bool, const char* filename, bool*) override {
+  virtual bool Initialize(bool, const char* filename, bool*, bool) override {
     pre_split_prop_area_ = prop_area::map_prop_area(filename);
     return pre_split_prop_area_ != nullptr;
   }
diff --git a/libc/system_properties/include/system_properties/contexts_serialized.h b/libc/system_properties/include/system_properties/contexts_serialized.h
index 93d6ac1..8bb0b11 100644
--- a/libc/system_properties/include/system_properties/contexts_serialized.h
+++ b/libc/system_properties/include/system_properties/contexts_serialized.h
@@ -32,13 +32,15 @@
 
 #include "context_node.h"
 #include "contexts.h"
+#include "properties_filename.h"
 
 class ContextsSerialized : public Contexts {
  public:
   virtual ~ContextsSerialized() override {
   }
 
-  virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) override;
+  virtual bool Initialize(bool writable, const char* dirname, bool* fsetxattr_failed,
+                          bool load_default_path) override;
   virtual prop_area* GetPropAreaForName(const char* name) override;
   virtual prop_area* GetSerialPropArea() override {
     return serial_prop_area_;
@@ -49,10 +51,12 @@
 
  private:
   bool InitializeContextNodes();
-  bool InitializeProperties();
+  bool InitializeProperties(bool load_default_path);
   bool MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed);
 
-  const char* filename_;
+  const char* dirname_;
+  PropertiesFilename tree_filename_;
+  PropertiesFilename serial_filename_;
   android::properties::PropertyInfoAreaFile property_info_area_file_;
   ContextNode* context_nodes_ = nullptr;
   size_t num_context_nodes_ = 0;
diff --git a/libc/system_properties/include/system_properties/contexts_split.h b/libc/system_properties/include/system_properties/contexts_split.h
index 1d954cc..321cfd2 100644
--- a/libc/system_properties/include/system_properties/contexts_split.h
+++ b/libc/system_properties/include/system_properties/contexts_split.h
@@ -38,7 +38,8 @@
   virtual ~ContextsSplit() override {
   }
 
-  virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed) override;
+  virtual bool Initialize(bool writable, const char* filename, bool* fsetxattr_failed,
+                          bool) override;
   virtual prop_area* GetPropAreaForName(const char* name) override;
   virtual prop_area* GetSerialPropArea() override {
     return serial_prop_area_;
diff --git a/libc/arch-riscv64/static_function_dispatch.S b/libc/system_properties/include/system_properties/properties_filename.h
similarity index 64%
rename from libc/arch-riscv64/static_function_dispatch.S
rename to libc/system_properties/include/system_properties/properties_filename.h
index f96d40e..d686f20 100644
--- a/libc/arch-riscv64/static_function_dispatch.S
+++ b/libc/system_properties/include/system_properties/properties_filename.h
@@ -26,31 +26,26 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
+#pragma once
 
-#define FUNCTION_DELEGATE(name, impl) \
-ENTRY(name); \
-    j impl; \
-END(name)
+#include <stdint.h>
 
-#if defined(__riscv_v)
+class PropertiesFilename {
+ public:
+  PropertiesFilename() = default;
+  PropertiesFilename(const char* dir, const char* file) {
+    if (snprintf(filename_, sizeof(filename_), "%s/%s", dir, file) >=
+        static_cast<int>(sizeof(filename_))) {
+      abort();
+    }
+  }
+  void operator=(const char* value) {
+    if (strlen(value) >= sizeof(filename_)) abort();
+    strcpy(filename_, value);
+  }
+  const char* c_str() { return filename_; }
 
-FUNCTION_DELEGATE(memchr, memchr_vext)
-FUNCTION_DELEGATE(memcmp, memcmp_vext)
-FUNCTION_DELEGATE(memcpy, memcpy_vext)
-FUNCTION_DELEGATE(memmove, memmove_vext)
-FUNCTION_DELEGATE(memset, memset_vext)
-FUNCTION_DELEGATE(stpcpy, stpcpy_vext)
-FUNCTION_DELEGATE(strcat, strcat_vext)
-FUNCTION_DELEGATE(strchr, strchr_vext)
-FUNCTION_DELEGATE(strcmp, strcmp_vext)
-FUNCTION_DELEGATE(strcpy, strcpy_vext)
-FUNCTION_DELEGATE(strlen, strlen_vext)
-FUNCTION_DELEGATE(strncat, strncat_vext)
-FUNCTION_DELEGATE(strncmp, strncmp_vext)
-FUNCTION_DELEGATE(strncpy, strncpy_vext)
-FUNCTION_DELEGATE(strnlen, strnlen_vext)
-
-#endif
-
-NOTE_GNU_PROPERTY()
+ private:
+  // Typically something like "/dev/__properties__/properties_serial".
+  char filename_[128];
+};
diff --git a/libc/system_properties/include/system_properties/system_properties.h b/libc/system_properties/include/system_properties/system_properties.h
index 4d84b39..ea4f339 100644
--- a/libc/system_properties/include/system_properties/system_properties.h
+++ b/libc/system_properties/include/system_properties/system_properties.h
@@ -28,7 +28,6 @@
 
 #pragma once
 
-#include <stdint.h>
 #include <sys/param.h>
 #include <sys/system_properties.h>
 
@@ -37,26 +36,6 @@
 #include "contexts_serialized.h"
 #include "contexts_split.h"
 
-class PropertiesFilename {
- public:
-  PropertiesFilename() = default;
-  PropertiesFilename(const char* dir, const char* file) {
-    if (snprintf(filename_, sizeof(filename_), "%s/%s", dir, file) >=
-        static_cast<int>(sizeof(filename_))) {
-      abort();
-    }
-  }
-  void operator=(const char* value) {
-    if (strlen(value) >= sizeof(filename_)) abort();
-    strcpy(filename_, value);
-  }
-  const char* c_str() { return filename_; }
-
- private:
-  // Typically something like "/dev/__properties__/properties_serial".
-  char filename_[128];
-};
-
 class SystemProperties {
  public:
   friend struct LocalPropertyTestState;
@@ -73,7 +52,9 @@
   BIONIC_DISALLOW_COPY_AND_ASSIGN(SystemProperties);
 
   bool Init(const char* filename);
+  bool Reload(bool load_default_path);
   bool AreaInit(const char* filename, bool* fsetxattr_failed);
+  bool AreaInit(const char* filename, bool* fsetxattr_failed, bool load_default_path);
   uint32_t AreaSerial();
   const prop_info* Find(const char* name);
   int Read(const prop_info* pi, char* name, char* value);
@@ -101,8 +82,14 @@
   static constexpr size_t kMaxContextsSize =
       MAX(sizeof(ContextsSerialized), MAX(sizeof(ContextsSplit), sizeof(ContextsPreSplit)));
   alignas(kMaxContextsAlign) char contexts_data_[kMaxContextsSize];
+  alignas(kMaxContextsAlign) char appcompat_override_contexts_data_[kMaxContextsSize];
   Contexts* contexts_;
+  // See http://b/291816546#comment#3 for more explanation of appcompat_override
+  Contexts* appcompat_override_contexts_;
+
+  bool InitContexts(bool load_default_path);
 
   bool initialized_;
   PropertiesFilename properties_filename_;
+  PropertiesFilename appcompat_filename_;
 };
diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp
index 049236f..9dd5e35 100644
--- a/libc/system_properties/system_properties.cpp
+++ b/libc/system_properties/system_properties.cpp
@@ -29,6 +29,7 @@
 #include "system_properties/system_properties.h"
 
 #include <errno.h>
+#include <private/android_filesystem_config.h>
 #include <stdatomic.h>
 #include <stdlib.h>
 #include <string.h>
@@ -38,6 +39,7 @@
 
 #include <new>
 
+#include <async_safe/CHECK.h>
 #include <async_safe/log.h>
 
 #include "private/ErrnoRestorer.h"
@@ -49,6 +51,7 @@
 
 #define SERIAL_DIRTY(serial) ((serial)&1)
 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
+#define APPCOMPAT_PREFIX "ro.appcompat_override."
 
 static bool is_dir(const char* pathname) {
   struct stat info;
@@ -69,10 +72,21 @@
 
   properties_filename_ = filename;
 
+  if (!InitContexts(false)) {
+    return false;
+  }
+
+  initialized_ = true;
+  return true;
+}
+
+bool SystemProperties::InitContexts(bool load_default_path) {
   if (is_dir(properties_filename_.c_str())) {
-    if (access("/dev/__properties__/property_info", R_OK) == 0) {
-      contexts_ = new (contexts_data_) ContextsSerialized();
-      if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
+    if (access(PROP_TREE_FILE, R_OK) == 0) {
+      auto serial_contexts = new (contexts_data_) ContextsSerialized();
+      contexts_ = serial_contexts;
+      if (!serial_contexts->Initialize(false, properties_filename_.c_str(), nullptr,
+                                       load_default_path)) {
         return false;
       }
     } else {
@@ -87,20 +101,46 @@
       return false;
     }
   }
-  initialized_ = true;
   return true;
 }
 
 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
+  return AreaInit(filename, fsetxattr_failed, false);
+}
+
+// Note: load_default_path is only used for testing, as it will cause properties to be loaded from
+// one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
+bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed,
+                                bool load_default_path) {
   properties_filename_ = filename;
-  contexts_ = new (contexts_data_) ContextsSerialized();
-  if (!contexts_->Initialize(true, properties_filename_.c_str(), fsetxattr_failed)) {
+  auto serial_contexts = new (contexts_data_) ContextsSerialized();
+  contexts_ = serial_contexts;
+  if (!serial_contexts->Initialize(true, properties_filename_.c_str(), fsetxattr_failed,
+                                   load_default_path)) {
     return false;
   }
+
+  auto* appcompat_contexts = new (appcompat_override_contexts_data_) ContextsSerialized();
+  appcompat_filename_ = PropertiesFilename(properties_filename_.c_str(), "appcompat_override");
+  if (!appcompat_contexts->Initialize(true, appcompat_filename_.c_str(), fsetxattr_failed,
+                                      load_default_path)) {
+    appcompat_override_contexts_ = nullptr;
+    return false;
+  }
+  appcompat_override_contexts_ = appcompat_contexts;
+
   initialized_ = true;
   return true;
 }
 
+bool SystemProperties::Reload(bool load_default_path) {
+  if (!initialized_) {
+    return true;
+  }
+
+  return InitContexts(load_default_path);
+}
+
 uint32_t SystemProperties::AreaSerial() {
   if (!initialized_) {
     return -1;
@@ -129,6 +169,10 @@
   return pa->find(name);
 }
 
+static bool is_appcompat_override(const char* name) {
+  return strncmp(name, APPCOMPAT_PREFIX, strlen(APPCOMPAT_PREFIX)) == 0;
+}
+
 static bool is_read_only(const char* name) {
   return strncmp(name, "ro.", 3) == 0;
 }
@@ -227,16 +271,24 @@
   if (!initialized_) {
     return -1;
   }
+  bool have_override = appcompat_override_contexts_ != nullptr;
 
   prop_area* serial_pa = contexts_->GetSerialPropArea();
+  prop_area* override_serial_pa =
+      have_override ? appcompat_override_contexts_->GetSerialPropArea() : nullptr;
   if (!serial_pa) {
     return -1;
   }
   prop_area* pa = contexts_->GetPropAreaForName(pi->name);
+  prop_area* override_pa =
+      have_override ? appcompat_override_contexts_->GetPropAreaForName(pi->name) : nullptr;
   if (__predict_false(!pa)) {
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
     return -1;
   }
+  CHECK(!have_override || (override_pa && override_serial_pa));
+
+  auto* override_pi = const_cast<prop_info*>(have_override ? override_pa->find(pi->name) : nullptr);
 
   uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
   unsigned int old_len = SERIAL_VALUE_LEN(serial);
@@ -246,18 +298,34 @@
   // that we publish our dirty area update before allowing readers to see a
   // dirty serial.
   memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
+  if (have_override) {
+    memcpy(override_pa->dirty_backup_area(), override_pi->value, old_len + 1);
+  }
   atomic_thread_fence(memory_order_release);
   serial |= 1;
   atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
   strlcpy(pi->value, value, len + 1);
+  if (have_override) {
+    atomic_store_explicit(&override_pi->serial, serial, memory_order_relaxed);
+    strlcpy(override_pi->value, value, len + 1);
+  }
   // Now the primary value property area is up-to-date. Let readers know that they should
   // look at the property value instead of the backup area.
   atomic_thread_fence(memory_order_release);
-  atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed);
+  int new_serial = (len << 24) | ((serial + 1) & 0xffffff);
+  atomic_store_explicit(&pi->serial, new_serial, memory_order_relaxed);
+  if (have_override) {
+    atomic_store_explicit(&override_pi->serial, new_serial, memory_order_relaxed);
+  }
   __futex_wake(&pi->serial, INT32_MAX);  // Fence by side effect
   atomic_store_explicit(serial_pa->serial(),
                         atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
                         memory_order_release);
+  if (have_override) {
+    atomic_store_explicit(override_serial_pa->serial(),
+                          atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
+                          memory_order_release);
+  }
   __futex_wake(serial_pa->serial(), INT32_MAX);
 
   return 0;
@@ -293,6 +361,34 @@
     return -1;
   }
 
+  if (appcompat_override_contexts_ != nullptr) {
+    bool is_override = is_appcompat_override(name);
+    const char* override_name = name;
+    if (is_override) override_name += strlen(APPCOMPAT_PREFIX);
+    prop_area* other_pa = appcompat_override_contexts_->GetPropAreaForName(override_name);
+    prop_area* other_serial_pa = appcompat_override_contexts_->GetSerialPropArea();
+    CHECK(other_pa && other_serial_pa);
+    // We may write a property twice to overrides, once for the ro.*, and again for the
+    // ro.appcompat_override.ro.* property. If we've already written, then we should essentially
+    // perform an Update, not an Add.
+    auto other_pi = const_cast<prop_info*>(other_pa->find(override_name));
+    if (!other_pi) {
+      if (other_pa->add(override_name, strlen(override_name), value, valuelen)) {
+        atomic_store_explicit(
+            other_serial_pa->serial(),
+            atomic_load_explicit(other_serial_pa->serial(), memory_order_relaxed) + 1,
+            memory_order_release);
+      }
+    } else if (is_override) {
+      // We already wrote the ro.*, but appcompat_override.ro.* should override that. We don't
+      // need to do the usual dirty bit setting, as this only happens during the init process,
+      // before any readers are started. Check that only init or root can write appcompat props.
+      CHECK(getpid() == 1 || getuid() == 0);
+      atomic_thread_fence(memory_order_release);
+      strlcpy(other_pi->value, value, valuelen + 1);
+    }
+  }
+
   // There is only a single mutator, but we want to make sure that
   // updates are visible to a reader waiting for the update.
   atomic_store_explicit(serial_pa->serial(),
diff --git a/libc/upstream-freebsd/lib/libc/string/bcopy.c b/libc/upstream-freebsd/lib/libc/string/bcopy.c
deleted file mode 100644
index 84715d0..0000000
--- a/libc/upstream-freebsd/lib/libc/string/bcopy.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)bcopy.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-
-typedef	intptr_t word;		/* "word" used for optimal copy speed */
-
-#define	wsize	sizeof(word)
-#define	wmask	(wsize - 1)
-
-/*
- * Copy a block of memory, handling overlap.
- * This is the routine that actually implements
- * (the portable versions of) bcopy, memcpy, and memmove.
- */
-#if defined(MEMCOPY) || defined(MEMMOVE)
-#include <string.h>
-
-void *
-#ifdef MEMCOPY
-memcpy
-#else
-memmove
-#endif
-(void *dst0, const void *src0, size_t length)
-#else
-#include <strings.h>
-
-void
-bcopy(const void *src0, void *dst0, size_t length)
-#endif
-{
-	char *dst = dst0;
-	const char *src = src0;
-	size_t t;
-
-	if (length == 0 || dst == src)		/* nothing to do */
-		goto done;
-
-	/*
-	 * Macros: loop-t-times; and loop-t-times, t>0
-	 */
-#define	TLOOP(s) if (t) TLOOP1(s)
-#define	TLOOP1(s) do { s; } while (--t)
-
-	if ((unsigned long)dst < (unsigned long)src) {
-		/*
-		 * Copy forward.
-		 */
-		t = (uintptr_t)src;	/* only need low bits */
-		if ((t | (uintptr_t)dst) & wmask) {
-			/*
-			 * Try to align operands.  This cannot be done
-			 * unless the low bits match.
-			 */
-			if ((t ^ (uintptr_t)dst) & wmask || length < wsize)
-				t = length;
-			else
-				t = wsize - (t & wmask);
-			length -= t;
-			TLOOP1(*dst++ = *src++);
-		}
-		/*
-		 * Copy whole words, then mop up any trailing bytes.
-		 */
-		t = length / wsize;
-		TLOOP(*(word *)(void *)dst = *(const word *)(const void *)src;
-		    src += wsize; dst += wsize);
-		t = length & wmask;
-		TLOOP(*dst++ = *src++);
-	} else {
-		/*
-		 * Copy backwards.  Otherwise essentially the same.
-		 * Alignment works as before, except that it takes
-		 * (t&wmask) bytes to align, not wsize-(t&wmask).
-		 */
-		src += length;
-		dst += length;
-		t = (uintptr_t)src;
-		if ((t | (uintptr_t)dst) & wmask) {
-			if ((t ^ (uintptr_t)dst) & wmask || length <= wsize)
-				t = length;
-			else
-				t &= wmask;
-			length -= t;
-			TLOOP1(*--dst = *--src);
-		}
-		t = length / wsize;
-		TLOOP(src -= wsize; dst -= wsize;
-		    *(word *)(void *)dst = *(const word *)(const void *)src);
-		t = length & wmask;
-		TLOOP(*--dst = *--src);
-	}
-done:
-#if defined(MEMCOPY) || defined(MEMMOVE)
-	return (dst0);
-#else
-	return;
-#endif
-}
diff --git a/libc/upstream-freebsd/lib/libc/string/memcmp.c b/libc/upstream-freebsd/lib/libc/string/memcmp.c
index c8d5d92..183b09c 100644
--- a/libc/upstream-freebsd/lib/libc/string/memcmp.c
+++ b/libc/upstream-freebsd/lib/libc/string/memcmp.c
@@ -56,3 +56,4 @@
 	}
 	return (0);
 }
+
diff --git a/libc/upstream-freebsd/lib/libc/string/memcpy.c b/libc/upstream-freebsd/lib/libc/string/memcpy.c
deleted file mode 100644
index ed03856..0000000
--- a/libc/upstream-freebsd/lib/libc/string/memcpy.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#define	MEMCOPY
-#include "bcopy.c"
diff --git a/libc/upstream-freebsd/lib/libc/string/memmove.c b/libc/upstream-freebsd/lib/libc/string/memmove.c
deleted file mode 100644
index 05cf75a..0000000
--- a/libc/upstream-freebsd/lib/libc/string/memmove.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#define	MEMMOVE
-#include "bcopy.c"
diff --git a/libc/upstream-freebsd/lib/libc/string/memset.c b/libc/upstream-freebsd/lib/libc/string/memset.c
deleted file mode 100644
index e2d4027..0000000
--- a/libc/upstream-freebsd/lib/libc/string/memset.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Hibler and Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)memset.c	8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-
-#include <limits.h>
-
-#define	wsize	sizeof(u_long)
-#define	wmask	(wsize - 1)
-
-#ifdef BZERO
-#include <strings.h>
-
-#define	RETURN	return
-#define	VAL	0
-#define	WIDEVAL	0
-
-void
-bzero(void *dst0, size_t length)
-#else
-#include <string.h>
-
-#define	RETURN	return (dst0)
-#define	VAL	c0
-#define	WIDEVAL	c
-
-void *
-memset(void *dst0, int c0, size_t length)
-#endif
-{
-	size_t t;
-#ifndef BZERO
-	u_long c;
-#endif
-	u_char *dst;
-
-	dst = dst0;
-	/*
-	 * If not enough words, just fill bytes.  A length >= 2 words
-	 * guarantees that at least one of them is `complete' after
-	 * any necessary alignment.  For instance:
-	 *
-	 *	|-----------|-----------|-----------|
-	 *	|00|01|02|03|04|05|06|07|08|09|0A|00|
-	 *	          ^---------------------^
-	 *		 dst		 dst+length-1
-	 *
-	 * but we use a minimum of 3 here since the overhead of the code
-	 * to do word writes is substantial.
-	 *
-	 * TODO: This threshold might not be sensible for 64-bit u_long.
-	 * We should benchmark and revisit this decision.
-	 */
-	if (length < 3 * wsize) {
-		while (length != 0) {
-			*dst++ = VAL;
-			--length;
-		}
-		RETURN;
-	}
-
-#ifndef BZERO
-	if ((c = (u_char)c0) != 0) {	/* Fill the word. */
-		c = (c << 8) | c;	/* u_long is 16 bits. */
-#if ULONG_MAX > 0xffff
-		c = (c << 16) | c;	/* u_long is 32 bits. */
-#endif
-#if ULONG_MAX > 0xffffffff
-		c = (c << 32) | c;	/* u_long is 64 bits. */
-#endif
-	}
-#endif
-	/* Align destination by filling in bytes. */
-	if ((t = (long)dst & wmask) != 0) {
-		t = wsize - t;
-		length -= t;
-		do {
-			*dst++ = VAL;
-		} while (--t != 0);
-	}
-
-	/* Fill words.  Length was >= 2*words so we know t >= 1 here. */
-	t = length / wsize;
-	do {
-		*(u_long *)(void *)dst = WIDEVAL;
-		dst += wsize;
-	} while (--t != 0);
-
-	/* Mop up trailing bytes, if any. */
-	t = length & wmask;
-	if (t != 0)
-		do {
-			*dst++ = VAL;
-		} while (--t != 0);
-	RETURN;
-}
diff --git a/libc/upstream-openbsd/lib/libc/string/strcmp.c b/libc/upstream-openbsd/lib/libc/string/strcmp.c
deleted file mode 100644
index be17556..0000000
--- a/libc/upstream-openbsd/lib/libc/string/strcmp.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*	$OpenBSD: strcmp.c,v 1.9 2015/08/31 02:53:57 guenther Exp $	*/
-
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <string.h>
-
-/*
- * Compare strings.
- */
-int
-strcmp(const char *s1, const char *s2)
-{
-	while (*s1 == *s2++)
-		if (*s1++ == 0)
-			return (0);
-	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
-}
-DEF_STRONG(strcmp);
diff --git a/libc/upstream-openbsd/lib/libc/string/strcpy.c b/libc/upstream-openbsd/lib/libc/string/strcpy.c
deleted file mode 100644
index 290eefe..0000000
--- a/libc/upstream-openbsd/lib/libc/string/strcpy.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*	$OpenBSD: strcpy.c,v 1.10 2017/11/28 06:55:49 tb Exp $	*/
-
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <string.h>
-
-#if defined(APIWARN)
-__warn_references(strcpy,
-    "strcpy() is almost always misused, please use strlcpy()");
-#endif
-
-char *
-strcpy(char *to, const char *from)
-{
-	char *save = to;
-
-	for (; (*to = *from) != '\0'; ++from, ++to);
-	return(save);
-}
diff --git a/libc/upstream-openbsd/lib/libc/string/strlen.c b/libc/upstream-openbsd/lib/libc/string/strlen.c
deleted file mode 100644
index a5721d3..0000000
--- a/libc/upstream-openbsd/lib/libc/string/strlen.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*	$OpenBSD: strlen.c,v 1.9 2015/08/31 02:53:57 guenther Exp $	*/
-
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <string.h>
-
-size_t
-strlen(const char *str)
-{
-	const char *s;
-
-	for (s = str; *s; ++s)
-		;
-	return (s - str);
-}
-
-DEF_STRONG(strlen);
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 2411753..14a426f 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -1734,3 +1734,36 @@
     }
   }
 }
+
+TEST(android_mallopt, get_decay_time_enabled_errors) {
+#if defined(__BIONIC__)
+  errno = 0;
+  EXPECT_FALSE(android_mallopt(M_GET_DECAY_TIME_ENABLED, nullptr, sizeof(bool)));
+  EXPECT_ERRNO(EINVAL);
+
+  errno = 0;
+  int value;
+  EXPECT_FALSE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value)));
+  EXPECT_ERRNO(EINVAL);
+#else
+  GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
+TEST(android_mallopt, get_decay_time_enabled) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
+
+  EXPECT_EQ(1, mallopt(M_DECAY_TIME, 0));
+
+  bool value;
+  EXPECT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value)));
+  EXPECT_FALSE(value);
+
+  EXPECT_EQ(1, mallopt(M_DECAY_TIME, 1));
+  EXPECT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value)));
+  EXPECT_TRUE(value);
+#else
+  GTEST_SKIP() << "bionic-only test";
+#endif
+}
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index b1dfe0b..0b7f5ae 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -25,31 +25,53 @@
 
 #include <android-base/file.h>
 #include <android-base/silent_death_test.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
 
 using namespace std::literals;
 
 #if defined(__BIONIC__)
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <stdlib.h>
 #include <sys/_system_properties.h>
+#include <sys/mount.h>
 
 #include <system_properties/system_properties.h>
 
 class SystemPropertiesTest : public SystemProperties {
  public:
   SystemPropertiesTest() : SystemProperties(false) {
-    valid_ = AreaInit(dir_.path, nullptr);
+    appcompat_path = android::base::StringPrintf("%s/appcompat_override", dir_.path);
+    mount_path = android::base::StringPrintf("%s/__properties__", dir_.path);
+    mkdir(appcompat_path.c_str(), S_IRWXU | S_IXGRP | S_IXOTH);
+    valid_ = AreaInit(dir_.path, nullptr, true);
   }
   ~SystemPropertiesTest() {
     if (valid_) {
       contexts_->FreeAndUnmap();
     }
+    umount2(dir_.path, MNT_DETACH);
+    umount2(real_sysprop_dir.c_str(), MNT_DETACH);
   }
 
   bool valid() const {
     return valid_;
   }
 
+  const char* get_path() const { return dir_.path; }
+
+  const char* get_appcompat_path() const { return appcompat_path.c_str(); }
+
+  const char* get_mount_path() const { return mount_path.c_str(); }
+
+  const char* get_real_sysprop_dir() const { return real_sysprop_dir.c_str(); }
+
+  std::string appcompat_path;
+  std::string mount_path;
+  std::string real_sysprop_dir = "/dev/__properties__";
+
  private:
   TemporaryDir dir_;
   bool valid_;
@@ -125,6 +147,58 @@
 #endif // __BIONIC__
 }
 
+TEST(properties, __system_property_add_appcompat) {
+#if defined(__BIONIC__)
+    if (getuid() != 0) GTEST_SKIP() << "test requires root";
+    SystemPropertiesTest system_properties;
+    ASSERT_TRUE(system_properties.valid());
+
+    char name[] = "ro.property";
+    char override_name[] = "ro.appcompat_override.ro.property";
+    char name_not_written[] = "ro.property_other";
+    char override_with_no_real[] = "ro.appcompat_override.ro.property_other";
+    ASSERT_EQ(0, system_properties.Add(name, strlen(name), "value1", 6));
+    ASSERT_EQ(0, system_properties.Add(override_name, strlen(override_name), "value2", 6));
+    ASSERT_EQ(0, system_properties.Add(override_with_no_real, strlen(override_with_no_real),
+                                       "value3", 6));
+
+    char propvalue[PROP_VALUE_MAX];
+    ASSERT_EQ(6, system_properties.Get(name, propvalue));
+    ASSERT_STREQ(propvalue, "value1");
+
+    ASSERT_EQ(6, system_properties.Get(override_name, propvalue));
+    ASSERT_STREQ(propvalue, "value2");
+
+    ASSERT_EQ(0, system_properties.Get(name_not_written, propvalue));
+    ASSERT_STREQ(propvalue, "");
+
+    ASSERT_EQ(6, system_properties.Get(override_with_no_real, propvalue));
+    ASSERT_STREQ(propvalue, "value3");
+
+    int ret = mount(system_properties.get_appcompat_path(), system_properties.get_path(), nullptr,
+                    MS_BIND | MS_REC, nullptr);
+    if (ret != 0) {
+      ASSERT_ERRNO(0);
+    }
+    system_properties.Reload(true);
+
+    ASSERT_EQ(6, system_properties.Get(name, propvalue));
+    ASSERT_STREQ(propvalue, "value2");
+
+    ASSERT_EQ(0, system_properties.Get(override_name, propvalue));
+    ASSERT_STREQ(propvalue, "");
+
+    ASSERT_EQ(6, system_properties.Get(name_not_written, propvalue));
+    ASSERT_STREQ(propvalue, "value3");
+
+    ASSERT_EQ(0, system_properties.Get(override_with_no_real, propvalue));
+    ASSERT_STREQ(propvalue, "");
+
+#else   // __BIONIC__
+    GTEST_SKIP() << "bionic-only test";
+#endif  // __BIONIC__
+}
+
 TEST(properties, __system_property_update) {
 #if defined(__BIONIC__)
     SystemPropertiesTest system_properties;
@@ -432,7 +506,7 @@
 
   // This test only makes sense if we're talking to the real system property service.
   struct stat sb;
-  ASSERT_FALSE(stat(PROP_FILENAME, &sb) == -1 && errno == ENOENT);
+  ASSERT_FALSE(stat(PROP_DIRNAME, &sb) == -1 && errno == ENOENT);
 
   ASSERT_EXIT(__system_property_add("property", 8, "value", 5), KilledByFault(), "");
 #else // __BIONIC__
@@ -526,3 +600,93 @@
   GTEST_SKIP() << "bionic-only test";
 #endif  // __BIONIC__
 }
+
+// Note that this test affects global state of the system
+// this tests tries to mitigate this by using utime+pid
+// prefix for the property name. It is still results in
+// pollution of property service since properties cannot
+// be removed.
+//
+// Note that there is also possibility to run into "out-of-memory"
+// if this test if it is executed often enough without reboot.
+TEST(properties, __system_property_reload_no_op) {
+#if defined(__BIONIC__)
+  std::string property_name =
+      android::base::StringPrintf("debug.test.%d.%" PRId64 ".property", getpid(), NanoTime());
+  ASSERT_EQ(0, __system_property_find(property_name.c_str()));
+  ASSERT_EQ(0, __system_property_set(property_name.c_str(), "test value"));
+  ASSERT_EQ(0, __system_properties_zygote_reload());
+  const prop_info* readptr = __system_property_find(property_name.c_str());
+  std::string expected_name = property_name;
+  __system_property_read_callback(
+      readptr,
+      [](void*, const char*, const char* value, unsigned) { ASSERT_STREQ("test value", value); },
+      &expected_name);
+#else   // __BIONIC__
+  GTEST_SKIP() << "bionic-only test";
+#endif  // __BIONIC__
+}
+
+TEST(properties, __system_property_reload_invalid) {
+#if defined(__BIONIC__)
+  if (getuid() != 0) GTEST_SKIP() << "test requires root";
+  SystemPropertiesTest system_properties;
+
+  // Create an invalid property_info file, so the system will attempt to initialize a
+  // ContextSerialized
+  std::string property_info_file =
+      android::base::StringPrintf("%s/property_info", system_properties.get_path());
+  fclose(fopen(property_info_file.c_str(), "w"));
+  int ret = mount(system_properties.get_path(), system_properties.get_real_sysprop_dir(), nullptr,
+                  MS_BIND | MS_REC, nullptr);
+  if (ret != 0) {
+    ASSERT_ERRNO(0);
+  }
+
+  ASSERT_EQ(-1, __system_properties_zygote_reload());
+#else   // __BIONIC__
+  GTEST_SKIP() << "bionic-only test";
+#endif  // __BIONIC__
+}
+
+// Note that this test affects global state of the system
+// this tests tries to mitigate this by using utime+pid
+// prefix for the property name. It is still results in
+// pollution of property service since properties cannot
+// be removed.
+//
+// Note that there is also possibility to run into "out-of-memory"
+// if this test if it is executed often enough without reboot.
+TEST(properties, __system_property_reload_valid) {
+#if defined(__BIONIC__)
+  if (getuid() != 0) GTEST_SKIP() << "test requires root";
+  SystemPropertiesTest system_properties;
+
+  // Copy the system properties files into the temp directory
+  std::string shell_cmd = android::base::StringPrintf(
+      "cp -r %s %s", system_properties.get_real_sysprop_dir(), system_properties.get_path());
+  system(shell_cmd.c_str());
+
+  // Write a system property to the current set of system properties
+  std::string property_name =
+      android::base::StringPrintf("debug.test.%d.%" PRId64 ".property", getpid(), NanoTime());
+  ASSERT_EQ(0, __system_property_find(property_name.c_str()));
+  ASSERT_EQ(0, __system_property_set(property_name.c_str(), "test value"));
+
+  // Mount the temp directory (which doesn't have the property we just wrote) in place of the
+  // real one
+  int ret = mount(system_properties.get_mount_path(), system_properties.get_real_sysprop_dir(),
+                  nullptr, MS_BIND | MS_REC, nullptr);
+  if (ret != 0) {
+    ASSERT_ERRNO(0);
+  }
+
+  // reload system properties in the new dir, and verify the property we wrote after we copied the
+  // files isn't there
+  ASSERT_EQ(0, __system_properties_zygote_reload());
+  ASSERT_EQ(0, __system_property_find(property_name.c_str()));
+
+#else   // __BIONIC__
+  GTEST_SKIP() << "bionic-only test";
+#endif  // __BIONIC__
+}
diff --git a/tests/system_properties_test2.cpp b/tests/system_properties_test2.cpp
index 0953bde..0795ccd 100644
--- a/tests/system_properties_test2.cpp
+++ b/tests/system_properties_test2.cpp
@@ -28,10 +28,6 @@
 
 #if defined(__BIONIC__)
 #include <sys/system_properties.h>
-int64_t NanoTime() {
-  auto t = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now());
-  return t.time_since_epoch().count();
-}
 #endif
 
 // Note that this test affects global state of the system
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 0c7c552..e123b42 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -89,6 +89,11 @@
   }
 }
 
+int64_t NanoTime() {
+  auto t = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now());
+  return t.time_since_epoch().count();
+}
+
 bool operator==(const Errno& lhs, const Errno& rhs) {
   return lhs.errno_ == rhs.errno_;
 }
diff --git a/tests/utils.h b/tests/utils.h
index f6b7174..dcb08f5 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -316,6 +316,8 @@
 
 bool IsLowRamDevice();
 
+int64_t NanoTime();
+
 class Errno {
  public:
   Errno(int e) : errno_(e) {}