Split properties into their own class to make testing better

Reinitializing system properties can result in crashes later in the
program, and is generally not recommended or even supported.  This
change moves the actual logic for system properties into a class that
can be tested in isolation, without reinitializing the actual system
property area used in libc.

Bug: 62197783
Test: boot devices, ensure properties work
Test: system property unit tests and benchmarks
Change-Id: I9ae6e1b56c62f51a4d3fdb5b62b8926cef545649
diff --git a/libc/system_properties/contexts_split.cpp b/libc/system_properties/contexts_split.cpp
index 77f2069..b8afa29 100644
--- a/libc/system_properties/contexts_split.cpp
+++ b/libc/system_properties/contexts_split.cpp
@@ -26,22 +26,23 @@
  * SUCH DAMAGE.
  */
 
-#include "contexts_split.h"
+#include "system_properties/contexts_split.h"
 
 #include <ctype.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 
 #include <async_safe/log.h>
 
-#include "context_node.h"
-#include "property_filename.h"
+#include "system_properties/context_node.h"
+#include "system_properties/system_properties.h"
 
 class ContextListNode : public ContextNode {
  public:
-  ContextListNode(ContextListNode* next, const char* context)
-      : ContextNode(strdup(context)), next(next) {
+  ContextListNode(ContextListNode* next, const char* context, const char* filename)
+      : ContextNode(strdup(context), filename), next(next) {
   }
 
   ~ContextListNode() {
@@ -194,8 +195,7 @@
 
 bool ContextsSplit::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
   char filename[PROP_FILENAME_MAX];
-  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
-                                     property_filename);
+  int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
   if (len < 0 || len > PROP_FILENAME_MAX) {
     serial_prop_area_ = nullptr;
     return false;
@@ -245,7 +245,7 @@
     if (old_context) {
       ListAddAfterLen(&prefixes_, prop_prefix, old_context);
     } else {
-      ListAdd(&contexts_, context);
+      ListAdd(&contexts_, context, filename_);
       ListAddAfterLen(&prefixes_, prop_prefix, contexts_);
     }
     free(prop_prefix);
@@ -285,26 +285,28 @@
   return true;
 }
 
-bool ContextsSplit::Initialize(bool writable) {
+bool ContextsSplit::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
+  filename_ = filename;
   if (!InitializeProperties()) {
     return false;
   }
 
   if (writable) {
-    mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
+    mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
     bool open_failed = false;
-    bool fsetxattr_failed = false;
+    if (fsetxattr_failed) {
+      *fsetxattr_failed = false;
+    }
+
     ListForEach(contexts_, [&fsetxattr_failed, &open_failed](ContextListNode* l) {
-      if (!l->Open(true, &fsetxattr_failed)) {
+      if (!l->Open(true, fsetxattr_failed)) {
         open_failed = true;
       }
     });
-    if (open_failed || !MapSerialPropertyArea(true, &fsetxattr_failed)) {
+    if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) {
       FreeAndUnmap();
       return false;
     }
-
-    return !fsetxattr_failed;
   } else {
     if (!MapSerialPropertyArea(false, nullptr)) {
       FreeAndUnmap();