Merge "Fix some typos in the linker configuration file format documentation."
diff --git a/docs/native_allocator.md b/docs/native_allocator.md
index 97c3648..2d06e2f 100644
--- a/docs/native_allocator.md
+++ b/docs/native_allocator.md
@@ -10,7 +10,7 @@
 It is important to note that there are two modes for a native allocator
 to run in on Android. The first is the normal allocator, the second is
 called the svelte config, which is designed to run on memory constrained
-systems and be a bit slower, but take less PSS. To enable the svelte config,
+systems and be a bit slower, but take less RSS. To enable the svelte config,
 add this line to the `BoardConfig.mk` for the given target:
 
     MALLOC_SVELTE := true
@@ -55,7 +55,7 @@
 When set to zero, `mallopt(M_DECAY_TIME, 0)`, it is expected that an
 allocator will attempt to purge and release any unused memory back to the
 kernel on free calls. This is important in Android to avoid consuming extra
-PSS.
+RSS.
 
 When set to non-zero, `mallopt(M_DECAY_TIME, 1)`, an allocator can delay the
 purge and release action. The amount of delay is up to the allocator
@@ -65,13 +65,13 @@
 The drawback to this option is that most allocators do not have a separate
 thread to handle the purge, so the decay is only handled when an
 allocation operation occurs. For server processes, this can mean that
-PSS is slightly higher when the server is waiting for the next connection
+RSS is slightly higher when the server is waiting for the next connection
 and no other allocation calls are made. The `M_PURGE` option is used to
 force a purge in this case.
 
 For all applications on Android, the call `mallopt(M_DECAY_TIME, 1)` is
 made by default. The idea is that it allows application frees to run a
-bit faster, while only increasing PSS a bit.
+bit faster, while only increasing RSS a bit.
 
 #### M\_PURGE
 When called, `mallopt(M_PURGE, 0)`, an allocator should purge and release
@@ -115,7 +115,7 @@
 ## Performance
 There are multiple different ways to evaluate the performance of a native
 allocator on Android. One is allocation speed in various different scenarios,
-anoher is total PSS taken by the allocator.
+another is total RSS taken by the allocator.
 
 The last is virtual address space consumed in 32 bit applications. There is
 a limited amount of address space available in 32 bit apps, and there have
@@ -129,7 +129,7 @@
     mmma -j bionic/benchmarks
 
 These benchmarks are only used to verify the speed of the allocator and
-ignore anything related to PSS and virtual address space consumed.
+ignore anything related to RSS and virtual address space consumed.
 
 #### Allocate/Free Benchmarks
 These are the benchmarks to verify the allocation speed of a loop doing a
@@ -228,7 +228,7 @@
 These numbers should be as performant as the current allocator.
 
 ### Memory Trace Benchmarks
-These benchmarks measure all three axes of a native allocator, PSS, virtual
+These benchmarks measure all three axes of a native allocator, RSS, virtual
 address space consumed, speed of allocation. They are designed to
 run on a trace of the allocations from a real world application or system
 process.
@@ -248,7 +248,7 @@
     /data/benchmarktest/trace_benchmark/trace_benchmark
 
 #### Memory Replay Benchmarks
-These benchmarks display PSS, virtual memory consumed (VA space), and do a
+These benchmarks display RSS, virtual memory consumed (VA space), and do a
 bit of performance testing on actual traces taken from running applications.
 
 The trace data includes what thread does each operation, so the replay
@@ -279,8 +279,8 @@
 
 Where XXX.txt is the name of a trace file.
 
-Every 100000 allocation operations, a dump of the PSS and VA space will be
-performed. At the end, a final PSS and VA space number will be printed.
+Every 100000 allocation operations, a dump of the RSS and VA space will be
+performed. At the end, a final RSS and VA space number will be printed.
 For the most part, the intermediate data can be ignored, but it is always
 a good idea to look over the data to verify that no strange spikes are
 occurring.
@@ -304,6 +304,14 @@
 executable, the virtual address space consumed is not much larger than the
 current allocator. A small increase (on the order of a few MBs) would be okay.
 
+There is no specific benchmark for memory fragmentation, instead, the RSS
+when running the memory traces acts as a proxy for this. An allocator that
+is fragmenting badly will show an increase in RSS. The best trace for
+tracking fragmentation is system\_server.txt which is an extremely long
+trace (~13 million operations). The total number of live allocations goes
+up and down a bit, but stays mostly the same so an allocator that fragments
+badly would likely show an abnormal increase in RSS on this trace.
+
 NOTE: When a native allocator calls mmap, it is expected that the allocator
 will name the map using the call:
 
diff --git a/libc/bionic/__cxa_guard.cpp b/libc/bionic/__cxa_guard.cpp
index 30b5f41..e2e7477 100644
--- a/libc/bionic/__cxa_guard.cpp
+++ b/libc/bionic/__cxa_guard.cpp
@@ -16,9 +16,7 @@
 
 #include <endian.h>
 #include <limits.h>
-#undef _USING_LIBCXX  // Prevent using of <atomic>.
 #include <stdatomic.h>
-
 #include <stddef.h>
 
 #include "private/bionic_futex.h"
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index dd3a96e..4ebc796 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -106,30 +106,8 @@
 }
 
 void __libc_init_fdsan() {
-  constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE;
-  const prop_info* pi = __system_property_find(kFdsanPropertyName);
-  if (!pi) {
-    android_fdsan_set_error_level(default_level);
-    return;
-  }
-  __system_property_read_callback(
-      pi,
-      [](void*, const char*, const char* value, uint32_t) {
-        if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) {
-          android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
-        } else if (strcasecmp(value, "warn") == 0) {
-          android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
-        } else if (strcasecmp(value, "warn_once") == 0) {
-          android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
-        } else {
-          if (strlen(value) != 0 && strcasecmp(value, "0") != 0) {
-            async_safe_format_log(ANDROID_LOG_ERROR, "libc",
-                                  "debug.fdsan set to unknown value '%s', disabling", value);
-          }
-          android_fdsan_set_error_level(default_level);
-        }
-      },
-      nullptr);
+  constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_FATAL;
+  android_fdsan_set_error_level_from_property(default_level);
 }
 
 static FdTable& GetFdTable() {
@@ -355,6 +333,45 @@
   return atomic_exchange(&GetFdTable().error_level, new_level);
 }
 
+android_fdsan_error_level android_fdsan_set_error_level_from_property(
+    android_fdsan_error_level default_level) {
+  const prop_info* pi = __system_property_find(kFdsanPropertyName);
+  if (!pi) {
+    return android_fdsan_set_error_level(default_level);
+  }
+
+  struct callback_data {
+    android_fdsan_error_level default_value;
+    android_fdsan_error_level result;
+  };
+
+  callback_data data;
+  data.default_value = default_level;
+
+  __system_property_read_callback(
+      pi,
+      [](void* arg, const char*, const char* value, uint32_t) {
+        callback_data* data = static_cast<callback_data*>(arg);
+
+        if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) {
+          data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
+        } else if (strcasecmp(value, "warn") == 0) {
+          data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
+        } else if (strcasecmp(value, "warn_once") == 0) {
+          data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
+        } else {
+          if (strlen(value) != 0 && strcasecmp(value, "0") != 0) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                                  "debug.fdsan set to unknown value '%s', disabling", value);
+          }
+          data->result = android_fdsan_set_error_level(data->default_value);
+        }
+      },
+      &data);
+
+  return data.result;
+}
+
 int close(int fd) {
   int rc = android_fdsan_close_with_tag(fd, 0);
   if (rc == -1 && errno == EINTR) {
diff --git a/libc/include/android/fdsan.h b/libc/include/android/fdsan.h
index 1169ed0..83b9318 100644
--- a/libc/include/android/fdsan.h
+++ b/libc/include/android/fdsan.h
@@ -197,4 +197,8 @@
  */
 enum android_fdsan_error_level android_fdsan_set_error_level(enum android_fdsan_error_level new_level) __INTRODUCED_IN(29) __attribute__((__weak__));
 
+/*
+ * Set the error level to the global setting if available, or a default value.
+ */
+enum android_fdsan_error_level android_fdsan_set_error_level_from_property(enum android_fdsan_error_level default_level) __INTRODUCED_IN(30) __attribute__((__weak__));
 __END_DECLS
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index b06f3e6..29c0f4a 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -26,10 +26,13 @@
  * SUCH DAMAGE.
  */
 
-#include "linker.h"
-#include <android/api-level.h>
 #include <atomic>
 
+#include <android/api-level.h>
+#include <android/fdsan.h>
+
+#include "linker.h"
+
 static std::atomic<int> g_target_sdk_version(__ANDROID_API__);
 
 void set_application_target_sdk_version(int target) {
@@ -38,6 +41,10 @@
     target = __ANDROID_API__;
   }
   g_target_sdk_version = target;
+
+  if (target < 30) {
+    android_fdsan_set_error_level_from_property(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
+  }
 }
 
 int get_application_target_sdk_version() {