Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 100b08a8 authored by S Vasudev Prasad's avatar S Vasudev Prasad Committed by Elliott Hughes
Browse files

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
parent 3b55f757
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ cc_library {
        "iosched_policy.cpp",
        "load_file.cpp",
        "native_handle.cpp",
        "properties.cpp",
        "record_stream.cpp",
        "strlcpy.c",
        "threads.cpp",
@@ -187,7 +188,6 @@ cc_library {
                "fs_config.cpp",
                "klog.cpp",
                "partition_utils.cpp",
                "properties.cpp",
                "qtaguid.cpp",
                "trace-dev.cpp",
                "uevent.cpp",
@@ -268,6 +268,7 @@ cc_defaults {
    name: "libcutils_test_default",
    srcs: [
        "native_handle_test.cpp",
        "properties_test.cpp",
        "sockets_test.cpp",
    ],

@@ -280,7 +281,6 @@ cc_defaults {
                "fs_config_test.cpp",
                "memset_test.cpp",
                "multiuser_test.cpp",
                "properties_test.cpp",
                "sched_policy_test.cpp",
                "str_parms_test.cpp",
                "trace-dev_test.cpp",
+15 −14
Original line number Diff line number Diff line
@@ -14,25 +14,28 @@
 * limitations under the License.
 */

#ifndef __CUTILS_PROPERTIES_H
#define __CUTILS_PROPERTIES_H
#pragma once

#include <sys/cdefs.h>
#include <stddef.h>
#include <sys/system_properties.h>
#include <stdint.h>

#if __has_include(<sys/system_properties.h>)
#include <sys/system_properties.h>
#else
#define PROP_VALUE_MAX 92
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* System properties are *small* name value pairs managed by the
** property service.  If your data doesn't fit in the provided
** space it is not appropriate for a system property.
**
** WARNING: system/bionic/include/sys/system_properties.h also defines
**          these, but with different names.  (TODO: fix that)
*/
//
// Deprecated.
//
// See <android-base/properties.h> for better API.
//

#define PROPERTY_KEY_MAX PROP_NAME_MAX
#define PROPERTY_VALUE_MAX PROP_VALUE_MAX

@@ -146,5 +149,3 @@ int property_get(const char *key, char *value, const char *default_value) {
#ifdef __cplusplus
}
#endif

#endif
+38 −64
Original line number Diff line number Diff line
@@ -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;
    }
    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 @@ int8_t property_get_bool(const char *key, int8_t default_value) {
    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;

    intmax_t result = default_value;
    char buf[PROPERTY_VALUE_MAX] = {'\0'};
    char *end = NULL;
    char value[PROPERTY_VALUE_MAX] = {};
    if (property_get(key, value, "") < 1) return default_value;

    int len = property_get(key, buf, "");
    if (len > 0) {
        int tmp = errno;
    // libcutils unwisely allows octal, which libbase doesn't.
    T result = default_value;
    int saved_errno = 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);
    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;
    }

        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);
    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);
    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) {
    return __system_property_set(key, 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;
@@ -142,3 +114,5 @@ int property_list(void (*fn)(const char* name, const char* value, void* cookie),
    callback_data data = {fn, cookie};
    return __system_property_foreach(property_list_callback, &data);
}

#endif
+136 −117
Original line number Diff line number Diff line
@@ -93,16 +93,12 @@ protected:
    }
};

TEST_F(PropertiesTest, SetString) {

TEST_F(PropertiesTest, property_set_null_key) {
    // Null key -> unsuccessful set
    {
        // Null key -> fails
    EXPECT_GT(0, property_set(/*key*/ NULL, PROPERTY_TEST_VALUE_DEFAULT));
}

    // Null value -> returns default value
    {
TEST_F(PropertiesTest, property_set_null_value) {
    // Null value -> OK, and it clears the value
    EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/ NULL));
    ResetValue();
@@ -113,16 +109,16 @@ TEST_F(PropertiesTest, SetString) {
    EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
}

TEST_F(PropertiesTest, property_set) {
    // Trivial case => get returns what was set
    {
    size_t len = SetAndGetProperty("hello_world");
    EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
    EXPECT_STREQ("hello_world", mValue);
    ResetValue();
}

TEST_F(PropertiesTest, property_set_empty) {
    // Set to empty string => get returns default always
    {
    const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
    size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
    EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
@@ -130,8 +126,8 @@ TEST_F(PropertiesTest, SetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_set_max_length) {
    // Set to max length => get returns what was set
    {
    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');

    int len = SetAndGetProperty(maxLengthString.c_str());
@@ -140,8 +136,8 @@ TEST_F(PropertiesTest, SetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_set_too_long) {
    // Set to max length + 1 => set fails
    {
    const char* VALID_TEST_VALUE = "VALID_VALUE";
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));

@@ -155,12 +151,9 @@ TEST_F(PropertiesTest, SetString) {
    EXPECT_STREQ(VALID_TEST_VALUE, mValue);
    ResetValue();
}
}

TEST_F(PropertiesTest, GetString) {

TEST_F(PropertiesTest, property_get_too_long) {
    // Try to use a default value that's too long => get truncates the value
    {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));

    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
@@ -173,8 +166,8 @@ TEST_F(PropertiesTest, GetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_get_default_too_long) {
    // Try to use a default value that's the max length => get succeeds
    {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));

    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
@@ -186,8 +179,8 @@ TEST_F(PropertiesTest, GetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_get_default_okay) {
    // Try to use a default value of length one => get succeeds
    {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));

    std::string oneCharString = std::string(1, 'c');
@@ -199,8 +192,8 @@ TEST_F(PropertiesTest, GetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_get_default_empty) {
    // Try to use a default value of length zero => get succeeds
    {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));

    std::string zeroCharString = std::string(0, 'd');
@@ -212,8 +205,8 @@ TEST_F(PropertiesTest, GetString) {
    ResetValue();
}

TEST_F(PropertiesTest, property_get_default_NULL) {
    // Try to use a NULL default value => get returns 0
    {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));

    // Expect a return value of 0
@@ -221,32 +214,58 @@ TEST_F(PropertiesTest, GetString) {
    EXPECT_EQ(0, len);
    ResetValue();
}

TEST_F(PropertiesTest, property_get_bool_0) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "0"));
    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
}

TEST_F(PropertiesTest, GetBool) {
    /**
     * TRUE
     */
    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
    for (size_t i = 0; i < arraysize(valuesTrue); ++i) {
        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
TEST_F(PropertiesTest, property_get_bool_1) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "1"));
    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
}

    /**
     * FALSE
     */
    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
    for (size_t i = 0; i < arraysize(valuesFalse); ++i) {
        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
TEST_F(PropertiesTest, property_get_bool_false) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "false"));
    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
}

    /**
     * NEITHER
     */
TEST_F(PropertiesTest, property_get_bool_n) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "n"));
    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
}

TEST_F(PropertiesTest, property_get_bool_no) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "no"));
    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
}

TEST_F(PropertiesTest, property_get_bool_off) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "off"));
    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
}

TEST_F(PropertiesTest, property_get_bool_on) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "on"));
    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
}

TEST_F(PropertiesTest, property_get_bool_true) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "true"));
    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
}

TEST_F(PropertiesTest, property_get_bool_y) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "y"));
    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
}

TEST_F(PropertiesTest, property_get_bool_yes) {
    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "yes"));
    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
}

TEST_F(PropertiesTest, property_get_bool_neither) {
    const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
            "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
            "+0", "-0", "00", "  00  ", "  false", "false  ",
@@ -263,7 +282,7 @@ TEST_F(PropertiesTest, GetBool) {
    }
}

TEST_F(PropertiesTest, GetInt64) {
TEST_F(PropertiesTest, property_get_int64) {
    const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);

    const std::string longMaxString = ToString(INT64_MAX);
@@ -310,7 +329,7 @@ TEST_F(PropertiesTest, GetInt64) {
    }
}

TEST_F(PropertiesTest, GetInt32) {
TEST_F(PropertiesTest, property_get_int32) {
    const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);

    const std::string intMaxString = ToString(INT32_MAX);