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

Commit 1f6d1c43 authored by Elliott Hughes's avatar Elliott Hughes Committed by android-build-merger
Browse files

Merge "Implement android::base::WaitForProperty." am: 01003d40

am: d96f68ee

Change-Id: Icbc1efd9293849d3b4cd9ccaba84eeacde974f9c
parents 0d94c26f d96f68ee
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -58,6 +58,9 @@ 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);

} // namespace base
} // namespace android

+41 −0
Original line number Diff line number Diff line
@@ -14,9 +14,12 @@
 * limitations under the License.
 */

#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_

#include "android-base/properties.h"

#include <sys/system_properties.h>
#include <sys/_system_properties.h>

#include <string>

@@ -78,5 +81,43 @@ bool SetProperty(const std::string& key, const std::string& value) {
  return (__system_property_set(key.c_str(), value.c_str()) == 0);
}

struct WaitForPropertyData {
  bool done;
  const std::string* expected_value;
  unsigned last_read_serial;
};

static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
  WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
  if (*data->expected_value == value) {
    data->done = true;
  } else {
    data->last_read_serial = serial;
  }
}

void WaitForProperty(const std::string& key, const std::string& expected_value) {
  // 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);
  }

  WaitForPropertyData data;
  data.expected_value = &expected_value;
  data.done = false;
  while (true) {
    // Check whether the property has the value we're looking for?
    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
    if (data.done) return;

    // It didn't so wait for it to change before checking again.
    __system_property_wait(pi, data.last_read_serial);
  }
}

}  // namespace base
}  // namespace android
+20 −0
Original line number Diff line number Diff line
@@ -18,7 +18,12 @@

#include <gtest/gtest.h>

#include <atomic>
#include <chrono>
#include <string>
#include <thread>

using namespace std::chrono_literals;

TEST(properties, smoke) {
  android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -119,3 +124,18 @@ TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }

TEST(properties, WaitForProperty) {
  std::atomic<bool> flag{false};
  std::thread thread([&]() {
    std::this_thread::sleep_for(100ms);
    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
    while (!flag) std::this_thread::yield();
    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
  });

  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a");
  flag = true;
  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b");
  thread.join();
}
+1 −1
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ struct callback_data {
    void* cookie;
};

static void trampoline(void* raw_data, const char* name, const char* value) {
static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
    callback_data* data = reinterpret_cast<callback_data*>(raw_data);
    data->callback(name, value, data->cookie);
}