libcutils: reimplement system property functions with libbase.

This makes the system property functions available on the host too, and
ensures a consistent view of system properties between libcutils and
libbase, if you have code running on the host that uses both.

Bug: http://b/151789258
Test: treehugger
Change-Id: Ie524a77d0c392d7b23e9d12becbb1bf53c81eac6
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 5dbbeba..03f0496 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -16,27 +16,19 @@
 
 #include <cutils/properties.h>
 
-#define LOG_TAG "properties"
-// #define LOG_NDEBUG 0
-
-#include <assert.h>
-#include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <cutils/sockets.h>
-#include <log/log.h>
+#include <android-base/properties.h>
 
-int8_t property_get_bool(const char *key, int8_t default_value) {
-    if (!key) {
-        return default_value;
-    }
+int8_t property_get_bool(const char* key, int8_t default_value) {
+    if (!key) return default_value;
 
     int8_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0'};
+    char buf[PROPERTY_VALUE_MAX] = {};
 
     int len = property_get(key, buf, "");
     if (len == 1) {
@@ -57,73 +49,53 @@
     return result;
 }
 
-// Convert string property to int (default if fails); return default value if out of bounds
-static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
-                                  intmax_t default_value) {
-    if (!key) {
-        return default_value;
+template <typename T>
+static T property_get_int(const char* key, T default_value) {
+    if (!key) return default_value;
+
+    char value[PROPERTY_VALUE_MAX] = {};
+    if (property_get(key, value, "") < 1) return default_value;
+
+    // libcutils unwisely allows octal, which libbase doesn't.
+    T result = default_value;
+    int saved_errno = errno;
+    errno = 0;
+    char* end = nullptr;
+    intmax_t v = strtoimax(value, &end, 0);
+    if (errno != ERANGE && end != value && v >= std::numeric_limits<T>::min() &&
+        v <= std::numeric_limits<T>::max()) {
+        result = v;
     }
-
-    intmax_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0'};
-    char *end = NULL;
-
-    int len = property_get(key, buf, "");
-    if (len > 0) {
-        int tmp = errno;
-        errno = 0;
-
-        // Infer base automatically
-        result = strtoimax(buf, &end, /*base*/ 0);
-        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
-            // Over or underflow
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
-        } else if (result < lower_bound || result > upper_bound) {
-            // Out of range of requested bounds
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
-        } else if (end == buf) {
-            // Numeric conversion failed
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", __FUNCTION__, key,
-                  default_value);
-        }
-
-        errno = tmp;
-    }
-
+    errno = saved_errno;
     return result;
 }
 
-int64_t property_get_int64(const char *key, int64_t default_value) {
-    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+int64_t property_get_int64(const char* key, int64_t default_value) {
+    return property_get_int<int64_t>(key, default_value);
 }
 
-int32_t property_get_int32(const char *key, int32_t default_value) {
-    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+int32_t property_get_int32(const char* key, int32_t default_value) {
+    return property_get_int<int32_t>(key, default_value);
 }
 
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-int property_set(const char *key, const char *value) {
+int property_set(const char* key, const char* value) {
     return __system_property_set(key, value);
 }
 
-int property_get(const char *key, char *value, const char *default_value) {
+int property_get(const char* key, char* value, const char* default_value) {
     int len = __system_property_get(key, value);
-    if (len > 0) {
-        return len;
-    }
-    if (default_value) {
-        len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
-        memcpy(value, default_value, len);
-        value[len] = '\0';
+    if (len < 1 && default_value) {
+        snprintf(value, PROPERTY_VALUE_MAX, "%s", default_value);
+        return strlen(value);
     }
     return len;
 }
 
+#if __has_include(<sys/system_properties.h>)
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 struct callback_data {
     void (*callback)(const char* name, const char* value, void* cookie);
     void* cookie;
@@ -139,6 +111,8 @@
 }
 
 int property_list(void (*fn)(const char* name, const char* value, void* cookie), void* cookie) {
-    callback_data data = { fn, cookie };
+    callback_data data = {fn, cookie};
     return __system_property_foreach(property_list_callback, &data);
 }
+
+#endif