diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c index 767baa3a6..c40950fbc 100644 --- a/libc/bionic/system_properties.c +++ b/libc/bionic/system_properties.c @@ -38,13 +38,14 @@ #include #include #include +#include #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include #include -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 @@ int __system_property_get(const char *name, char *value) } } + +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 4fdc9447f..85915b2de 100644 --- a/libc/include/sys/system_properties.h +++ b/libc/include/sys/system_properties.h @@ -46,6 +46,10 @@ typedef struct prop_info prop_info; */ 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