From 71002885325be3a0c4a0d09a6a6ad9b14531bdd7 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 8 Mar 2016 16:18:26 -0800 Subject: [PATCH] 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 --- liblog/Android.bp | 5 +- liblog/README | 7 +- liblog/config_read.c | 24 +- liblog/config_write.c | 27 +- liblog/include/log/log_frontend.h | 1 + liblog/local_logger.c | 556 +++++++++++++++++++++++++++ liblog/logger.h | 2 + liblog/logger_write.c | 39 +- liblog/tests/Android.mk | 3 +- liblog/tests/liblog_test.cpp | 146 +++++-- liblog/tests/liblog_test_default.cpp | 5 + liblog/tests/liblog_test_local.cpp | 4 + 12 files changed, 756 insertions(+), 63 deletions(-) create mode 100644 liblog/local_logger.c create mode 100644 liblog/tests/liblog_test_default.cpp create mode 100644 liblog/tests/liblog_test_local.cpp diff --git a/liblog/Android.bp b/liblog/Android.bp index cd6784559..310dbf4c3 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_host_sources = [ ] 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 922b5e3d5..40a39ad8b 100644 --- a/liblog/README +++ b/liblog/README @@ -168,9 +168,10 @@ DESCRIPTION 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 a4232f412..b9a281b30 100644 --- a/liblog/config_read.c +++ b/liblog/config_read.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "config_read.h" #include "logger.h" @@ -52,12 +54,24 @@ static void __android_log_add_transport( } 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 0aaaea6e4..583dcff3a 100644 --- a/liblog/config_write.c +++ b/liblog/config_write.c @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "config_write.h" #include "logger.h" @@ -52,17 +54,30 @@ static void __android_log_add_transport( } 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 c2f8b7ba8..952777971 100644 --- a/liblog/include/log/log_frontend.h +++ b/liblog/include/log/log_frontend.h @@ -21,6 +21,7 @@ extern "C" { #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 000000000..d504342ea --- /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 +#include +#include +#if !defined(__MINGW32__) +#include +#endif +#include +#include +#include +#include +#include + +#include /* template, no library dependency */ +#include +#include +#include +#include + +#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 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 471a52993..d94cd1467 100644 --- a/liblog/logger.h +++ b/liblog/logger.h @@ -196,6 +196,8 @@ LIBLOG_HIDDEN void __android_log_lock(); 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 bff77f8ef..e149e682f 100644 --- a/liblog/logger_write.c +++ b/liblog/logger_write.c @@ -29,6 +29,7 @@ #include #include +#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 @@ LIBLOG_ABI_PUBLIC void __android_log_close() } } + __android_log_config_write_close(); + #if defined(__ANDROID__) /* * Additional risk here somewhat mitigated by immediately unlock flushing @@ -639,12 +642,18 @@ static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr) /* 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 @@ LIBLOG_ABI_PUBLIC int android_set_log_frontend(int frontend_flag) __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 @@ LIBLOG_ABI_PUBLIC int android_get_log_frontend() __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 73434127a..cfea45202 100644 --- a/liblog/tests/Android.mk +++ b/liblog/tests/Android.mk @@ -55,7 +55,8 @@ test_c_flags := \ -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 346314c2d..bc0ea4c25 100644 --- a/liblog/tests/liblog_test.cpp +++ b/liblog/tests/liblog_test.cpp @@ -41,6 +41,28 @@ #include #include +#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 @@ TEST(liblog, __android_log_btwrite) { 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 @@ static bool tested__android_log_close; #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 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) { 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 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) { 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 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) { // 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 @@ TEST(liblog, android_set_log_frontend) { #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 @@ static inline uint32_t get4LE(const char* src) { #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 @@ TEST(liblog, __android_log_bswrite_and_print__multiple_newline) { } 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 @@ TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) { 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 @@ static void get_ticks(unsigned long long *uticks, unsigned long long *sticks) #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 @@ TEST(liblog, android_logger_list_read__cpu_signal) { #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 @@ static int start_thread() #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 @@ TEST(liblog, android_logger_list_read__cpu_thread) { 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 @@ when you depart from me, sorrow abides and happiness\n\ 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, max_payload) { } 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, __android_log_buf_print__maxtag) { } 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, too_big_payload) { } 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 @@ TEST(liblog, dual_reader) { #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 @@ TEST(liblog, filterRule) { 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 @@ TEST(liblog, is_loggable) { 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 @@ static testing::AssertionResult IsOk(bool ok, std::string &message) { 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 @@ TEST(liblog, enoent) { 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 @@ TEST(liblog, __security_buffer) { 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 @@ static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG, #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__typical) { } 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__data_too_l } 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__null_data) } 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 @@ TEST(liblog, __android_log_buf_write_and_print__max) { 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 @@ static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count #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__success) { } 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 @@ TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) { #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 @@ static int android_log_buffer_to_string(const char *msg, size_t len, 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 print_barrier() { } 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 @@ static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expect #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_int32) { } 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_int64) { } 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_list_int64) { } 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_simple_automagic_list) { } 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_list_empty) { } 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_complex_nested_list) { } 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_prefix) { } 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_7_level_suffix) { } 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) { } 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 @@ TEST(liblog, android_log_write_list_buffer) { 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 @@ TEST(liblog, __android_log_pmsg_file_read) { 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: ' 0 kB' static bool isZero(const std::string &content, std::string::size_type pos, @@ -2977,7 +3042,7 @@ static void event_log_tags_test_smap(pid_t pid) { 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 @@ TEST(liblog, event_log_tags) { 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 @@ TEST(liblog, __android_log_ratelimit) { } // 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 @@ TEST(liblog, android_lookupEventTagNum) { 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 000000000..079ba07ca --- /dev/null +++ b/liblog/tests/liblog_test_default.cpp @@ -0,0 +1,5 @@ +#ifdef __ANDROID__ +#include +#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 000000000..5f7f645fc --- /dev/null +++ b/liblog/tests/liblog_test_local.cpp @@ -0,0 +1,4 @@ +#include +#define liblog liblog_local +#define TEST_PREFIX android_set_log_frontend(LOGGER_LOCAL); +#include "liblog_test.cpp"