summaryrefslogtreecommitdiffstats
path: root/liblog/log_read.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblog/log_read.c')
-rw-r--r--liblog/log_read.c857
1 files changed, 458 insertions, 399 deletions
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 47aa711..ca5a1a7 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -14,37 +14,180 @@
** limitations under the License.
*/
-#define _GNU_SOURCE /* asprintf for x86 host */
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <poll.h>
-#include <string.h>
-#include <stdio.h>
+#include <signal.h>
+#include <stddef.h>
+#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+
#include <cutils/list.h>
+#include <cutils/sockets.h>
#include <log/log.h>
#include <log/logger.h>
-#include <sys/ioctl.h>
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+
+#define WEAK __attribute__((weak))
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
+/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
+
+#ifdef HAVE_WINSOCK
+
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+ errno = ENOSYS;
+ return -ENOSYS;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+/* Private copy of ../libcutils/socket_local.h prevent library loops */
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+/* End of ../libcutils/socket_local.h */
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
+ struct sockaddr_un *p_addr, socklen_t *alen)
+{
+ memset (p_addr, 0, sizeof (*p_addr));
+ size_t namelen;
+
+ switch (namespaceId) {
+ case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+ namelen = strlen(name);
+
+ /* Test with length +1 for the *initial* '\0'. */
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
+
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
+
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+ /* this OS doesn't have the Linux abstract namespace */
+
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_RESERVED:
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, name);
+ break;
+
+ default:
+ /* invalid namespace id */
+ return -1;
+ }
+
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId,
+ int type __unused)
+{
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int err;
+
+ err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ goto error;
+ }
+
+ if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+ goto error;
+ }
+
+ return fd;
-#define __LOGGERIO 0xAE
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+ int s;
-#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
-#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
-#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
+ s = socket(AF_LOCAL, type, 0);
+ if(s < 0) return -1;
-typedef char bool;
-#define false (const bool)0
-#define true (const bool)1
+ if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
-#define LOG_FILE_DIR "/dev/log/"
+ return s;
+}
-/* timeout in milliseconds */
-#define LOG_TIMEOUT_FLUSH 5
-#define LOG_TIMEOUT_NEVER -1
+#endif /* !HAVE_WINSOCK */
+/* End of ../libcutils/socket_local_client.c */
#define logger_for_each(logger, logger_list) \
for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
@@ -56,47 +199,21 @@ static const char *LOG_NAME[LOG_ID_MAX] = {
[LOG_ID_MAIN] = "main",
[LOG_ID_RADIO] = "radio",
[LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system"
+ [LOG_ID_SYSTEM] = "system",
+ [LOG_ID_CRASH] = "crash",
};
-const char *android_log_id_to_name(log_id_t log_id) {
+const char *android_log_id_to_name(log_id_t log_id)
+{
if (log_id >= LOG_ID_MAX) {
log_id = LOG_ID_MAIN;
}
return LOG_NAME[log_id];
}
-static int accessmode(int mode)
+log_id_t android_name_to_log_id(const char *logName)
{
- if ((mode & O_ACCMODE) == O_WRONLY) {
- return W_OK;
- }
- if ((mode & O_ACCMODE) == O_RDWR) {
- return R_OK | W_OK;
- }
- return R_OK;
-}
-
-/* repeated fragment */
-static int check_allocate_accessible(char **n, const char *b, int mode)
-{
- *n = NULL;
-
- if (!b) {
- return -EINVAL;
- }
-
- asprintf(n, LOG_FILE_DIR "%s", b);
- if (!*n) {
- return -1;
- }
-
- return access(*n, accessmode(mode));
-}
-
-log_id_t android_name_to_log_id(const char *logName) {
const char *b;
- char *n;
int ret;
if (!logName) {
@@ -109,12 +226,6 @@ log_id_t android_name_to_log_id(const char *logName) {
++b;
}
- ret = check_allocate_accessible(&n, b, O_RDONLY);
- free(n);
- if (ret) {
- return ret;
- }
-
for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
const char *l = LOG_NAME[ret];
if (l && !strcmp(b, l)) {
@@ -128,27 +239,15 @@ struct logger_list {
struct listnode node;
int mode;
unsigned int tail;
+ log_time start;
pid_t pid;
- unsigned int queued_lines;
- int timeout_ms;
- int error;
- bool flush;
- bool valid_entry; /* valiant(?) effort to deal with memory starvation */
- struct log_msg entry;
-};
-
-struct log_list {
- struct listnode node;
- struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+ int sock;
};
struct logger {
struct listnode node;
struct logger_list *top;
- int fd;
log_id_t id;
- short *revents;
- struct listnode log_list;
};
/* android_logger_alloc unimplemented, no use case */
@@ -159,91 +258,209 @@ static void android_logger_free(struct logger *logger)
return;
}
- while (!list_empty(&logger->log_list)) {
- struct log_list *entry = node_to_item(
- list_head(&logger->log_list), struct log_list, node);
- list_remove(&entry->node);
- free(entry);
- if (logger->top->queued_lines) {
- logger->top->queued_lines--;
- }
- }
-
- if (logger->fd >= 0) {
- close(logger->fd);
- }
-
list_remove(&logger->node);
free(logger);
}
+/* android_logger_alloc unimplemented, no use case */
+
+/* method for getting the associated sublog id */
log_id_t android_logger_get_id(struct logger *logger)
{
return logger->id;
}
/* worker for sending the command to the logger */
-static int logger_ioctl(struct logger *logger, int cmd, int mode)
+static ssize_t send_log_msg(struct logger *logger,
+ const char *msg, char *buf, size_t buf_size)
{
- char *n;
- int f, ret;
-
- if (!logger || !logger->top) {
- return -EFAULT;
+ ssize_t ret;
+ size_t len;
+ char *cp;
+ int errno_save = 0;
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock < 0) {
+ return sock;
}
- if (((mode & O_ACCMODE) == O_RDWR)
- || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
- return ioctl(logger->fd, cmd);
+ if (msg) {
+ snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
}
- /* We go here if android_logger_list_open got mode wrong for this ioctl */
- ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
- if (ret) {
- free(n);
- return ret;
+ len = strlen(buf) + 1;
+ ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+ if (ret <= 0) {
+ goto done;
}
- f = open(n, mode);
- free(n);
- if (f < 0) {
- return f;
+ len = buf_size;
+ cp = buf;
+ while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+ struct pollfd p;
+
+ if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+ break;
+ }
+
+ len -= ret;
+ cp += ret;
+
+ memset(&p, 0, sizeof(p));
+ p.fd = sock;
+ p.events = POLLIN;
+
+ /* Give other side 20ms to refill pipe */
+ ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+ if (ret <= 0) {
+ break;
+ }
+
+ if (!(p.revents & POLLIN)) {
+ ret = 0;
+ break;
+ }
}
- ret = ioctl(f, cmd);
- close (f);
+ if (ret >= 0) {
+ ret += buf_size - len;
+ }
+done:
+ if ((ret == -1) && errno) {
+ errno_save = errno;
+ }
+ close(sock);
+ if (errno_save) {
+ errno = errno_save;
+ }
return ret;
}
+static int check_log_success(char *buf, ssize_t ret)
+{
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (strncmp(buf, "success", 7)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
int android_logger_clear(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+ char buf[512];
+
+ return check_log_success(buf,
+ send_log_msg(logger, "clear %d", buf, sizeof(buf)));
}
/* returns the total size of the log's ring buffer */
-int android_logger_get_log_size(struct logger *logger)
+long android_logger_get_log_size(struct logger *logger)
+{
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
+}
+
+int android_logger_set_log_size(struct logger *logger, unsigned long size)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+ char buf[512];
+
+ snprintf(buf, sizeof(buf), "setLogSize %d %lu",
+ logger ? logger->id : (unsigned) -1, size);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
}
/*
* returns the readable size of the log's ring buffer (that is, amount of the
* log consumed)
*/
-int android_logger_get_log_readable_size(struct logger *logger)
+long android_logger_get_log_readable_size(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
}
/*
* returns the logger version
*/
-int android_logger_get_log_version(struct logger *logger)
+int android_logger_get_log_version(struct logger *logger __unused)
+{
+ return 3;
+}
+
+/*
+ * returns statistics
+ */
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+ char *buf, size_t len)
+{
+ struct logger *logger;
+ char *cp = buf;
+ size_t remaining = len;
+ size_t n;
+
+ n = snprintf(cp, remaining, "getStatistics");
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+
+ logger_for_each(logger, logger_list) {
+ n = snprintf(cp, remaining, " %d", logger->id);
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+ }
+ return send_log_msg(NULL, NULL, buf, len);
+}
+
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
+ char *buf, size_t len)
+{
+ return send_log_msg(NULL, "getPruneList", buf, len);
+}
+
+int android_logger_set_prune_list(struct logger_list *logger_list __unused,
+ char *buf, size_t len)
{
- int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
- return (ret < 0) ? 1 : ret;
+ const char cmd[] = "setPruneList ";
+ const size_t cmdlen = sizeof(cmd) - 1;
+
+ if (strlen(buf) > (len - cmdlen)) {
+ return -ENOMEM; /* KISS */
+ }
+ memmove(buf + cmdlen, buf, len - cmdlen);
+ buf[len - 1] = '\0';
+ memcpy(buf, cmd, cmdlen);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
}
struct logger_list *android_logger_list_alloc(int mode,
@@ -256,10 +473,36 @@ struct logger_list *android_logger_list_alloc(int mode,
if (!logger_list) {
return NULL;
}
+
list_init(&logger_list->node);
logger_list->mode = mode;
+ logger_list->start.tv_sec = 0;
+ logger_list->start.tv_nsec = 0;
logger_list->tail = tail;
logger_list->pid = pid;
+ logger_list->sock = -1;
+
+ return logger_list;
+}
+
+struct logger_list *android_logger_list_alloc_time(int mode,
+ log_time start,
+ pid_t pid)
+{
+ struct logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+
+ list_init(&logger_list->node);
+ logger_list->mode = mode;
+ logger_list->start = start;
+ logger_list->tail = 0;
+ logger_list->pid = pid;
+ logger_list->sock = -1;
+
return logger_list;
}
@@ -270,9 +513,7 @@ struct logger_list *android_logger_list_alloc(int mode,
struct logger *android_logger_open(struct logger_list *logger_list,
log_id_t id)
{
- struct listnode *node;
struct logger *logger;
- char *n;
if (!logger_list || (id >= LOG_ID_MAX)) {
goto err;
@@ -289,28 +530,11 @@ struct logger *android_logger_open(struct logger_list *logger_list,
goto err;
}
- if (check_allocate_accessible(&n, android_log_id_to_name(id),
- logger_list->mode)) {
- goto err_name;
- }
-
- logger->fd = open(n, logger_list->mode);
- if (logger->fd < 0) {
- goto err_name;
- }
-
- free(n);
logger->id = id;
- list_init(&logger->log_list);
list_add_tail(&logger_list->node, &logger->node);
logger->top = logger_list;
- logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
goto ok;
-err_name:
- free(n);
-err_logger:
- free(logger);
err:
logger = NULL;
ok:
@@ -336,315 +560,146 @@ struct logger_list *android_logger_list_open(log_id_t id,
return logger_list;
}
-/* prevent memory starvation when backfilling */
-static unsigned int queue_threshold(struct logger_list *logger_list)
-{
- return (logger_list->tail < 64) ? 64 : logger_list->tail;
-}
-
-static bool low_queue(struct listnode *node)
-{
- /* low is considered less than 2 */
- return list_head(node) == list_tail(node);
-}
-
-/* Flush queues in sequential order, one at a time */
-static int android_logger_list_flush(struct logger_list *logger_list,
- struct log_msg *log_msg)
+static void caught_signal(int signum __unused)
{
- int ret = 0;
- struct log_list *firstentry = NULL;
-
- while ((ret == 0)
- && (logger_list->flush
- || (logger_list->queued_lines > logger_list->tail))) {
- struct logger *logger;
-
- /* Merge sort */
- bool at_least_one_is_low = false;
- struct logger *firstlogger = NULL;
- firstentry = NULL;
-
- logger_for_each(logger, logger_list) {
- struct listnode *node;
- struct log_list *oldest = NULL;
-
- /* kernel logger channels not necessarily time-sort order */
- list_for_each(node, &logger->log_list) {
- struct log_list *entry = node_to_item(node,
- struct log_list, node);
- if (!oldest
- || (entry->entry.entry.sec < oldest->entry.entry.sec)
- || ((entry->entry.entry.sec == oldest->entry.entry.sec)
- && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
- oldest = entry;
- }
- }
-
- if (!oldest) {
- at_least_one_is_low = true;
- continue;
- } else if (low_queue(&logger->log_list)) {
- at_least_one_is_low = true;
- }
-
- if (!firstentry
- || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
- || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
- && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
- firstentry = oldest;
- firstlogger = logger;
- }
- }
-
- if (!firstentry) {
- break;
- }
-
- /* when trimming list, tries to keep one entry behind in each bucket */
- if (!logger_list->flush
- && at_least_one_is_low
- && (logger_list->queued_lines < queue_threshold(logger_list))) {
- break;
- }
-
- /* within tail?, send! */
- if ((logger_list->tail == 0)
- || (logger_list->queued_lines <= logger_list->tail)) {
- ret = firstentry->entry.entry.hdr_size;
- if (!ret) {
- ret = sizeof(firstentry->entry.entry_v1);
- }
- ret += firstentry->entry.entry.len;
-
- memcpy(log_msg->buf, firstentry->entry.buf, ret + 1);
- log_msg->extra.id = firstlogger->id;
- }
-
- /* next entry */
- list_remove(&firstentry->node);
- free(firstentry);
- if (logger_list->queued_lines) {
- logger_list->queued_lines--;
- }
- }
-
- /* Flushed the list, no longer in tail mode for continuing content */
- if (logger_list->flush && !firstentry) {
- logger_list->tail = 0;
- }
- return ret;
}
/* Read from the selected logs */
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
+ int ret, e;
struct logger *logger;
- nfds_t nfds;
- struct pollfd *p, *pollfds = NULL;
- int error = 0, ret = 0;
-
- memset(log_msg, 0, sizeof(struct log_msg));
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
if (!logger_list) {
- return -ENODEV;
- }
-
- if (!(accessmode(logger_list->mode) & R_OK)) {
- logger_list->error = EPERM;
- goto done;
- }
-
- nfds = 0;
- logger_for_each(logger, logger_list) {
- ++nfds;
- }
- if (nfds <= 0) {
- error = ENODEV;
- goto done;
- }
-
- /* Do we have anything to offer from the buffer or state? */
- if (logger_list->valid_entry) { /* implies we are also in a flush state */
- goto flush;
- }
-
- ret = android_logger_list_flush(logger_list, log_msg);
- if (ret) {
- goto done;
+ return -EINVAL;
}
- if (logger_list->error) { /* implies we are also in a flush state */
- goto done;
+ if (logger_list->mode & O_NONBLOCK) {
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
}
- /* Lets start grinding on metal */
- pollfds = calloc(nfds, sizeof(struct pollfd));
- if (!pollfds) {
- error = ENOMEM;
- goto flush;
- }
+ if (logger_list->sock < 0) {
+ char buffer[256], *cp, c;
- p = pollfds;
- logger_for_each(logger, logger_list) {
- p->fd = logger->fd;
- p->events = POLLIN;
- logger->revents = &p->revents;
- ++p;
- }
-
- while (!ret && !error) {
- int result;
-
- /* If we oversleep it's ok, i.e. ignore EINTR. */
- result = TEMP_FAILURE_RETRY(
- poll(pollfds, nfds, logger_list->timeout_ms));
-
- if (result <= 0) {
- if (result) {
- error = errno;
- } else if (logger_list->mode & O_NDELAY) {
- error = EAGAIN;
- } else {
- logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+ int sock = socket_local_client("logdr",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET);
+ if (sock < 0) {
+ if ((sock == -1) && errno) {
+ return -errno;
}
-
- logger_list->flush = true;
- goto try_flush;
+ return sock;
}
- logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
-
- /* Anti starvation */
- if (!logger_list->flush
- && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
- /* Any queues with input pending that is low? */
- bool starving = false;
- logger_for_each(logger, logger_list) {
- if ((*(logger->revents) & POLLIN)
- && low_queue(&logger->log_list)) {
- starving = true;
- break;
- }
- }
+ strcpy(buffer,
+ (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+ cp = buffer + strlen(buffer);
- /* pushback on any queues that are not low */
- if (starving) {
- logger_for_each(logger, logger_list) {
- if ((*(logger->revents) & POLLIN)
- && !low_queue(&logger->log_list)) {
- *(logger->revents) &= ~POLLIN;
- }
- }
- }
+ strcpy(cp, " lids");
+ cp += 5;
+ c = '=';
+ int remaining = sizeof(buffer) - (cp - buffer);
+ logger_for_each(logger, logger_list) {
+ ret = snprintf(cp, remaining, "%c%u", c, logger->id);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ c = ',';
}
- logger_for_each(logger, logger_list) {
- unsigned int hdr_size;
- struct log_list *entry;
+ if (logger_list->tail) {
+ ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
- if (!(*(logger->revents) & POLLIN)) {
- continue;
- }
+ if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+ ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+ logger_list->start.tv_sec,
+ logger_list->start.tv_nsec);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
- memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
- /* NOTE: driver guarantees we read exactly one full entry */
- result = read(logger->fd, logger_list->entry.buf,
- LOGGER_ENTRY_MAX_LEN);
- if (result <= 0) {
- if (!result) {
- error = EIO;
- } else if (errno != EINTR) {
- error = errno;
- }
- continue;
- }
+ if (logger_list->pid) {
+ ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
- if (logger_list->pid
- && (logger_list->pid != logger_list->entry.entry.pid)) {
- continue;
+ if (logger_list->mode & O_NONBLOCK) {
+ /* Deal with an unresponsive logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ ret = write(sock, buffer, cp - buffer);
+ e = errno;
+ if (logger_list->mode & O_NONBLOCK) {
+ if (e == EINTR) {
+ e = ETIMEDOUT;
}
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
- hdr_size = logger_list->entry.entry.hdr_size;
- if (!hdr_size) {
- hdr_size = sizeof(logger_list->entry.entry_v1);
+ if (ret <= 0) {
+ close(sock);
+ if ((ret == -1) && e) {
+ return -e;
}
-
- if ((hdr_size > sizeof(struct log_msg))
- || (logger_list->entry.entry.len
- > sizeof(logger_list->entry.buf) - hdr_size)
- || (logger_list->entry.entry.len != result - hdr_size)) {
- error = EINVAL;
- continue;
+ if (ret == 0) {
+ return -EIO;
}
+ return ret;
+ }
- logger_list->entry.extra.id = logger->id;
-
- /* speedup: If not tail, and only one list, send directly */
- if (!logger_list->tail
- && (list_head(&logger_list->node)
- == list_tail(&logger_list->node))) {
- ret = result;
- memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
- log_msg->extra.id = logger->id;
- break;
- }
+ logger_list->sock = sock;
+ }
- entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
+ ret = 0;
+ while(1) {
+ memset(log_msg, 0, sizeof(*log_msg));
- if (!entry) {
- logger_list->valid_entry = true;
- error = ENOMEM;
- break;
+ if (logger_list->mode & O_NONBLOCK) {
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+ ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+ e = errno;
+ if (logger_list->mode & O_NONBLOCK) {
+ if ((ret == 0) || (e == EINTR)) {
+ e = EAGAIN;
+ ret = -1;
}
-
- logger_list->queued_lines++;
-
- memcpy(entry->entry.buf, logger_list->entry.buf, result);
- entry->entry.buf[result] = '\0';
- list_add_tail(&logger->log_list, &entry->node);
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
}
if (ret <= 0) {
-try_flush:
- ret = android_logger_list_flush(logger_list, log_msg);
- }
- }
-
- free(pollfds);
-
-flush:
- if (error) {
- logger_list->flush = true;
- }
-
- if (ret <= 0) {
- ret = android_logger_list_flush(logger_list, log_msg);
-
- if (!ret && logger_list->valid_entry) {
- ret = logger_list->entry.entry.hdr_size;
- if (!ret) {
- ret = sizeof(logger_list->entry.entry_v1);
+ if ((ret == -1) && e) {
+ return -e;
}
- ret += logger_list->entry.entry.len;
-
- memcpy(log_msg->buf, logger_list->entry.buf,
- sizeof(struct log_msg));
- logger_list->valid_entry = false;
+ return ret;
}
- }
-done:
- if (logger_list->error) {
- error = logger_list->error;
- }
- if (error) {
- logger_list->error = error;
- if (!ret) {
- ret = -error;
+ logger_for_each(logger, logger_list) {
+ if (log_msg->entry.lid == logger->id) {
+ return ret;
+ }
}
}
+ /* NOTREACH */
return ret;
}
@@ -661,5 +716,9 @@ void android_logger_list_free(struct logger_list *logger_list)
android_logger_free(logger);
}
+ if (logger_list->sock >= 0) {
+ close (logger_list->sock);
+ }
+
free(logger_list);
}