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"