Merge "add base::WaitForPropertyCreation"
This commit is contained in:
commit
22a64b3a8a
3 changed files with 57 additions and 7 deletions
|
|
@ -66,6 +66,12 @@ bool WaitForProperty(const std::string& key,
|
||||||
const std::string& expected_value,
|
const std::string& expected_value,
|
||||||
std::chrono::milliseconds relative_timeout);
|
std::chrono::milliseconds relative_timeout);
|
||||||
|
|
||||||
|
// Waits for the system property `key` to be created.
|
||||||
|
// Times out after `relative_timeout`.
|
||||||
|
// Returns true on success, false on timeout.
|
||||||
|
bool WaitForPropertyCreation(const std::string& key,
|
||||||
|
std::chrono::milliseconds relative_timeout);
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,8 +108,10 @@ static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
|
||||||
ts.tv_nsec = ns.count();
|
ts.tv_nsec = ns.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
|
||||||
|
|
||||||
static void UpdateTimeSpec(timespec& ts,
|
static void UpdateTimeSpec(timespec& ts,
|
||||||
const std::chrono::time_point<std::chrono::steady_clock>& timeout) {
|
const AbsTime& timeout) {
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
|
auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
|
||||||
if (remaining_timeout < 0ns) {
|
if (remaining_timeout < 0ns) {
|
||||||
|
|
@ -119,13 +121,16 @@ static void UpdateTimeSpec(timespec& ts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaitForProperty(const std::string& key,
|
// Waits for the system property `key` to be created.
|
||||||
const std::string& expected_value,
|
// Times out after `relative_timeout`.
|
||||||
std::chrono::milliseconds relative_timeout) {
|
// Sets absolute_timeout which represents absolute time for the timeout.
|
||||||
|
// Returns nullptr on timeout.
|
||||||
|
static const prop_info* WaitForPropertyCreation(const std::string& key,
|
||||||
|
const std::chrono::milliseconds& relative_timeout,
|
||||||
|
AbsTime& absolute_timeout) {
|
||||||
// TODO: boot_clock?
|
// TODO: boot_clock?
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
std::chrono::time_point<std::chrono::steady_clock> absolute_timeout = now + relative_timeout;
|
absolute_timeout = now + relative_timeout;
|
||||||
timespec ts;
|
|
||||||
|
|
||||||
// Find the property's prop_info*.
|
// Find the property's prop_info*.
|
||||||
const prop_info* pi;
|
const prop_info* pi;
|
||||||
|
|
@ -133,14 +138,25 @@ bool WaitForProperty(const std::string& key,
|
||||||
while ((pi = __system_property_find(key.c_str())) == nullptr) {
|
while ((pi = __system_property_find(key.c_str())) == nullptr) {
|
||||||
// The property doesn't even exist yet.
|
// The property doesn't even exist yet.
|
||||||
// Wait for a global change and then look again.
|
// Wait for a global change and then look again.
|
||||||
|
timespec ts;
|
||||||
UpdateTimeSpec(ts, absolute_timeout);
|
UpdateTimeSpec(ts, absolute_timeout);
|
||||||
if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return false;
|
if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
|
||||||
}
|
}
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaitForProperty(const std::string& key,
|
||||||
|
const std::string& expected_value,
|
||||||
|
std::chrono::milliseconds relative_timeout) {
|
||||||
|
AbsTime absolute_timeout;
|
||||||
|
const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
|
||||||
|
if (pi == nullptr) return false;
|
||||||
|
|
||||||
WaitForPropertyData data;
|
WaitForPropertyData data;
|
||||||
data.expected_value = &expected_value;
|
data.expected_value = &expected_value;
|
||||||
data.done = false;
|
data.done = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
timespec ts;
|
||||||
// Check whether the property has the value we're looking for?
|
// Check whether the property has the value we're looking for?
|
||||||
__system_property_read_callback(pi, WaitForPropertyCallback, &data);
|
__system_property_read_callback(pi, WaitForPropertyCallback, &data);
|
||||||
if (data.done) return true;
|
if (data.done) return true;
|
||||||
|
|
@ -152,5 +168,11 @@ bool WaitForProperty(const std::string& key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WaitForPropertyCreation(const std::string& key,
|
||||||
|
std::chrono::milliseconds relative_timeout) {
|
||||||
|
AbsTime absolute_timeout;
|
||||||
|
return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
||||||
|
|
@ -150,3 +150,25 @@ TEST(properties, WaitForProperty_timeout) {
|
||||||
// Upper bounds on timing are inherently flaky, but let's try...
|
// Upper bounds on timing are inherently flaky, but let's try...
|
||||||
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
|
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(properties, WaitForPropertyCreation) {
|
||||||
|
std::thread thread([&]() {
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_TRUE(android::base::WaitForPropertyCreation(
|
||||||
|
"debug.libbase.WaitForPropertyCreation_test", 1s));
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(properties, WaitForPropertyCreation_timeout) {
|
||||||
|
auto t0 = std::chrono::steady_clock::now();
|
||||||
|
ASSERT_FALSE(android::base::WaitForPropertyCreation(
|
||||||
|
"debug.libbase.WaitForPropertyCreation_timeout_test", 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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue