Merge commit '8da75ab8936b0b7fcf8dd9a3befeb696ee6aa39d' into honeycomb-mr1-release-to-dalvik-dev
This commit is contained in:
commit
2848ca2c05
@ -30,6 +30,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
@ -156,15 +157,17 @@ int __system_property_get(const char *name, char *value)
|
|||||||
|
|
||||||
static int send_prop_msg(prop_msg *msg)
|
static int send_prop_msg(prop_msg *msg)
|
||||||
{
|
{
|
||||||
|
struct pollfd pollfds[1];
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
socklen_t alen;
|
socklen_t alen;
|
||||||
size_t namelen;
|
size_t namelen;
|
||||||
int s;
|
int s;
|
||||||
int r;
|
int r;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
s = socket(AF_LOCAL, SOCK_STREAM, 0);
|
s = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||||
if(s < 0) {
|
if(s < 0) {
|
||||||
return -1;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@ -175,30 +178,49 @@ static int send_prop_msg(prop_msg *msg)
|
|||||||
|
|
||||||
if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) {
|
if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen) < 0)) {
|
||||||
close(s);
|
close(s);
|
||||||
return -1;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
|
r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
|
||||||
|
|
||||||
if(r == sizeof(prop_msg)) {
|
if(r == sizeof(prop_msg)) {
|
||||||
r = 0;
|
// We successfully wrote to the property server but now we
|
||||||
} else {
|
// wait for the property server to finish its work. It
|
||||||
r = -1;
|
// 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.
|
||||||
|
pollfds[0].fd = s;
|
||||||
|
pollfds[0].events = 0;
|
||||||
|
r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
|
||||||
|
if (r == 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.
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(s);
|
close(s);
|
||||||
return r;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __system_property_set(const char *key, const char *value)
|
int __system_property_set(const char *key, const char *value)
|
||||||
{
|
{
|
||||||
unsigned old_serial;
|
|
||||||
volatile unsigned *serial;
|
|
||||||
prop_msg msg;
|
|
||||||
int err;
|
int err;
|
||||||
prop_area *pa = __system_property_area__;
|
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
int update_seen = 0;
|
int update_seen = 0;
|
||||||
|
prop_msg msg;
|
||||||
|
|
||||||
if(key == 0) return -1;
|
if(key == 0) return -1;
|
||||||
if(value == 0) value = "";
|
if(value == 0) value = "";
|
||||||
@ -210,54 +232,11 @@ int __system_property_set(const char *key, const char *value)
|
|||||||
strlcpy(msg.name, key, sizeof msg.name);
|
strlcpy(msg.name, key, sizeof msg.name);
|
||||||
strlcpy(msg.value, value, sizeof msg.value);
|
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);
|
err = send_prop_msg(&msg);
|
||||||
if(err < 0) {
|
if(err < 0) {
|
||||||
return err;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user