liblog: use a rwlock for writer initialization
The current system of using atomics isn't thread safe and may result
in doubly closing FDs or closing actively used FDs. The safest way to
do this is to use a rwlock, which should not have a much higher
overhead than the atomics do, as a vast majority of the time, there
will not be writers.
This moves us further away from using the transport interface, which
will be removed. Each writer should be self contained, without a
separate open or available function.
Also, keep the pmsg fd open if it is opened by
__android_log_pmsg_file_write(). This fd was closed due to issues
with zygote, but it looks like it is only called by recovery now, so
there is no reason to close this fd at the end of that function.
Test: logging works, liblog-unit-tests
Change-Id: I345c9a5d18c55b11a280c8362df854784abf46fd
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 54980d9..de48086 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -25,68 +25,51 @@
#include <sys/types.h>
#include <time.h>
+#include <shared_mutex>
+
#include <log/log_properties.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "log_portability.h"
#include "logger.h"
+#include "rwlock.h"
#include "uio.h"
-static int pmsgOpen();
-static void pmsgClose();
-static int pmsgAvailable(log_id_t logId);
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static void PmsgClose();
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
struct android_log_transport_write pmsgLoggerWrite = {
.name = "pmsg",
.logMask = 0,
- .context.fd = -1,
- .available = pmsgAvailable,
- .open = pmsgOpen,
- .close = pmsgClose,
- .write = pmsgWrite,
+ .available = [](log_id_t) { return 0; },
+ .open = [] { return 0; },
+ .close = PmsgClose,
+ .write = PmsgWrite,
};
-static int pmsgOpen() {
- int fd = atomic_load(&pmsgLoggerWrite.context.fd);
- if (fd < 0) {
- int i;
+static int pmsg_fd;
+static RwLock pmsg_fd_lock;
- fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
- if ((i >= 0) && (i != fd)) {
- close(i);
- }
+static void PmsgOpen() {
+ auto lock = std::unique_lock{pmsg_fd_lock};
+ if (pmsg_fd > 0) {
+ // Someone raced us and opened the socket already.
+ return;
}
- return fd;
+ pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
}
-static void pmsgClose() {
- int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
- if (fd >= 0) {
- close(fd);
+static void PmsgClose() {
+ auto lock = std::unique_lock{pmsg_fd_lock};
+ if (pmsg_fd > 0) {
+ close(pmsg_fd);
}
+ pmsg_fd = 0;
}
-static int pmsgAvailable(log_id_t logId) {
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
- }
- if ((logId != LOG_ID_SECURITY) && (logId != LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
- return -EINVAL;
- }
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (access("/dev/pmsg0", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
-}
-
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
static const unsigned headerLength = 2;
struct iovec newVec[nr + headerLength];
android_log_header_t header;
@@ -94,17 +77,31 @@
size_t i, payloadSize;
ssize_t ret;
- if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
+ if (!__android_log_is_debuggable()) {
+ if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
+ return -1;
}
- if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
- return -EPERM;
+ if (logId == LOG_ID_EVENTS) {
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
+
+ if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
+ return -EPERM;
+ }
}
}
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ auto lock = std::shared_lock{pmsg_fd_lock};
+
+ if (pmsg_fd <= 0) {
+ lock.unlock();
+ PmsgOpen();
+ lock.lock();
+ }
+
+ if (pmsg_fd <= 0) {
return -EBADF;
}
@@ -158,7 +155,7 @@
}
pmsgHeader.len += payloadSize;
- ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd), newVec, i));
+ ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
if (ret < 0) {
ret = errno ? -errno : -ENOTCONN;
}
@@ -193,7 +190,6 @@
/* Write a buffer as filename references (tag = <basedir>:<basename>) */
ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
const char* buf, size_t len) {
- bool weOpened;
size_t length, packet_len;
const char* tag;
char *cp, *slash;
@@ -233,7 +229,6 @@
vec[1].iov_base = (unsigned char*)tag;
vec[1].iov_len = length;
- weOpened = false;
for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
ssize_t ret;
size_t transfer;
@@ -254,37 +249,15 @@
vec[2].iov_base = (unsigned char*)buf;
vec[2].iov_len = transfer;
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (!weOpened) { /* Impossible for weOpened = true here */
- __android_log_lock();
- }
- weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
- if (!weOpened) {
- __android_log_unlock();
- } else if (pmsgOpen() < 0) {
- __android_log_unlock();
- free(cp);
- return -EBADF;
- }
- }
-
- ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+ ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
if (ret <= 0) {
- if (weOpened) {
- pmsgClose();
- __android_log_unlock();
- }
free(cp);
return ret ? ret : (len - length);
}
length -= transfer;
buf += transfer;
}
- if (weOpened) {
- pmsgClose();
- __android_log_unlock();
- }
free(cp);
return len;
}