liblog: add local_logger
- Create the local-only logger module
- Add LOGGER_LOCAL flag to android_set_log_frontend to enable
- Permit log reader for host compilation
android_set_log_frontend(LOGGER_LOCAL) will result in logs going
into application local memory. logcat can not retrieve the data,
the user must utilize the log reading interface directly to
acquire their own logs. Some local logger tests dropped as they
represent testing other liblog facilities. Other local logger
tests dropped because we make the conscious decision to not
support LOG_ID_SECURITY logging.
ToDo: Some local logger tests dropped because of missing
functionality associated with blocking reader.
Test: gTest libcutils-tests, logd-unit-tests, liblog-unit-tests,
logcat-unit-tests, liblog-benchmarks and CtsLiblogTestCases_list
Bug: 27405083
Change-Id: Ia23b932af9e05756eaa60bab9139876b14faf72d
diff --git a/liblog/Android.bp b/liblog/Android.bp
index cd67845..310dbf4 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -15,12 +15,15 @@
//
liblog_sources = [
+ "config_read.c",
"config_write.c",
+ "local_logger.c",
"log_event_list.c",
"log_event_write.c",
"log_ratelimit.cpp",
"logger_lock.c",
"logger_name.c",
+ "logger_read.c",
"logger_write.c",
"logprint.c",
]
@@ -30,14 +33,12 @@
]
liblog_target_sources = [
"event_tag_map.cpp",
- "config_read.c",
"log_time.cpp",
"properties.c",
"pmsg_reader.c",
"pmsg_writer.c",
"logd_reader.c",
"logd_writer.c",
- "logger_read.c",
]
// Shared and static library for host and device
diff --git a/liblog/README b/liblog/README
index 922b5e3..40a39ad 100644
--- a/liblog/README
+++ b/liblog/README
@@ -168,9 +168,10 @@
ANDROID_LOG_RDONLY in these cases.
android_set_log_frontend() selects frontend filters. Argument is either
- LOGGER_DEFAULT, LOGGER_LOGD or LOGGER_NULL. The latter drops all
- content on the floor. Both android_set_log_frontend() and
- android_get_log_frontend() return the current frontend mask, or a
+ LOGGER_DEFAULT, LOGGER_LOGD, LOGGER_NULL or LOGGER_LOCAL. Log to logger
+ daemon for default or logd, drop contents on floor, or log into local
+ memory respectively. Both android_set_log_frontend() and
+ android_get_log_frontend() return the current frontend mask, or a
negative errno for any problems.
ERRORS
diff --git a/liblog/config_read.c b/liblog/config_read.c
index a4232f4..b9a281b 100644
--- a/liblog/config_read.c
+++ b/liblog/config_read.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <log/log_frontend.h>
+
#include "config_read.h"
#include "logger.h"
@@ -52,12 +54,24 @@
}
LIBLOG_HIDDEN void __android_log_config_read() {
-#if (FAKE_LOG_DEVICE == 0)
- extern struct android_log_transport_read logdLoggerRead;
- extern struct android_log_transport_read pmsgLoggerRead;
+ if (__android_log_frontend & LOGGER_LOCAL) {
+ extern struct android_log_transport_read localLoggerRead;
- __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
- __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
+ __android_log_add_transport(&__android_log_transport_read,
+ &localLoggerRead);
+ }
+
+#if (FAKE_LOG_DEVICE == 0)
+ if ((__android_log_frontend == LOGGER_DEFAULT) ||
+ (__android_log_frontend & LOGGER_LOGD)) {
+ extern struct android_log_transport_read logdLoggerRead;
+ extern struct android_log_transport_read pmsgLoggerRead;
+
+ __android_log_add_transport(&__android_log_transport_read,
+ &logdLoggerRead);
+ __android_log_add_transport(&__android_log_persist_read,
+ &pmsgLoggerRead);
+ }
#endif
}
diff --git a/liblog/config_write.c b/liblog/config_write.c
index 0aaaea6..583dcff 100644
--- a/liblog/config_write.c
+++ b/liblog/config_write.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <log/log_frontend.h>
+
#include "config_write.h"
#include "logger.h"
@@ -52,17 +54,30 @@
}
LIBLOG_HIDDEN void __android_log_config_write() {
+ if (__android_log_frontend & LOGGER_LOCAL) {
+ extern struct android_log_transport_write localLoggerWrite;
+
+ __android_log_add_transport(&__android_log_transport_write,
+ &localLoggerWrite);
+ }
+
+ if ((__android_log_frontend == LOGGER_DEFAULT) ||
+ (__android_log_frontend & LOGGER_LOGD)) {
#if (FAKE_LOG_DEVICE == 0)
- extern struct android_log_transport_write logdLoggerWrite;
- extern struct android_log_transport_write pmsgLoggerWrite;
+ extern struct android_log_transport_write logdLoggerWrite;
+ extern struct android_log_transport_write pmsgLoggerWrite;
- __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
- __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
+ __android_log_add_transport(&__android_log_transport_write,
+ &logdLoggerWrite);
+ __android_log_add_transport(&__android_log_persist_write,
+ &pmsgLoggerWrite);
#else
- extern struct android_log_transport_write fakeLoggerWrite;
+ extern struct android_log_transport_write fakeLoggerWrite;
- __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
+ __android_log_add_transport(&__android_log_transport_write,
+ &fakeLoggerWrite);
#endif
+ }
}
LIBLOG_HIDDEN void __android_log_config_write_close() {
diff --git a/liblog/include/log/log_frontend.h b/liblog/include/log/log_frontend.h
index c2f8b7b..9527779 100644
--- a/liblog/include/log/log_frontend.h
+++ b/liblog/include/log/log_frontend.h
@@ -21,6 +21,7 @@
#define LOGGER_LOGD 0x1
#define LOGGER_KERNEL 0x2 /* Reserved/Deprecated */
#define LOGGER_NULL 0x4 /* Does not release resources of other selections */
+#define LOGGER_LOCAL 0x8 /* logs sent to local memory */
/* Both return the selected frontend flag mask, or negative errno */
int android_set_log_frontend(int frontend_flag);
diff --git a/liblog/local_logger.c b/liblog/local_logger.c
new file mode 100644
index 0000000..d504342
--- /dev/null
+++ b/liblog/local_logger.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#if !defined(__MINGW32__)
+#include <pwd.h>
+#endif
+#include <sched.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <log/uio.h>
+
+#include <cutils/list.h> /* template, no library dependency */
+#include <log/log_frontend.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+#include <system/thread_defs.h>
+
+#include "config_read.h"
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static const char baseServiceName[] = "android.logd";
+
+static int writeToLocalInit();
+static int writeToLocalAvailable(log_id_t logId);
+static void writeToLocalReset();
+static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write localLoggerWrite = {
+ .node = { &localLoggerWrite.node, &localLoggerWrite.node },
+ .context.private = NULL,
+ .name = "local",
+ .available = writeToLocalAvailable,
+ .open = writeToLocalInit,
+ .close = writeToLocalReset,
+ .write = writeToLocalWrite,
+};
+
+static int writeToLocalVersion(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static int writeToLocalRead(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg);
+static int writeToLocalPoll(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+static void writeToLocalClose(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+static int writeToLocalClear(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static ssize_t writeToLocalGetSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static ssize_t writeToLocalSetSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused,
+ size_t size);
+static ssize_t writeToLocalGetReadbleSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+
+struct android_log_transport_read localLoggerRead = {
+ .node = { &localLoggerRead.node, &localLoggerRead.node },
+ .name = "local",
+ .available = writeToLocalAvailable,
+ .version = writeToLocalVersion,
+ .read = writeToLocalRead,
+ .poll = writeToLocalPoll,
+ .close = writeToLocalClose,
+ .clear = writeToLocalClear,
+ .getSize = writeToLocalGetSize,
+ .setSize = writeToLocalSetSize,
+ .getReadableSize = writeToLocalGetReadbleSize,
+ .getPrune = NULL,
+ .setPrune = NULL,
+ .getStats = NULL,
+};
+
+struct LogBufferElement {
+ struct listnode node;
+ log_id_t logId;
+ pid_t tid;
+ log_time timestamp;
+ unsigned short len;
+ char msg[];
+};
+
+static const size_t MAX_SIZE_DEFAULT = 32768;
+
+/*
+ * Number of log buffers we support with the following assumption:
+ * . . .
+ * LOG_ID_SECURITY = 5, // security logs go to the system logs only
+ * LOG_ID_KERNEL = 6, // place last, third-parties can not use it
+ * LOG_ID_MAX
+ * } log_id_t;
+ *
+ * Confirm the following should <log/log_id.h> be adjusted in the future.
+ */
+#define NUMBER_OF_LOG_BUFFERS ((LOG_ID_SECURITY == (LOG_ID_MAX - 2)) ? \
+ LOG_ID_SECURITY : \
+ LOG_ID_KERNEL)
+#define BLOCK_LOG_BUFFERS(id) (((id) == LOG_ID_SECURITY) || \
+ ((id) == LOG_ID_KERNEL))
+
+static struct LogBuffer {
+ struct listnode head;
+ pthread_rwlock_t listLock;
+ char *serviceName; /* Also indicates ready by having a value */
+ /* Order and proximity important for memset */
+ size_t number[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
+ size_t size[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
+ size_t totalSize[NUMBER_OF_LOG_BUFFERS]; /* init memset */
+ size_t maxSize[NUMBER_OF_LOG_BUFFERS]; /* init MAX_SIZE_DEFAULT */
+ struct listnode *last[NUMBER_OF_LOG_BUFFERS]; /* init &head */
+} logbuf = {
+ .head = { &logbuf.head, &logbuf.head },
+ .listLock = PTHREAD_RWLOCK_INITIALIZER,
+};
+
+static void LogBufferInit(struct LogBuffer *log) {
+ size_t i;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ list_init(&log->head);
+ memset(log->number, 0,
+ sizeof(log->number) + sizeof(log->size) + sizeof(log->totalSize));
+ for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+ log->maxSize[i] = MAX_SIZE_DEFAULT;
+ log->last[i] = &log->head;
+ }
+#ifdef __BIONIC__
+ asprintf(&log->serviceName, "%s@%d:%d", baseServiceName,
+ __android_log_uid(), getpid());
+#else
+ char buffer[sizeof(baseServiceName) + 1 + 5 + 1 + 5 + 8];
+ snprintf(buffer, sizeof(buffer), "%s@%d:%d", baseServiceName,
+ __android_log_uid(), getpid());
+ log->serviceName = strdup(buffer);
+#endif
+ pthread_rwlock_unlock(&log->listLock);
+}
+
+static void LogBufferClear(struct LogBuffer *log) {
+ size_t i;
+ struct listnode *node;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ memset(log->number, 0, sizeof(log->number) + sizeof(log->size));
+ for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+ log->last[i] = &log->head;
+ }
+ while ((node = list_head(&log->head)) != &log->head) {
+ struct LogBufferElement *element;
+
+ element = node_to_item(node, struct LogBufferElement, node);
+ list_remove(node);
+ free(element);
+ }
+ pthread_rwlock_unlock(&log->listLock);
+}
+
+static inline void LogBufferFree(struct LogBuffer *log) {
+ pthread_rwlock_wrlock(&log->listLock);
+ free(log->serviceName);
+ log->serviceName = NULL;
+ pthread_rwlock_unlock(&log->listLock);
+ LogBufferClear(log);
+}
+
+static int LogBufferLog(struct LogBuffer *log,
+ struct LogBufferElement *element) {
+ log_id_t logId = element->logId;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ log->number[logId]++;
+ log->size[logId] += element->len;
+ log->totalSize[logId] += element->len;
+ /* prune entry(s) until enough space is available */
+ if (log->last[logId] == &log->head) {
+ log->last[logId] = list_tail(&log->head);
+ }
+ while (log->size[logId] > log->maxSize[logId]) {
+ struct listnode *node = log->last[logId];
+ struct LogBufferElement *e;
+ struct android_log_logger_list *logger_list;
+
+ e = node_to_item(node, struct LogBufferElement, node);
+ log->number[logId]--;
+ log->size[logId] -= e->len;
+ logger_list_rdlock();
+ logger_list_for_each(logger_list) {
+ struct android_log_transport_context *transp;
+
+ transport_context_for_each(transp, logger_list) {
+ if ((transp->transport == &localLoggerRead) &&
+ (transp->context.node == node)) {
+ if (node == &log->head) {
+ transp->context.node = &log->head;
+ } else {
+ transp->context.node = node->next;
+ }
+ }
+ }
+ }
+ logger_list_unlock();
+ if (node != &log->head) {
+ log->last[logId] = node->prev;
+ }
+ list_remove(node);
+ free(e);
+ }
+ /* add entry to list */
+ list_add_head(&log->head, &element->node);
+ /* ToDo: wake up all readers */
+ pthread_rwlock_unlock(&log->listLock);
+
+ return element->len;
+}
+
+/*
+ * return zero if permitted to log directly to logd,
+ * return 1 if binder server started and
+ * return negative error number if failed to start binder server.
+ */
+static int writeToLocalInit() {
+ pthread_attr_t attr;
+ struct LogBuffer *log;
+
+ if (writeToLocalAvailable(LOG_ID_MAIN) < 0) {
+ return -EPERM;
+ }
+
+ log = &logbuf;
+ if (!log->serviceName) {
+ LogBufferInit(log);
+ }
+
+ if (!log->serviceName) {
+ LogBufferFree(log);
+ return -ENOMEM;
+ }
+
+ return EPERM; /* successful local-only logging */
+}
+
+static void writeToLocalReset() {
+ LogBufferFree(&logbuf);
+}
+
+static int writeToLocalAvailable(log_id_t logId) {
+#if !defined(__MINGW32__)
+ uid_t uid;
+#endif
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+ /* Android hard coded permitted, system goes to logd */
+#if !defined(__MINGW32__)
+ if (__android_log_frontend == LOGGER_DEFAULT) {
+ uid = __android_log_uid();
+ if ((uid < AID_APP) && (getpwuid(uid) != NULL)) {
+ return -EPERM;
+ }
+ }
+#endif
+
+ /* ToDo: Ask package manager for LOGD permissions */
+ /* Assume we do _not_ have permissions to go to LOGD, so must go local */
+ return 0;
+}
+
+static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr) {
+ size_t len, i;
+ struct LogBufferElement *element;
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+ len = 0;
+ for (i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+
+ if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ len = LOGGER_ENTRY_MAX_PAYLOAD;
+ }
+ element = (struct LogBufferElement *)calloc(1,
+ sizeof(struct LogBufferElement) + len + 1);
+ if (!element) {
+ return errno ? -errno : -ENOMEM;
+ }
+ element->timestamp.tv_sec = ts->tv_sec;
+ element->timestamp.tv_nsec = ts->tv_nsec;
+#ifdef __BIONIC__
+ element->tid = gettid();
+#else
+ element->tid = getpid();
+#endif
+ element->logId = logId;
+ element->len = len;
+
+ char *cp = element->msg;
+ for (i = 0; i < nr; ++i) {
+ size_t iov_len = vec[i].iov_len;
+ if (iov_len > len) {
+ iov_len = len;
+ }
+ memcpy(cp, vec[i].iov_base, iov_len);
+ len -= iov_len;
+ if (len == 0) {
+ break;
+ }
+ cp += iov_len;
+ }
+
+ return LogBufferLog(&logbuf, element);
+}
+
+static int writeToLocalVersion(
+ struct android_log_logger *logger __unused,
+ struct android_log_transport_context *transp __unused) {
+ return 3;
+}
+
+/* within reader lock, serviceName already validated */
+static struct listnode *writeToLocalNode(
+ struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp) {
+ struct listnode *node;
+ unsigned logMask;
+ unsigned int tail;
+
+ node = transp->context.node;
+ if (node) {
+ return node;
+ }
+
+ if (!logger_list->tail) {
+ return transp->context.node = &logbuf.head;
+ }
+
+ logMask = transp->logMask;
+ tail = logger_list->tail;
+
+ for (node = list_head(&logbuf.head); node != &logbuf.head; node = node->next) {
+ struct LogBufferElement *element;
+ log_id_t logId;
+
+ element = node_to_item(node, struct LogBufferElement, node);
+ logId = element->logId;
+
+ if ((logMask & (1 << logId)) && !--tail) {
+ node = node->next;
+ break;
+ }
+ }
+ return transp->context.node = node;
+}
+
+static int writeToLocalRead(
+ struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg) {
+ int ret;
+ struct listnode *node;
+ unsigned logMask;
+
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ if (!logbuf.serviceName) {
+ pthread_rwlock_unlock(&logbuf.listLock);
+ return (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+ }
+
+ logMask = transp->logMask;
+
+ node = writeToLocalNode(logger_list, transp);
+
+ ret = 0;
+
+ while (node != list_head(&logbuf.head)) {
+ struct LogBufferElement *element;
+ log_id_t logId;
+
+ node = node->prev;
+ element = node_to_item(node, struct LogBufferElement, node);
+ logId = element->logId;
+
+ if (logMask & (1 << logId)) {
+ ret = log_msg->entry_v3.len = element->len;
+ log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+ log_msg->entry_v3.pid = getpid();
+ log_msg->entry_v3.tid = element->tid;
+ log_msg->entry_v3.sec = element->timestamp.tv_sec;
+ log_msg->entry_v3.nsec = element->timestamp.tv_nsec;
+ log_msg->entry_v3.lid = logId;
+ memcpy(log_msg->entry_v3.msg, element->msg, ret);
+ ret += log_msg->entry_v3.hdr_size;
+ break;
+ }
+ }
+
+ transp->context.node = node;
+
+ /* ToDo: if blocking, and no entry, put reader to sleep */
+ pthread_rwlock_unlock(&logbuf.listLock);
+ return ret;
+}
+
+static int writeToLocalPoll(
+ struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp) {
+ int ret = (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+
+ pthread_rwlock_rdlock(&logbuf.listLock);
+
+ if (logbuf.serviceName) {
+ unsigned logMask = transp->logMask;
+ struct listnode *node = writeToLocalNode(logger_list, transp);
+
+ ret = (node != list_head(&logbuf.head));
+ if (ret) {
+ do {
+ ret = !!(logMask & (1 << (node_to_item(node->prev,
+ struct LogBufferElement,
+ node))->logId));
+ } while (!ret && ((node = node->prev) != list_head(&logbuf.head)));
+ }
+
+ transp->context.node = node;
+ }
+
+ pthread_rwlock_unlock(&logbuf.listLock);
+
+ return ret;
+}
+
+static void writeToLocalClose(
+ struct android_log_logger_list *logger_list __unused,
+ struct android_log_transport_context *transp) {
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ transp->context.node = list_head(&logbuf.head);
+ pthread_rwlock_unlock(&logbuf.listLock);
+}
+
+static int writeToLocalClear(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *unused __unused) {
+ log_id_t logId = logger->logId;
+ struct listnode *node, *n;
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ logbuf.number[logId] = 0;
+ logbuf.last[logId] = &logbuf.head;
+ list_for_each_safe(node, n, &logbuf.head) {
+ struct LogBufferElement *element;
+ element = node_to_item(node, struct LogBufferElement, node);
+
+ if (logId == element->logId) {
+ struct android_log_logger_list *logger_list;
+
+ logger_list_rdlock();
+ logger_list_for_each(logger_list) {
+ struct android_log_transport_context *transp;
+
+ transport_context_for_each(transp, logger_list) {
+ if ((transp->transport == &localLoggerRead) &&
+ (transp->context.node == node)) {
+ transp->context.node = node->next;
+ }
+ }
+ }
+ logger_list_unlock();
+ list_remove(node);
+ free(element);
+ }
+ }
+
+ pthread_rwlock_unlock(&logbuf.listLock);
+
+ return 0;
+}
+
+static ssize_t writeToLocalGetSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused) {
+ ssize_t ret = -EINVAL;
+ log_id_t logId = logger->logId;
+
+ if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ ret = logbuf.maxSize[logId];
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+
+ return ret;
+}
+
+static ssize_t writeToLocalSetSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused,
+ size_t size) {
+ ssize_t ret = -EINVAL;
+
+ if ((size > LOGGER_ENTRY_MAX_LEN) || (size < (4 * 1024 * 1024))) {
+ log_id_t logId = logger->logId;
+ if ((logId < NUMBER_OF_LOG_BUFFERS) || !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ ret = logbuf.maxSize[logId] = size;
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t writeToLocalGetReadbleSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused) {
+ ssize_t ret = -EINVAL;
+ log_id_t logId = logger->logId;
+
+ if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ ret = logbuf.serviceName ? (ssize_t)logbuf.size[logId] : -EBADF;
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+
+ return ret;
+}
diff --git a/liblog/logger.h b/liblog/logger.h
index 471a529..d94cd14 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -196,6 +196,8 @@
LIBLOG_HIDDEN int __android_log_trylock();
LIBLOG_HIDDEN void __android_log_unlock();
+LIBLOG_HIDDEN int __android_log_frontend;
+
__END_DECLS
#endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index bff77f8..e149e68 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -29,6 +29,7 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#include "config_read.h" /* __android_log_config_read_close() definition */
#include "config_write.h"
#include "log_portability.h"
#include "logger.h"
@@ -171,6 +172,8 @@
}
}
+ __android_log_config_write_close();
+
#if defined(__ANDROID__)
/*
* Additional risk here somewhat mitigated by immediately unlock flushing
@@ -639,12 +642,18 @@
/* Following functions need access to our internal write_to_log status */
+LIBLOG_HIDDEN int __android_log_frontend;
+
LIBLOG_ABI_PUBLIC int android_set_log_frontend(int frontend_flag)
{
+ int retval;
+
if (frontend_flag < 0) {
return -EINVAL;
}
+ retval = LOGGER_NULL;
+
__android_log_lock();
if (frontend_flag & LOGGER_NULL) {
@@ -652,20 +661,30 @@
__android_log_unlock();
- return LOGGER_NULL;
+ return retval;
}
- /* Anything else, act as if LOGGER_DEFAULT */
+ __android_log_frontend &= LOGGER_LOCAL | LOGGER_LOGD;
+ frontend_flag &= LOGGER_LOCAL | LOGGER_LOGD;
+
+ if (__android_log_frontend != frontend_flag) {
+ __android_log_frontend = frontend_flag;
+ __android_log_config_write_close();
+ __android_log_config_read_close();
+
+ write_to_log = __write_to_log_init;
/* generically we only expect these two values for write_to_log */
- if ((write_to_log != __write_to_log_init) &&
- (write_to_log != __write_to_log_daemon)) {
+ } else if ((write_to_log != __write_to_log_init) &&
+ (write_to_log != __write_to_log_daemon)) {
write_to_log = __write_to_log_init;
}
+ retval = __android_log_frontend;
+
__android_log_unlock();
- return LOGGER_DEFAULT;
+ return retval;
}
LIBLOG_ABI_PUBLIC int android_get_log_frontend()
@@ -675,9 +694,13 @@
__android_log_lock();
if (write_to_log == __write_to_log_null) {
ret = LOGGER_NULL;
- } else if ((write_to_log != __write_to_log_init) &&
- (write_to_log != __write_to_log_daemon)) {
- ret = -EINVAL;
+ } else {
+ __android_log_frontend &= LOGGER_LOCAL | LOGGER_LOGD;
+ ret = __android_log_frontend;
+ if ((write_to_log != __write_to_log_init) &&
+ (write_to_log != __write_to_log_daemon)) {
+ ret = -EINVAL;
+ }
}
__android_log_unlock();
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 7343412..cfea452 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -55,7 +55,8 @@
-fno-builtin \
test_src_files := \
- liblog_test.cpp \
+ liblog_test_default.cpp \
+ liblog_test_local.cpp \
log_id_test.cpp \
log_radio_test.cpp \
log_read_test.cpp \
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 346314c..bc0ea4c 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -41,6 +41,28 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#ifndef TEST_PREFIX
+#ifdef __ANDROID__ // make sure we always run code if compiled for android
+#define TEST_PREFIX
+#endif
+#endif
+
+#if (!defined(USING_LOGGER_DEFAULT) || !defined(USING_LOGGER_LOCAL))
+#ifdef liblog // a binary clue that we are overriding the test names
+// Does not support log reading blocking feature yet
+// Does not support LOG_ID_SECURITY (unless we set LOGGER_LOCAL | LOGGER_LOGD)
+// Assume some common aspects are tested by USING_LOGGER_DEFAULT:
+// Does not need to _retest_ pmsg functionality
+// Does not need to _retest_ property handling as it is a higher function
+// Does not need to _retest_ event mapping functionality
+// Does not need to _retest_ ratelimit
+// Does not need to _retest_ logprint
+#define USING_LOGGER_LOCAL
+#else
+#define USING_LOGGER_DEFAULT
+#endif
+#endif
+
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
@@ -57,6 +79,9 @@
_rc; })
TEST(liblog, __android_log_btwrite) {
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+#endif
int intBuf = 0xDEADBEEF;
EXPECT_LT(0, __android_log_btwrite(0,
EVENT_TYPE_INT,
@@ -73,7 +98,7 @@
usleep(1000);
}
-#ifdef __ANDROID__
+#if (defined(__ANDROID__) && !defined(USING_LOGGER_LOCAL))
static std::string popenToString(std::string command) {
std::string ret;
@@ -142,7 +167,7 @@
#endif
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
-#ifdef __ANDROID__
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -152,6 +177,7 @@
log_time ts(CLOCK_MONOTONIC);
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+#ifndef USING_LOGGER_LOCAL
// Check that we can close and reopen the logger
bool pmsgActiveAfter__android_log_btwrite;
bool logdwActiveAfter__android_log_btwrite;
@@ -171,15 +197,18 @@
EXPECT_FALSE(pmsgActiveAfter__android_log_close);
EXPECT_FALSE(logdwActiveAfter__android_log_close);
}
+#endif
log_time ts1(CLOCK_MONOTONIC);
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+#ifndef USING_LOGGER_LOCAL
if (getuid() == AID_ROOT) {
pmsgActiveAfter__android_log_btwrite = isPmsgActive();
logdwActiveAfter__android_log_btwrite = isLogdwActive();
EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
}
+#endif
usleep(1000000);
int count = 0;
@@ -226,7 +255,11 @@
// and behind us, to make us whole. We could incorporate a prefix and
// suffix test to make this standalone, but opted to not complicate this.
TEST(liblog, android_set_log_frontend) {
-#ifdef __ANDROID__
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+#endif
+
int logger = android_get_log_frontend();
EXPECT_NE(LOGGER_NULL, logger);
@@ -291,7 +324,7 @@
#endif
}
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static inline uint32_t get4LE(const uint8_t* src) {
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
@@ -302,7 +335,8 @@
#endif
static void bswrite_test(const char *message) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -421,7 +455,8 @@
}
static void buf_write_test(const char *message) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -513,7 +548,8 @@
buf_write_test("\n Hello World \n");
}
-#ifdef __ANDROID__
+#ifndef USING_LOGGER_LOCAL // requires blocking reader functionality
+#ifdef TEST_PREFIX
static unsigned signaled;
static log_time signal_time;
@@ -575,7 +611,8 @@
#endif
TEST(liblog, android_logger_list_read__cpu_signal) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
struct logger_list *logger_list;
unsigned long long v = 0xDEADBEEFA55A0000ULL;
@@ -667,7 +704,7 @@
#endif
}
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
/*
* Strictly, we are not allowed to log messages in a signal context, the
* correct way to handle this is to ensure the messages are constructed in
@@ -733,7 +770,8 @@
#endif
TEST(liblog, android_logger_list_read__cpu_thread) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
struct logger_list *logger_list;
unsigned long long v = 0xDEADBEAFA55A0000ULL;
@@ -825,8 +863,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
sizeof(max_payload_tag) - 1)
@@ -963,7 +1002,8 @@
takes his leave.";
TEST(liblog, max_payload) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
pid_t pid = getpid();
char tag[sizeof(max_payload_tag)];
memcpy(tag, max_payload_tag, sizeof(tag));
@@ -1027,7 +1067,8 @@
}
TEST(liblog, __android_log_buf_print__maxtag) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -1091,7 +1132,8 @@
}
TEST(liblog, too_big_payload) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
pid_t pid = getpid();
static const char big_payload_tag[] = "TEST_big_payload_XXXX";
char tag[sizeof(big_payload_tag)];
@@ -1158,7 +1200,9 @@
}
TEST(liblog, dual_reader) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+
static const int num = 25;
for (int i = 25; i > 0; --i) {
@@ -1218,6 +1262,7 @@
#endif
}
+#ifndef USING_LOGGER_LOCAL // Do not retest logprint
static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
return android_log_shouldPrintLine(p_format, tag, pri)
&& !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
@@ -1286,7 +1331,9 @@
android_log_format_free(p_format);
}
+#endif // !USING_LOGGER_LOCAL
+#ifndef USING_LOGGER_LOCAL // Do not retest property handling
TEST(liblog, is_loggable) {
#ifdef __ANDROID__
static const char tag[] = "is_loggable";
@@ -1585,11 +1632,13 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
-#ifdef __ANDROID__
// Following tests the specific issues surrounding error handling wrt logd.
// Kills logd and toss all collected data, equivalent to logcat -b all -c,
// except we also return errors to the logging callers.
+#ifndef USING_LOGGER_LOCAL
+#ifdef TEST_PREFIX
// helper to liblog.enoent to count end-to-end matching logging messages.
static int count_matching_ts(log_time ts) {
usleep(1000000);
@@ -1631,10 +1680,11 @@
testing::AssertionSuccess() :
(testing::AssertionFailure() << message);
}
-#endif
+#endif // TEST_PREFIX
TEST(liblog, enoent) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+ TEST_PREFIX
log_time ts(CLOCK_MONOTONIC);
EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
EXPECT_EQ(1, count_matching_ts(ts));
@@ -1688,9 +1738,12 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOCAL_LOGGER
// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
+// Do not retest properties, and cannot log into LOG_ID_SECURITY
+#ifndef USING_LOGGER_LOCAL
TEST(liblog, __security) {
#ifdef __ANDROID__
static const char persist_key[] = "persist.logd.security";
@@ -1876,11 +1929,13 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
int UID, const char* payload,
int DATA_LEN, int& count) {
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -1983,7 +2038,7 @@
#endif
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteWithInfoLog_helper(
123456781,
@@ -1999,7 +2054,7 @@
}
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteWithInfoLog_helper(
123456782,
@@ -2015,7 +2070,7 @@
}
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteWithInfoLog_helper(
123456783,
@@ -2031,7 +2086,7 @@
}
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteWithInfoLog_helper(
123456784,
@@ -2054,8 +2109,9 @@
buf_write_test(max_payload_buf);
}
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count) {
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -2125,7 +2181,7 @@
#endif
TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteLog_helper(123456785, "test-subtag", count);
EXPECT_EQ(1, count);
@@ -2135,7 +2191,7 @@
}
TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
int count;
android_errorWriteLog_helper(123456786, NULL, count);
EXPECT_EQ(0, count);
@@ -2144,6 +2200,8 @@
#endif
}
+// Do not retest logger list handling
+#if (defined(TEST_PREFIX) || !defined(USING_LOGGER_LOCAL))
static int is_real_element(int type) {
return ((type == EVENT_TYPE_INT) ||
(type == EVENT_TYPE_LONG) ||
@@ -2302,8 +2360,9 @@
return 0;
}
+#endif // TEST_PREFIX || !USING_LOGGER_LOCAL
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
android_log_context ctx;
@@ -2559,6 +2618,7 @@
}
static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
+ TEST_PREFIX
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -2650,7 +2710,7 @@
#endif
TEST(liblog, create_android_logger_int32) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_int32);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2658,7 +2718,7 @@
}
TEST(liblog, create_android_logger_int64) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_int64);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2666,7 +2726,7 @@
}
TEST(liblog, create_android_logger_list_int64) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_list_int64);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2674,7 +2734,7 @@
}
TEST(liblog, create_android_logger_simple_automagic_list) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_simple_automagic_list);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2682,7 +2742,7 @@
}
TEST(liblog, create_android_logger_list_empty) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_list_empty);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2690,7 +2750,7 @@
}
TEST(liblog, create_android_logger_complex_nested_list) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_complex_nested_list);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2698,7 +2758,7 @@
}
TEST(liblog, create_android_logger_7_level_prefix) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_7_level_prefix);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2706,7 +2766,7 @@
}
TEST(liblog, create_android_logger_7_level_suffix) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_7_level_suffix);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2714,7 +2774,7 @@
}
TEST(liblog, create_android_logger_android_log_error_write) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_android_log_error_write);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2722,13 +2782,14 @@
}
TEST(liblog, create_android_logger_android_log_error_write_null) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
create_android_logger(event_test_android_log_error_write_null);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#ifndef USING_LOGGER_LOCAL // Do not retest logger list handling
TEST(liblog, create_android_logger_overflow) {
android_log_context ctx;
@@ -2768,7 +2829,9 @@
msgBuf, sizeof(msgBuf)), 0);
EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
}
+#endif // !USING_LOGGER_LOCAL
+#ifndef USING_LOGGER_LOCAL // Do not retest pmsg functionality
#ifdef __ANDROID__
static const char __pmsg_file[] =
"/data/william-shakespeare/MuchAdoAboutNothing.txt";
@@ -2894,7 +2957,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
+#ifndef USING_LOGGER_LOCAL // Do not retest event mapping functionality
#ifdef __ANDROID__
// must be: '<needle:> 0 kB'
static bool isZero(const std::string &content, std::string::size_type pos,
@@ -2977,7 +3042,7 @@
EXPECT_TRUE(IsOk(private_ok, content));
EXPECT_TRUE(IsOk(anonymous_ok, content));
}
-#endif
+#endif // __ANDROID__
TEST(liblog, event_log_tags) {
#ifdef __ANDROID__
@@ -2998,7 +3063,9 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
+#ifndef USING_LOGGER_LOCAL // Do not retest ratelimit
TEST(liblog, __android_log_ratelimit) {
time_t state = 0;
@@ -3030,7 +3097,9 @@
}
// Do not test default seconds, to allow liblog to tune freely
}
+#endif // !USING_LOGGER_LOCAL
+#ifndef USING_LOGGER_LOCAL // Do not retest event mapping functionality
TEST(liblog, android_lookupEventTagNum) {
#ifdef __ANDROID__
EventTagMap* map = android_openEventTagMap(NULL);
@@ -3046,3 +3115,4 @@
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
diff --git a/liblog/tests/liblog_test_default.cpp b/liblog/tests/liblog_test_default.cpp
new file mode 100644
index 0000000..079ba07
--- /dev/null
+++ b/liblog/tests/liblog_test_default.cpp
@@ -0,0 +1,5 @@
+#ifdef __ANDROID__
+#include <log/log_frontend.h>
+#define TEST_PREFIX android_set_log_frontend(LOGGER_DEFAULT);
+#endif
+#include "liblog_test.cpp"
diff --git a/liblog/tests/liblog_test_local.cpp b/liblog/tests/liblog_test_local.cpp
new file mode 100644
index 0000000..5f7f645
--- /dev/null
+++ b/liblog/tests/liblog_test_local.cpp
@@ -0,0 +1,4 @@
+#include <log/log_frontend.h>
+#define liblog liblog_local
+#define TEST_PREFIX android_set_log_frontend(LOGGER_LOCAL);
+#include "liblog_test.cpp"