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

Commit 6f4e2cf6 authored by Elliott Hughes's avatar Elliott Hughes Committed by android-build-merger
Browse files

Merge "Add timeout support to android::base::WaitForProperty." am: ff692a5a

am: 6bbdfa32

Change-Id: I72b4839593fe67be88ba5ff5dd95822af8f8d819
parents a119bcc8 6bbdfa32
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#error Only bionic supports system properties.
#endif

#include <chrono>
#include <limits>
#include <string>

@@ -58,8 +59,12 @@ template <typename T> T GetUintProperty(const std::string& key,
// tell you whether or not your call succeeded. A `false` return value definitely means failure.
bool SetProperty(const std::string& key, const std::string& value);

// Waits for the system property `key` to have the value `expected_value`, .
void WaitForProperty(const std::string& key, const std::string& expected_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.
bool WaitForProperty(const std::string& key,
                     const std::string& expected_value,
                     std::chrono::milliseconds relative_timeout);

} // namespace base
} // namespace android
+38 −5
Original line number Diff line number Diff line
@@ -21,10 +21,14 @@
#include <sys/system_properties.h>
#include <sys/_system_properties.h>

#include <algorithm>
#include <chrono>
#include <string>

#include <android-base/parseint.h>

using namespace std::chrono_literals;

namespace android {
namespace base {

@@ -96,14 +100,41 @@ static void WaitForPropertyCallback(void* data_ptr, const char*, const char* val
  }
}

void WaitForProperty(const std::string& key, const std::string& expected_value) {
// TODO: chrono_utils?
static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
  auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
  auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
  ts.tv_sec = s.count();
  ts.tv_nsec = ns.count();
}

static void UpdateTimeSpec(timespec& ts,
                           const std::chrono::time_point<std::chrono::steady_clock>& timeout) {
  auto now = std::chrono::steady_clock::now();
  auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
  if (remaining_timeout < 0ns) {
    ts = { 0, 0 };
  } else {
    DurationToTimeSpec(ts, remaining_timeout);
  }
}

bool WaitForProperty(const std::string& key,
                     const std::string& expected_value,
                     std::chrono::milliseconds relative_timeout) {
  // TODO: boot_clock?
  auto now = std::chrono::steady_clock::now();
  std::chrono::time_point<std::chrono::steady_clock> absolute_timeout = now + relative_timeout;
  timespec ts;

  // Find the property's prop_info*.
  const prop_info* pi;
  unsigned global_serial = 0;
  while ((pi = __system_property_find(key.c_str())) == nullptr) {
    // The property doesn't even exist yet.
    // Wait for a global change and then look again.
    global_serial = __system_property_wait_any(global_serial);
    UpdateTimeSpec(ts, absolute_timeout);
    if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return false;
  }

  WaitForPropertyData data;
@@ -112,10 +143,12 @@ void WaitForProperty(const std::string& key, const std::string& expected_value)
  while (true) {
    // Check whether the property has the value we're looking for?
    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
    if (data.done) return;
    if (data.done) return true;

    // It didn't so wait for it to change before checking again.
    __system_property_wait(pi, data.last_read_serial);
    // It didn't, so wait for the property to change before checking again.
    UpdateTimeSpec(ts, absolute_timeout);
    uint32_t unused;
    if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
  }
}

+13 −2
Original line number Diff line number Diff line
@@ -134,8 +134,19 @@ TEST(properties, WaitForProperty) {
    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
  });

  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a");
  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
  flag = true;
  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b");
  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s));
  thread.join();
}

TEST(properties, WaitForProperty_timeout) {
  auto t0 = std::chrono::steady_clock::now();
  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a",
                                              200ms));
  auto t1 = std::chrono::steady_clock::now();

  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);
}