From c619e49f74eaccb6184cd87247c2ef999942444d Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Tue, 10 Dec 2019 13:32:31 -0800 Subject: [PATCH] liblog: simplify fake_log_device This still fakes the long removed /dev/log devices, whereas it only needs to print to stderr, so simplify that code. Use std::mutex now that it is C++ to easy portability concerns. Use the proper liblog headers for formatting information instead of hardcoding a copy. Test: liblog-host unit test Change-Id: I310a6e7ad939960300eafa729cbfc535c5ced445 --- liblog/Android.bp | 1 - liblog/fake_log_device.cpp | 224 +++++++++---------------------------- liblog/fake_writer.cpp | 105 ----------------- 3 files changed, 55 insertions(+), 275 deletions(-) delete mode 100644 liblog/fake_writer.cpp diff --git a/liblog/Android.bp b/liblog/Android.bp index 91bd52c66..656d4dd9e 100644 --- a/liblog/Android.bp +++ b/liblog/Android.bp @@ -25,7 +25,6 @@ liblog_sources = [ ] liblog_host_sources = [ "fake_log_device.cpp", - "fake_writer.cpp", ] liblog_target_sources = [ "event_tag_map.cpp", diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp index 601bb5126..4143fa61d 100644 --- a/liblog/fake_log_device.cpp +++ b/liblog/fake_log_device.cpp @@ -23,18 +23,20 @@ #include #include #include -#if !defined(_WIN32) -#include -#endif #include #include #include #include #include +#include + #include +#include +#include #include "log_portability.h" +#include "logger.h" #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */ @@ -46,37 +48,26 @@ #define TRACE(...) ((void)0) #endif -/* from the long-dead utils/Log.cpp */ -typedef enum { - FORMAT_OFF = 0, - FORMAT_BRIEF, - FORMAT_PROCESS, - FORMAT_TAG, - FORMAT_THREAD, - FORMAT_RAW, - FORMAT_TIME, - FORMAT_THREADTIME, - FORMAT_LONG -} LogFormat; +static int FakeAvailable(log_id_t); +static int FakeOpen(); +static void FakeClose(); +static int FakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr); + +struct android_log_transport_write fakeLoggerWrite = { + .name = "fake", + .logMask = 0, + .available = FakeAvailable, + .open = FakeOpen, + .close = FakeClose, + .write = FakeWrite, +}; -/* - * Log driver state. - */ typedef struct LogState { - /* the fake fd that's seen by the user */ - int fakeFd; - - /* a printable name for this fake device */ - char debugName[sizeof("/dev/log/security")]; - - /* nonzero if this is a binary log */ - int isBinary; - /* global minimum priority */ - int globalMinPriority; + int global_min_priority; /* output format */ - LogFormat outputFormat; + AndroidLogPrintFormat output_format; /* tags and priorities */ struct { @@ -85,81 +76,18 @@ typedef struct LogState { } tagSet[kTagSetSize]; } LogState; -#if !defined(_WIN32) /* * Locking. Since we're emulating a device, we need to be prepared * to have multiple callers at the same time. This lock is used * to both protect the fd list and to prevent LogStates from being * freed out from under a user. */ -static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER; +std::mutex mutex; -static void lock() { - /* - * If we trigger a signal handler in the middle of locked activity and the - * signal handler logs a message, we could get into a deadlock state. - */ - pthread_mutex_lock(&fakeLogDeviceLock); -} +static LogState log_state; -static void unlock() { - pthread_mutex_unlock(&fakeLogDeviceLock); -} - -#else // !defined(_WIN32) - -#define lock() ((void)0) -#define unlock() ((void)0) - -#endif // !defined(_WIN32) - -/* - * File descriptor management. - */ -#define FAKE_FD_BASE 10000 -#define MAX_OPEN_LOGS 8 -static LogState openLogTable[MAX_OPEN_LOGS]; - -/* - * Allocate an fd and associate a new LogState with it. - * The fd is available via the fakeFd field of the return value. - */ -static LogState* createLogState() { - size_t i; - - for (i = 0; i < (sizeof(openLogTable) / sizeof(openLogTable[0])); i++) { - if (openLogTable[i].fakeFd == 0) { - openLogTable[i].fakeFd = FAKE_FD_BASE + i; - return &openLogTable[i]; - } - } - return NULL; -} - -/* - * Translate an fd to a LogState. - */ -static LogState* fdToLogState(int fd) { - if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) { - return &openLogTable[fd - FAKE_FD_BASE]; - } - return NULL; -} - -/* - * Unregister the fake fd and free the memory it pointed to. - */ -static void deleteFakeFd(int fd) { - LogState* ls; - - lock(); - - ls = fdToLogState(fd); - if (ls != NULL) { - memset(&openLogTable[fd - FAKE_FD_BASE], 0, sizeof(openLogTable[0])); - } - - unlock(); +static int FakeAvailable(log_id_t) { + return 0; } /* @@ -175,20 +103,11 @@ static void deleteFakeFd(int fd) { * We also want to check ANDROID_PRINTF_LOG to determine how the output * will look. */ -static void configureInitialState(const char* pathName, LogState* logState) { - static const int kDevLogLen = sizeof("/dev/log/") - 1; - - strncpy(logState->debugName, pathName, sizeof(logState->debugName)); - logState->debugName[sizeof(logState->debugName) - 1] = '\0'; - - /* identify binary logs */ - if (!strcmp(pathName + kDevLogLen, "events") || !strcmp(pathName + kDevLogLen, "security") || - !strcmp(pathName + kDevLogLen, "stats")) { - logState->isBinary = 1; - } +int FakeOpen() { + std::lock_guard guard{mutex}; /* global min priority defaults to "info" level */ - logState->globalMinPriority = ANDROID_LOG_INFO; + log_state.global_min_priority = ANDROID_LOG_INFO; /* * This is based on the the long-dead utils/Log.cpp code. @@ -210,7 +129,7 @@ static void configureInitialState(const char* pathName, LogState* logState) { } if (i == kMaxTagLen) { TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen - 1); - return; + return 0; } tagName[i] = '\0'; @@ -261,16 +180,16 @@ static void configureInitialState(const char* pathName, LogState* logState) { if (*tags != '\0' && !isspace(*tags)) { TRACE("ERROR: garbage in tag env; expected whitespace\n"); TRACE(" env='%s'\n", tags); - return; + return 0; } } if (tagName[0] == 0) { - logState->globalMinPriority = minPrio; + log_state.global_min_priority = minPrio; TRACE("+++ global min prio %d\n", logState->globalMinPriority); } else { - logState->tagSet[entry].minPriority = minPrio; - strcpy(logState->tagSet[entry].tag, tagName); + log_state.tagSet[entry].minPriority = minPrio; + strcpy(log_state.tagSet[entry].tag, tagName); TRACE("+++ entry %d: %s:%d\n", entry, logState->tagSet[entry].tag, logState->tagSet[entry].minPriority); entry++; @@ -282,7 +201,7 @@ static void configureInitialState(const char* pathName, LogState* logState) { * Taken from the long-dead utils/Log.cpp */ const char* fstr = getenv("ANDROID_PRINTF_LOG"); - LogFormat format; + AndroidLogPrintFormat format; if (fstr == NULL) { format = FORMAT_BRIEF; } else { @@ -301,10 +220,11 @@ static void configureInitialState(const char* pathName, LogState* logState) { else if (strcmp(fstr, "long") == 0) format = FORMAT_PROCESS; else - format = (LogFormat)atoi(fstr); // really?! + format = (AndroidLogPrintFormat)atoi(fstr); // really?! } - logState->outputFormat = format; + log_state.output_format = format; + return 0; } /* @@ -349,7 +269,7 @@ static ssize_t fake_writev(int fd, const struct iovec* iov, int iovcnt) { * * Log format parsing taken from the long-dead utils/Log.cpp. */ -static void showLog(LogState* state, int logPrio, const char* tag, const char* msg) { +static void ShowLog(int logPrio, const char* tag, const char* msg) { #if !defined(_WIN32) struct tm tmBuf; #endif @@ -392,7 +312,7 @@ static void showLog(LogState* state, int logPrio, const char* tag, const char* m */ size_t prefixLen, suffixLen; - switch (state->outputFormat) { + switch (log_state.output_format) { case FORMAT_TAG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s: ", priChar, tag); strcpy(suffixBuf, "\n"); @@ -549,35 +469,24 @@ static void showLog(LogState* state, int logPrio, const char* tag, const char* m * tag (N bytes -- null-terminated ASCII string) * message (N bytes -- null-terminated ASCII string) */ -ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) { - LogState* state; - +static int FakeWrite(log_id_t log_id, struct timespec*, struct iovec* vector, size_t count) { /* Make sure that no-one frees the LogState while we're using it. * Also guarantees that only one thread is in showLog() at a given * time (if it matters). */ - lock(); + std::lock_guard guard{mutex}; - state = fdToLogState(fd); - if (state == NULL) { - errno = EBADF; - unlock(); - return -1; - } - - if (state->isBinary) { - TRACE("%s: ignoring binary log\n", state->debugName); - unlock(); + if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY) { + TRACE("%s: ignoring binary log\n", android_log_id_to_name(log_id)); int len = 0; - for (int i = 0; i < count; ++i) { + for (size_t i = 0; i < count; ++i) { len += vector[i].iov_len; } return len; } if (count != 3) { - TRACE("%s: writevLog with count=%d not expected\n", state->debugName, count); - unlock(); + TRACE("%s: writevLog with count=%d not expected\n", android_log_id_to_name(log_id), count); return -1; } @@ -587,32 +496,30 @@ ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) { const char* msg = (const char*)vector[2].iov_base; /* see if this log tag is configured */ - int i; - int minPrio = state->globalMinPriority; - for (i = 0; i < kTagSetSize; i++) { - if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN) + int minPrio = log_state.global_min_priority; + for (size_t i = 0; i < kTagSetSize; i++) { + if (log_state.tagSet[i].minPriority == ANDROID_LOG_UNKNOWN) break; /* reached end of configured values */ - if (strcmp(state->tagSet[i].tag, tag) == 0) { - minPrio = state->tagSet[i].minPriority; + if (strcmp(log_state.tagSet[i].tag, tag) == 0) { + minPrio = log_state.tagSet[i].minPriority; break; } } if (logPrio >= minPrio) { - showLog(state, logPrio, tag, msg); + ShowLog(logPrio, tag, msg); } - unlock(); int len = 0; - for (i = 0; i < count; ++i) { + for (size_t i = 0; i < count; ++i) { len += vector[i].iov_len; } return len; } /* - * Free up our state and close the fake descriptor. + * Reset out state. * * The logger API has no means or need to 'stop' or 'close' using the logs, * and as such, there is no way for that 'stop' or 'close' to translate into @@ -624,31 +531,10 @@ ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count) { * call is in the exit handler. Logging can continue in the exit handler to * help debug HOST tools ... */ -int fakeLogClose(int fd) { - deleteFakeFd(fd); - return 0; -} +static void FakeClose() { + std::lock_guard guard{mutex}; -/* - * Open a log output device and return a fake fd. - */ -int fakeLogOpen(const char* pathName) { - LogState* logState; - int fd = -1; - - lock(); - - logState = createLogState(); - if (logState != NULL) { - configureInitialState(pathName, logState); - fd = logState->fakeFd; - } else { - errno = ENFILE; - } - - unlock(); - - return fd; + memset(&log_state, 0, sizeof(log_state)); } int __android_log_is_loggable(int prio, const char*, int def) { diff --git a/liblog/fake_writer.cpp b/liblog/fake_writer.cpp deleted file mode 100644 index f1ddff17b..000000000 --- a/liblog/fake_writer.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2007-2016 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 - -#include - -#include "fake_log_device.h" -#include "log_portability.h" -#include "logger.h" - -static int fakeAvailable(log_id_t); -static int fakeOpen(); -static void fakeClose(); -static int fakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr); - -static int logFds[(int)LOG_ID_MAX] = {-1, -1, -1, -1, -1, -1}; - -struct android_log_transport_write fakeLoggerWrite = { - .name = "fake", - .logMask = 0, - .context.priv = &logFds, - .available = fakeAvailable, - .open = fakeOpen, - .close = fakeClose, - .write = fakeWrite, -}; - -static int fakeAvailable(log_id_t) { - return 0; -} - -static int fakeOpen() { - int i; - - for (i = 0; i < LOG_ID_MAX; i++) { - /* - * Known maximum size string, plus an 8 character margin to deal with - * possible independent changes to android_log_id_to_name(). - */ - char buf[sizeof("/dev/log_security") + 8]; - if (logFds[i] >= 0) { - continue; - } - snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(static_cast(i))); - logFds[i] = fakeLogOpen(buf); - if (logFds[i] < 0) { - fprintf(stderr, "fakeLogOpen(%s) failed\n", buf); - } - } - return 0; -} - -static void fakeClose() { - int i; - - for (i = 0; i < LOG_ID_MAX; i++) { - fakeLogClose(logFds[i]); - logFds[i] = -1; - } -} - -static int fakeWrite(log_id_t log_id, struct timespec*, struct iovec* vec, size_t nr) { - ssize_t ret; - size_t i; - int logFd, len; - - if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) { - 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; - } - - logFd = logFds[(int)log_id]; - ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr)); - if (ret < 0) { - ret = -errno; - } else if (ret > len) { - ret = len; - } - - return ret; -}