add base::WaitForPropertyCreation

- unlike base::WaitForProperty, which waits for specific value to
  be set, this one only waits until the property is created.

bug: 35178781
Test: added unit test
Change-Id: Idbf98c2152fe768357302f6b69310c55305f5d54
diff --git a/base/properties.cpp b/base/properties.cpp
index acd6c0f..32c0128 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -108,8 +108,10 @@
   ts.tv_nsec = ns.count();
 }
 
+using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
+
 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 remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
   if (remaining_timeout < 0ns) {
@@ -119,13 +121,16 @@
   }
 }
 
-bool WaitForProperty(const std::string& key,
-                     const std::string& expected_value,
-                     std::chrono::milliseconds relative_timeout) {
+// Waits for the system property `key` to be created.
+// Times out after `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?
   auto now = std::chrono::steady_clock::now();
-  std::chrono::time_point<std::chrono::steady_clock> absolute_timeout = now + relative_timeout;
-  timespec ts;
+  absolute_timeout = now + relative_timeout;
 
   // Find the property's prop_info*.
   const prop_info* pi;
@@ -133,14 +138,25 @@
   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.
+    timespec ts;
     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;
   data.expected_value = &expected_value;
   data.done = false;
   while (true) {
+    timespec ts;
     // Check whether the property has the value we're looking for?
     __system_property_read_callback(pi, WaitForPropertyCallback, &data);
     if (data.done) return true;
@@ -152,5 +168,11 @@
   }
 }
 
+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 android