-bool prop_area::foreach_property(prop_bt *const trie,
- void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
-{
- if (!trie)
- return false;
-
- uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
- if (left_offset != 0) {
- const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
- if (err < 0)
- return false;
- }
- uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
- if (prop_offset != 0) {
- prop_info *info = to_prop_info(&trie->prop);
- if (!info)
- return false;
- propfn(info, cookie);
- }
- uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
- if (children_offset != 0) {
- const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
- if (err < 0)
- return false;
- }
- uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
- if (right_offset != 0) {
- const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
- if (err < 0)
- return false;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
+};
+
+struct prop_msg {
+ unsigned cmd;
+ char name[PROP_NAME_MAX];
+ char value[PROP_VALUE_MAX];
+};
+
+static int send_prop_msg(const prop_msg* msg) {
+ PropertyServiceConnection connection;
+ if (!connection.IsValid()) {
+ return connection.GetLastError();
+ }
+
+ int result = -1;
+ int s = connection.socket();
+
+ const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
+ if (num_bytes == sizeof(prop_msg)) {
+ // We successfully wrote to the property server but now we
+ // wait for the property server to finish its work. It
+ // acknowledges its completion by closing the socket so we
+ // poll here (on nothing), waiting for the socket to close.
+ // If you 'adb shell setprop foo bar' you'll see the POLLHUP
+ // once the socket closes. Out of paranoia we cap our poll
+ // at 250 ms.
+ pollfd pollfds[1];
+ pollfds[0].fd = s;
+ pollfds[0].events = 0;
+ const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
+ if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
+ result = 0;
+ } else {
+ // Ignore the timeout and treat it like a success anyway.
+ // The init process is single-threaded and its property
+ // service is sometimes slow to respond (perhaps it's off
+ // starting a child process or something) and thus this
+ // times out and the caller thinks it failed, even though
+ // it's still getting around to it. So we fake it here,
+ // mostly for ctl.* properties, but we do try and wait 250
+ // ms so callers who do read-after-write can reliably see
+ // what they've written. Most of the time.
+ // TODO: fix the system properties design.
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Property service has timed out while trying to set \"%s\" to \"%s\"",
+ msg->name, msg->value);
+ result = 0;