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

Commit d580c441 authored by Elliott Hughes's avatar Elliott Hughes Committed by Gerrit Code Review
Browse files

Merge "libbase: add host properties support."

parents 420fe5fe dc803126
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ cc_defaults {
        "file.cpp",
        "logging.cpp",
        "parsenetaddress.cpp",
        "properties.cpp",
        "quick_exit.cpp",
        "stringprintf.cpp",
        "strings.cpp",
@@ -58,9 +59,6 @@ cc_defaults {
    shared_libs: ["liblog"],
    target: {
        android: {
            srcs: [
                "properties.cpp",
            ],
            sanitize: {
                misc_undefined: ["integer"],
            },
@@ -130,6 +128,7 @@ cc_test {
        "parsedouble_test.cpp",
        "parseint_test.cpp",
        "parsenetaddress_test.cpp",
        "properties_test.cpp",
        "quick_exit_test.cpp",
        "scopeguard_test.cpp",
        "stringprintf_test.cpp",
@@ -139,7 +138,6 @@ cc_test {
    ],
    target: {
        android: {
            srcs: ["properties_test.cpp"],
            sanitize: {
                misc_undefined: ["integer"],
            },
+4 −4
Original line number Diff line number Diff line
@@ -19,10 +19,6 @@

#include <sys/cdefs.h>

#if !defined(__BIONIC__)
#error Only bionic supports system properties.
#endif

#include <chrono>
#include <limits>
#include <string>
@@ -62,14 +58,18 @@ bool SetProperty(const std::string& key, const std::string& value);
// Waits for the system property `key` to have the value `expected_value`.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
#if defined(__BIONIC__)
bool WaitForProperty(const std::string& key, const std::string& expected_value,
                     std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
#endif

// Waits for the system property `key` to be created.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
#if defined(__BIONIC__)
bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
                                                         std::chrono::milliseconds::max());
#endif

} // namespace base
} // namespace android
+39 −20
Original line number Diff line number Diff line
@@ -14,16 +14,18 @@
 * limitations under the License.
 */

#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_

#include "android-base/properties.h"

#if defined(__BIONIC__)
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/system_properties.h>
#include <sys/_system_properties.h>
#endif

#include <algorithm>
#include <chrono>
#include <limits>
#include <map>
#include <string>

#include <android-base/parseint.h>
@@ -31,24 +33,6 @@
namespace android {
namespace base {

std::string GetProperty(const std::string& key, const std::string& default_value) {
  const prop_info* pi = __system_property_find(key.c_str());
  if (pi == nullptr) return default_value;

  std::string property_value;
  __system_property_read_callback(pi,
                                  [](void* cookie, const char*, const char* value, unsigned) {
                                    auto property_value = reinterpret_cast<std::string*>(cookie);
                                    *property_value = value;
                                  },
                                  &property_value);

  // If the property exists but is empty, also return the default value.
  // Since we can't remove system properties, "empty" is traditionally
  // the same as "missing" (this was true for cutils' property_get).
  return property_value.empty() ? default_value : property_value;
}

bool GetBoolProperty(const std::string& key, bool default_value) {
  std::string value = GetProperty(key, "");
  if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
@@ -85,10 +69,43 @@ template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
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__)
  const prop_info* pi = __system_property_find(key.c_str());
  if (pi == nullptr) return default_value;

  __system_property_read_callback(pi,
                                  [](void* cookie, const char*, const char* value, unsigned) {
                                    auto property_value = reinterpret_cast<std::string*>(cookie);
                                    *property_value = value;
                                  },
                                  &property_value);
#else
  auto it = g_properties.find(key);
  if (it == g_properties.end()) return default_value;
  property_value = it->second;
#endif
  // If the property exists but is empty, also return the default value.
  // Since we can't remove system properties, "empty" is traditionally
  // the same as "missing" (this was true for cutils' property_get).
  return property_value.empty() ? default_value : property_value;
}

bool SetProperty(const std::string& key, const std::string& value) {
  return (__system_property_set(key.c_str(), value.c_str()) == 0);
}

#if defined(__BIONIC__)

struct WaitForPropertyData {
  bool done;
  const std::string* expected_value;
@@ -175,5 +192,7 @@ bool WaitForPropertyCreation(const std::string& key,
  return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}

#endif

}  // namespace base
}  // namespace android
+27 −1
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@
#include <string>
#include <thread>

using namespace std::chrono_literals;
#if !defined(_WIN32)
using namespace std::literals;
#endif

TEST(properties, smoke) {
  android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -126,6 +128,7 @@ TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }

TEST(properties, WaitForProperty) {
#if defined(__BIONIC__)
  std::atomic<bool> flag{false};
  std::thread thread([&]() {
    std::this_thread::sleep_for(100ms);
@@ -138,9 +141,13 @@ TEST(properties, WaitForProperty) {
  flag = true;
  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s));
  thread.join();
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}

TEST(properties, WaitForProperty_timeout) {
#if defined(__BIONIC__)
  auto t0 = std::chrono::steady_clock::now();
  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a",
                                              200ms));
@@ -149,9 +156,13 @@ TEST(properties, WaitForProperty_timeout) {
  ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
  // Upper bounds on timing are inherently flaky, but let's try...
  ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}

TEST(properties, WaitForProperty_MaxTimeout) {
#if defined(__BIONIC__)
  std::atomic<bool> flag{false};
  std::thread thread([&]() {
    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
@@ -165,9 +176,13 @@ TEST(properties, WaitForProperty_MaxTimeout) {
  // Test that this does not immediately return false due to overflow issues with the timeout.
  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
  thread.join();
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}

TEST(properties, WaitForProperty_NegativeTimeout) {
#if defined(__BIONIC__)
  std::atomic<bool> flag{false};
  std::thread thread([&]() {
    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
@@ -181,9 +196,13 @@ TEST(properties, WaitForProperty_NegativeTimeout) {
  // Assert that this immediately returns with a negative timeout
  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
  thread.join();
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}

TEST(properties, WaitForPropertyCreation) {
#if defined(__BIONIC__)
  std::thread thread([&]() {
    std::this_thread::sleep_for(100ms);
    android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
@@ -192,9 +211,13 @@ TEST(properties, WaitForPropertyCreation) {
  ASSERT_TRUE(android::base::WaitForPropertyCreation(
          "debug.libbase.WaitForPropertyCreation_test", 1s));
  thread.join();
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}

TEST(properties, WaitForPropertyCreation_timeout) {
#if defined(__BIONIC__)
  auto t0 = std::chrono::steady_clock::now();
  ASSERT_FALSE(android::base::WaitForPropertyCreation(
          "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms));
@@ -203,4 +226,7 @@ TEST(properties, WaitForPropertyCreation_timeout) {
  ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
  // Upper bounds on timing are inherently flaky, but let's try...
  ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
#else
  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
#endif
}
+1 −6
Original line number Diff line number Diff line
@@ -18,16 +18,11 @@

#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>

#include "util.h"

#if defined(__ANDROID__)
#include <android-base/properties.h>
#else
#include "host_init_stubs.h"
#endif

using android::base::Join;

namespace android {
Loading