Merge "Implement android::base::WaitForProperty."
am: 01003d40fc
Change-Id: Iede377bab376afff8146ca6fdf9c88d326cf0487
This commit is contained in:
commit
d96f68ee21
4 changed files with 65 additions and 1 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue