Merge "Implement android::base::WaitForProperty."

This commit is contained in:
Treehugger Robot 2017-02-14 03:48:23 +00:00 committed by Gerrit Code Review
commit 01003d40fc
4 changed files with 65 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

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

View File

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