Enable libcutils property_get()/property_set() on the host.

Expose working equivalents of the bionic __system_property_get() and
__system_property_set() functions for libcutils to use.

Various improvements to the implementations so that we can pass all the
libcutils tests too.

Bug: http://b/151789258
Test: treehugger
Change-Id: If4634d1ac11cc7c84c029518beedfa653f74f66b
diff --git a/properties.cpp b/properties.cpp
index 5c9ec7e..8190987 100644
--- a/properties.cpp
+++ b/properties.cpp
@@ -32,6 +32,39 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 
+#if !defined(__BIONIC__)
+
+#define PROP_VALUE_MAX 92
+
+static std::map<std::string, std::string>& g_properties = *new std::map<std::string, std::string>;
+
+int __system_property_set(const char* key, const char* value) {
+  if (key == nullptr || *key == '\0') return -1;
+  if (value == nullptr) value = "";
+
+  bool read_only = !strncmp(key, "ro.", 3);
+  if (read_only) {
+    const auto [it, success] = g_properties.insert({key, value});
+    return success ? 0 : -1;
+  }
+
+  if (strlen(value) >= 92) return -1;
+  g_properties[key] = value;
+  return 0;
+}
+
+int __system_property_get(const char* key, char* value) {
+  auto it = g_properties.find(key);
+  if (it == g_properties.end()) {
+    *value = '\0';
+    return 0;
+  }
+  snprintf(value, PROP_VALUE_MAX, "%s", it->second.c_str());
+  return strlen(value);
+}
+
+#endif
+
 namespace android {
 namespace base {
 
@@ -73,14 +106,6 @@
 template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
 template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
 
-#if !defined(__BIONIC__)
-static std::map<std::string, std::string>& g_properties = *new std::map<std::string, std::string>;
-static int __system_property_set(const char* key, const char* value) {
-  g_properties[key] = value;
-  return 0;
-}
-#endif
-
 std::string GetProperty(const std::string& key, const std::string& default_value) {
   std::string property_value;
 #if defined(__BIONIC__)
@@ -94,6 +119,7 @@
                                   },
                                   &property_value);
 #else
+  // TODO: implement host __system_property_find()/__system_property_read_callback()?
   auto it = g_properties.find(key);
   if (it == g_properties.end()) return default_value;
   property_value = it->second;