Move property setting from libcutils to bionic.

All the other property stuff is already here.  Property setting was
only in libcutils previously to leverage a utility function / constant
or two.

Unfortunately in the process of fixing a race condition we would've
had to do break abstraction boundaries and put some libc-internal
details into libcutils so instead of that we'll just move this
into bionic.

Along with Iee1ca9b7, this now passes:

$ adb shell am instrument -w -e class android.os.SystemPropertiesTest \
  com.android.frameworks.coretests.systemproperties/android.test.InstrumentationTestRunner

Bug: 3511230
Change-Id: I110b653a58f312fbe069dca59892a877ae9bc911
diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c
index 767baa3..c40950f 100644
--- a/libc/bionic/system_properties.c
+++ b/libc/bionic/system_properties.c
@@ -38,13 +38,14 @@
 #include <sys/select.h>
 #include <sys/types.h>
 #include <netinet/in.h>
+#include <unistd.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
 #include <sys/atomics.h>
 
-static const char property_service_name[] = PROP_SERVICE_NAME;
+static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
 
 static unsigned dummy_props = 0;
 
@@ -152,6 +153,114 @@
     }
 }
 
+
+static int send_prop_msg(prop_msg *msg)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    size_t namelen;
+    int s;
+    int r;
+
+    s = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if(s < 0) {
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    namelen = strlen(property_service_socket);
+    strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
+    addr.sun_family = AF_LOCAL;
+    alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+
+    if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) {
+        close(s);
+        return -1;
+    }
+
+    r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
+
+    if(r == sizeof(prop_msg)) {
+        r = 0;
+    } else {
+        r = -1;
+    }
+
+    close(s);
+    return r;
+}
+
+int __system_property_set(const char *key, const char *value)
+{
+    unsigned old_serial;
+    volatile unsigned *serial;
+    prop_msg msg;
+    int err;
+    prop_area *pa = __system_property_area__;
+    int tries = 0;
+    int update_seen = 0;
+
+    if(key == 0) return -1;
+    if(value == 0) value = "";
+    if(strlen(key) >= PROP_NAME_MAX) return -1;
+    if(strlen(value) >= PROP_VALUE_MAX) return -1;
+
+    memset(&msg, 0, sizeof msg);
+    msg.cmd = PROP_MSG_SETPROP;
+    strlcpy(msg.name, key, sizeof msg.name);
+    strlcpy(msg.value, value, sizeof msg.value);
+
+    /* Note the system properties serial number before we do our update. */
+    const prop_info *pi = __system_property_find(key);
+    if(pi != NULL) {
+        serial = &pi->serial;
+    } else {
+        serial = &pa->serial;
+    }
+    old_serial = *serial;
+
+    err = send_prop_msg(&msg);
+    if(err < 0) {
+        return err;
+    }
+
+    /**
+     * Wait for the shared memory page to be written back and be
+     * visible in our address space before returning to the caller
+     * who might reasonably expect subsequent reads to match what was
+     * just written.
+     *
+     * Sleep 5 ms after failed checks and only wait up to a 500 ms
+     * total, just in case the system property server fails to update
+     * for whatever reason.
+     */
+    do {
+        struct timespec timeout;
+        timeout.tv_sec = 0;
+        timeout.tv_nsec = 2500000;  // 2.5 ms
+
+        if(tries++ > 0) {
+            usleep(2500); // 2.5 ms
+        }
+        __futex_wait(serial, old_serial, &timeout);
+        if(pi != NULL) {
+            unsigned new_serial = *serial;
+            /* Waiting on a specific prop_info to be updated. */
+            if (old_serial != new_serial && !SERIAL_DIRTY(new_serial)) {
+                update_seen = 1;
+            }
+        } else {
+            /* Waiting for a prop_info to be created. */
+            const prop_info *new_pi = __system_property_find(key);
+            if(new_pi != NULL && !SERIAL_DIRTY(new_pi->serial)) {
+                update_seen = 1;
+            }
+        }
+    } while (!update_seen && tries < 100);
+
+    return 0;
+}
+
 int __system_property_wait(const prop_info *pi)
 {
     unsigned n;
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index 4fdc944..85915b2 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -46,6 +46,10 @@
 */
 int __system_property_get(const char *name, char *value);
 
+/* Set a system property by name.
+**/
+int __system_property_set(const char *key, const char *value);
+
 /* Return a pointer to the system property named name, if it
 ** exists, or NULL if there is no such property.  Use 
 ** __system_property_read() to obtain the string value from