Merge "libc: __system_property_set uses writev to write atomically"
This commit is contained in:
commit
3246b9d8ae
3 changed files with 134 additions and 61 deletions
|
@ -34,7 +34,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -47,6 +46,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
|
@ -487,8 +487,8 @@ const prop_info* prop_area::find_property(prop_bt* const trie, const char* name,
|
|||
class PropertyServiceConnection {
|
||||
public:
|
||||
PropertyServiceConnection() : last_error_(0) {
|
||||
fd_ = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd_ == -1) {
|
||||
socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (socket_ == -1) {
|
||||
last_error_ = errno;
|
||||
return;
|
||||
}
|
||||
|
@ -500,54 +500,33 @@ class PropertyServiceConnection {
|
|||
addr.sun_family = AF_LOCAL;
|
||||
socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
|
||||
|
||||
if (TEMP_FAILURE_RETRY(connect(fd_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
|
||||
close(socket_);
|
||||
socket_ = -1;
|
||||
last_error_ = errno;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValid() {
|
||||
return fd_ != -1;
|
||||
return socket_ != -1;
|
||||
}
|
||||
|
||||
int GetLastError() {
|
||||
return last_error_;
|
||||
}
|
||||
|
||||
bool SendUint32(uint32_t value) {
|
||||
int result = TEMP_FAILURE_RETRY(send(fd_, &value, sizeof(value), 0));
|
||||
return CheckSendRecvResult(result, sizeof(value));
|
||||
}
|
||||
|
||||
bool SendString(const char* value) {
|
||||
uint32_t valuelen = strlen(value);
|
||||
if (!SendUint32(valuelen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trying to send even 0 bytes to closed socket may lead to
|
||||
// broken pipe (http://b/34670529).
|
||||
if (valuelen == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int result = TEMP_FAILURE_RETRY(send(fd_, value, valuelen, 0));
|
||||
return CheckSendRecvResult(result, valuelen);
|
||||
}
|
||||
|
||||
bool RecvInt32(int32_t* value) {
|
||||
int result = TEMP_FAILURE_RETRY(recv(fd_, value, sizeof(*value), MSG_WAITALL));
|
||||
int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
|
||||
return CheckSendRecvResult(result, sizeof(*value));
|
||||
}
|
||||
|
||||
int GetFd() {
|
||||
return fd_;
|
||||
int socket() {
|
||||
return socket_;
|
||||
}
|
||||
|
||||
~PropertyServiceConnection() {
|
||||
if (fd_ != -1) {
|
||||
close(fd_);
|
||||
if (socket_ != -1) {
|
||||
close(socket_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,8 +543,69 @@ class PropertyServiceConnection {
|
|||
return last_error_ == 0;
|
||||
}
|
||||
|
||||
int fd_;
|
||||
int socket_;
|
||||
int last_error_;
|
||||
|
||||
friend class SocketWriter;
|
||||
};
|
||||
|
||||
class SocketWriter {
|
||||
public:
|
||||
explicit SocketWriter(PropertyServiceConnection* connection)
|
||||
: connection_(connection), iov_index_(0), uint_buf_index_(0)
|
||||
{}
|
||||
|
||||
SocketWriter& WriteUint32(uint32_t value) {
|
||||
CHECK(uint_buf_index_ < kUintBufSize);
|
||||
CHECK(iov_index_ < kIovSize);
|
||||
uint32_t* ptr = uint_buf_ + uint_buf_index_;
|
||||
uint_buf_[uint_buf_index_++] = value;
|
||||
iov_[iov_index_].iov_base = ptr;
|
||||
iov_[iov_index_].iov_len = sizeof(*ptr);
|
||||
++iov_index_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SocketWriter& WriteString(const char* value) {
|
||||
uint32_t valuelen = strlen(value);
|
||||
WriteUint32(valuelen);
|
||||
if (valuelen == 0) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CHECK(iov_index_ < kIovSize);
|
||||
iov_[iov_index_].iov_base = const_cast<char*>(value);
|
||||
iov_[iov_index_].iov_len = valuelen;
|
||||
++iov_index_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Send() {
|
||||
if (!connection_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (writev(connection_->socket(), iov_, iov_index_) == -1) {
|
||||
connection_->last_error_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
iov_index_ = uint_buf_index_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t kUintBufSize = 8;
|
||||
static constexpr size_t kIovSize = 8;
|
||||
|
||||
PropertyServiceConnection* connection_;
|
||||
iovec iov_[kIovSize];
|
||||
size_t iov_index_;
|
||||
uint32_t uint_buf_[kUintBufSize];
|
||||
size_t uint_buf_index_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
|
||||
};
|
||||
|
||||
struct prop_msg {
|
||||
|
@ -581,9 +621,9 @@ static int send_prop_msg(const prop_msg* msg) {
|
|||
}
|
||||
|
||||
int result = -1;
|
||||
int fd = connection.GetFd();
|
||||
int s = connection.socket();
|
||||
|
||||
const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
|
||||
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
|
||||
|
@ -593,7 +633,7 @@ static int send_prop_msg(const prop_msg* msg) {
|
|||
// once the socket closes. Out of paranoia we cap our poll
|
||||
// at 250 ms.
|
||||
pollfd pollfds[1];
|
||||
pollfds[0].fd = fd;
|
||||
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) {
|
||||
|
@ -1230,7 +1270,6 @@ int __system_property_set(const char* key, const char* value) {
|
|||
detect_protocol_version();
|
||||
}
|
||||
|
||||
int result = -1;
|
||||
if (g_propservice_protocol_version == kProtocolVersion1) {
|
||||
// Old protocol does not support long names
|
||||
if (strlen(key) >= PROP_NAME_MAX) return -1;
|
||||
|
@ -1241,27 +1280,60 @@ int __system_property_set(const char* key, const char* value) {
|
|||
strlcpy(msg.name, key, sizeof msg.name);
|
||||
strlcpy(msg.value, value, sizeof msg.value);
|
||||
|
||||
result = send_prop_msg(&msg);
|
||||
return send_prop_msg(&msg);
|
||||
} else {
|
||||
// Use proper protocol
|
||||
PropertyServiceConnection connection;
|
||||
if (connection.IsValid() && connection.SendUint32(PROP_MSG_SETPROP2) &&
|
||||
connection.SendString(key) && connection.SendString(value) &&
|
||||
connection.RecvInt32(&result)) {
|
||||
if (result != PROP_SUCCESS) {
|
||||
__libc_format_log(ANDROID_LOG_WARN, "libc",
|
||||
"Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
|
||||
result);
|
||||
}
|
||||
} else {
|
||||
result = connection.GetLastError();
|
||||
__libc_format_log(ANDROID_LOG_WARN, "libc",
|
||||
"Unable to set property \"%s\" to \"%s\": error code: 0x%x (%s)", key,
|
||||
value, result, strerror(result));
|
||||
}
|
||||
if (!connection.IsValid()) {
|
||||
errno = connection.GetLastError();
|
||||
__libc_format_log(ANDROID_LOG_WARN,
|
||||
"libc",
|
||||
"Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
|
||||
key,
|
||||
value,
|
||||
errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result != 0 ? -1 : 0;
|
||||
SocketWriter writer(&connection);
|
||||
if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
|
||||
errno = connection.GetLastError();
|
||||
__libc_format_log(ANDROID_LOG_WARN,
|
||||
"libc",
|
||||
"Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
|
||||
key,
|
||||
value,
|
||||
errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = -1;
|
||||
if (!connection.RecvInt32(&result)) {
|
||||
errno = connection.GetLastError();
|
||||
__libc_format_log(ANDROID_LOG_WARN,
|
||||
"libc",
|
||||
"Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
|
||||
key,
|
||||
value,
|
||||
errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result != PROP_SUCCESS) {
|
||||
__libc_format_log(ANDROID_LOG_WARN,
|
||||
"libc",
|
||||
"Unable to set property \"%s\" to \"%s\": error code: 0x%x",
|
||||
key,
|
||||
value,
|
||||
result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
|
||||
|
|
|
@ -97,6 +97,14 @@ int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _No
|
|||
#endif
|
||||
int __libc_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
|
||||
|
||||
#define CHECK(predicate) \
|
||||
do { \
|
||||
if (!(predicate)) { \
|
||||
__libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,13 +59,6 @@
|
|||
|
||||
__LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
|
||||
|
||||
#define CHECK(predicate) { \
|
||||
if (!(predicate)) { \
|
||||
__libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if LINKER_DEBUG_TO_LOG
|
||||
#define _PRINTVF(v, x...) \
|
||||
do { \
|
||||
|
|
Loading…
Reference in a new issue