From b30769a87acc15fc7f628d8541cdf97aba22e2e2 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Feb 2017 19:02:51 -0800 Subject: [PATCH] Implement android::base::WaitForProperty. Also adapt libcutils to the bionic change that was necessary for this. Bug: http://b/35201172 Test: ran tests Change-Id: I72a98b70b03d23e958b46778b505fbd5c86c32ae --- base/include/android-base/properties.h | 3 ++ base/properties.cpp | 41 ++++++++++++++++++++++++++ base/properties_test.cpp | 20 +++++++++++++ libcutils/properties.cpp | 2 +- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h index 4d7082a21..e275fa2a4 100644 --- a/base/include/android-base/properties.h +++ b/base/include/android-base/properties.h @@ -58,6 +58,9 @@ template 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 diff --git a/base/properties.cpp b/base/properties.cpp index 37daf9a10..0f0f6382f 100644 --- a/base/properties.cpp +++ b/base/properties.cpp @@ -14,9 +14,12 @@ * limitations under the License. */ +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ + #include "android-base/properties.h" #include +#include #include @@ -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(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 diff --git a/base/properties_test.cpp b/base/properties_test.cpp index da89ec5a9..d8186be6e 100644 --- a/base/properties_test.cpp +++ b/base/properties_test.cpp @@ -18,7 +18,12 @@ #include +#include +#include #include +#include + +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(); } TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty(); } TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty(); } TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty(); } + +TEST(properties, WaitForProperty) { + std::atomic 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(); +} diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp index 43ad5748e..d2645e640 100644 --- a/libcutils/properties.cpp +++ b/libcutils/properties.cpp @@ -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(raw_data); data->callback(name, value, data->cookie); }