diff options
Diffstat (limited to 'liblog/logd_write.c')
-rw-r--r-- | liblog/logd_write.c | 304 |
1 files changed, 249 insertions, 55 deletions
diff --git a/liblog/logd_write.c b/liblog/logd_write.c index 5766f8c..3171c78 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -13,41 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <time.h> -#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #ifdef HAVE_PTHREADS #include <pthread.h> #endif -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> #include <stdarg.h> -#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> +#include <sys/types.h> +#if (FAKE_LOG_DEVICE == 0) +#include <sys/socket.h> +#include <sys/un.h> +#endif +#include <time.h> +#include <unistd.h> -#include <log/logger.h> #include <log/logd.h> -#include <log/log.h> - -#define LOGGER_LOG_MAIN "log/main" -#define LOGGER_LOG_RADIO "log/radio" -#define LOGGER_LOG_EVENTS "log/events" -#define LOGGER_LOG_SYSTEM "log/system" +#include <log/logger.h> +#include <log/log_read.h> +#include <private/android_filesystem_config.h> #define LOG_BUF_SIZE 1024 #if FAKE_LOG_DEVICE -// This will be defined when building for the host. +/* This will be defined when building for the host. */ #include "fake_log_device.h" -#define log_open(pathname, flags) fakeLogOpen(pathname, flags) -#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) -#define log_close(filedes) fakeLogClose(filedes) -#else -#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC) -#define log_writev(filedes, vector, count) writev(filedes, vector, count) -#define log_close(filedes) close(filedes) #endif static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); @@ -56,13 +49,20 @@ static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_ static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; #endif -#define UNUSED __attribute__((__unused__)) +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif -static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 }; +#if FAKE_LOG_DEVICE +#define WEAK __attribute__((weak)) +static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 }; +#else +static int logd_fd = -1; +#endif /* * This is used by the C++ code to decide if it should write logs through - * the C code. Basically, if /dev/log/... is available, we're running in + * the C code. Basically, if /dev/socket/logd is available, we're running in * the simulator rather than a desktop tool and want to use the device. */ static enum { @@ -71,7 +71,7 @@ static enum { int __android_log_dev_available(void) { if (g_log_status == kLogUninitialized) { - if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0) + if (access("/dev/socket/logdw", W_OK) == 0) g_log_status = kLogAvailable; else g_log_status = kLogNotAvailable; @@ -80,30 +80,205 @@ int __android_log_dev_available(void) return (g_log_status == kLogAvailable); } -static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED, - size_t nr UNUSED) +#if !FAKE_LOG_DEVICE +/* give up, resources too limited */ +static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, + size_t nr __unused) { return -1; } +#endif + +/* log_init_lock assumed */ +static int __write_to_log_initialize() +{ + int i, ret = 0; + +#if FAKE_LOG_DEVICE + for (i = 0; i < LOG_ID_MAX; i++) { + char buf[sizeof("/dev/log_system")]; + snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i)); + log_fds[i] = fakeLogOpen(buf, O_WRONLY); + } +#else + if (logd_fd >= 0) { + i = logd_fd; + logd_fd = -1; + close(i); + } + + i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (i < 0) { + ret = -errno; + write_to_log = __write_to_log_null; + } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) { + ret = -errno; + close(i); + i = -1; + write_to_log = __write_to_log_null; + } else { + struct sockaddr_un un; + memset(&un, 0, sizeof(struct sockaddr_un)); + un.sun_family = AF_UNIX; + strcpy(un.sun_path, "/dev/socket/logdw"); + + if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) { + ret = -errno; + close(i); + i = -1; + } + } + logd_fd = i; +#endif + + return ret; +} static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) { ssize_t ret; +#if FAKE_LOG_DEVICE int log_fd; if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { log_fd = log_fds[(int)log_id]; } else { - return EBADF; + return -EBADF; } - do { - ret = log_writev(log_fd, vec, nr); - } while (ret < 0 && errno == EINTR); + ret = fakeLogWritev(log_fd, vec, nr); + if (ret < 0) { + ret = -errno; + } + } while (ret == -EINTR); +#else + static const unsigned header_length = 3; + struct iovec newVec[nr + header_length]; + typeof_log_id_t log_id_buf; + uint16_t tid; + struct timespec ts; + log_time realtime_ts; + size_t i, payload_size; + static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */ + + if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */ + last_uid = getuid(); + } + if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */ + /* + * ignore log messages we send to ourself (logd). + * Such log messages are often generated by libraries we depend on + * which use standard Android logging. + */ + return 0; + } + + if (logd_fd < 0) { + return -EBADF; + } + + /* + * struct { + * // what we provide + * typeof_log_id_t log_id; + * u16 tid; + * log_time realtime; + * // caller provides + * union { + * struct { + * char prio; + * char payload[]; + * } string; + * struct { + * uint32_t tag + * char payload[]; + * } binary; + * }; + * }; + */ + + clock_gettime(CLOCK_REALTIME, &ts); + realtime_ts.tv_sec = ts.tv_sec; + realtime_ts.tv_nsec = ts.tv_nsec; + + log_id_buf = log_id; + tid = gettid(); + + newVec[0].iov_base = (unsigned char *) &log_id_buf; + newVec[0].iov_len = sizeof_log_id_t; + newVec[1].iov_base = (unsigned char *) &tid; + newVec[1].iov_len = sizeof(tid); + newVec[2].iov_base = (unsigned char *) &realtime_ts; + newVec[2].iov_len = sizeof(log_time); + + for (payload_size = 0, i = header_length; i < nr + header_length; i++) { + newVec[i].iov_base = vec[i - header_length].iov_base; + payload_size += newVec[i].iov_len = vec[i - header_length].iov_len; + + if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) { + newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD; + if (newVec[i].iov_len) { + ++i; + } + break; + } + } + + /* + * The write below could be lost, but will never block. + * + * ENOTCONN occurs if logd dies. + * EAGAIN occurs if logd is overloaded. + */ + ret = writev(logd_fd, newVec, i); + if (ret < 0) { + ret = -errno; + if (ret == -ENOTCONN) { +#ifdef HAVE_PTHREADS + pthread_mutex_lock(&log_init_lock); +#endif + ret = __write_to_log_initialize(); +#ifdef HAVE_PTHREADS + pthread_mutex_unlock(&log_init_lock); +#endif + + if (ret < 0) { + return ret; + } + + ret = writev(logd_fd, newVec, nr + header_length); + if (ret < 0) { + ret = -errno; + } + } + } + + if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) { + ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time); + } +#endif return ret; } +#if FAKE_LOG_DEVICE +static const char *LOG_NAME[LOG_ID_MAX] = { + [LOG_ID_MAIN] = "main", + [LOG_ID_RADIO] = "radio", + [LOG_ID_EVENTS] = "events", + [LOG_ID_SYSTEM] = "system", + [LOG_ID_CRASH] = "crash" +}; + +const WEAK char *android_log_id_to_name(log_id_t log_id) +{ + if (log_id >= LOG_ID_MAX) { + log_id = LOG_ID_MAIN; + } + return LOG_NAME[log_id]; +} +#endif + static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) { #ifdef HAVE_PTHREADS @@ -111,27 +286,17 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) #endif if (write_to_log == __write_to_log_init) { - log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); - log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); - log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); - log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); - - write_to_log = __write_to_log_kernel; + int ret; - if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || - log_fds[LOG_ID_EVENTS] < 0) { - log_close(log_fds[LOG_ID_MAIN]); - log_close(log_fds[LOG_ID_RADIO]); - log_close(log_fds[LOG_ID_EVENTS]); - log_fds[LOG_ID_MAIN] = -1; - log_fds[LOG_ID_RADIO] = -1; - log_fds[LOG_ID_EVENTS] = -1; - write_to_log = __write_to_log_null; + ret = __write_to_log_initialize(); + if (ret < 0) { +#ifdef HAVE_PTHREADS + pthread_mutex_unlock(&log_init_lock); +#endif + return ret; } - if (log_fds[LOG_ID_SYSTEM] < 0) { - log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; - } + write_to_log = __write_to_log_kernel; } #ifdef HAVE_PTHREADS @@ -161,11 +326,18 @@ int __android_log_write(int prio, const char *tag, const char *msg) !strcmp(tag, "PHONE") || !strcmp(tag, "SMS")) { log_id = LOG_ID_RADIO; - // Inform third party apps/ril/radio.. to use Rlog or RLOG + /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); tag = tmp_tag; } +#if __BIONIC__ + if (prio == ANDROID_LOG_FATAL) { + extern void __android_set_abort_message(const char*); + __android_set_abort_message(msg); + } +#endif + vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; @@ -196,7 +368,7 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms !strcmp(tag, "PHONE") || !strcmp(tag, "SMS"))) { bufID = LOG_ID_RADIO; - // Inform third party apps/ril/radio.. to use Rlog or RLOG + /* Inform third party apps/ril/radio.. to use Rlog or RLOG */ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag); tag = tmp_tag; } @@ -266,8 +438,8 @@ void __android_log_assert(const char *cond, const char *tag, } __android_log_write(ANDROID_LOG_FATAL, tag, buf); - __builtin_trap(); /* trap so we have a chance to debug the situation */ + /* NOTREACHED */ } int __android_log_bwrite(int32_t tag, const void *payload, size_t len) @@ -288,7 +460,7 @@ int __android_log_bwrite(int32_t tag, const void *payload, size_t len) * handy if we just want to dump an integer into the log. */ int __android_log_btwrite(int32_t tag, char type, const void *payload, - size_t len) + size_t len) { struct iovec vec[3]; @@ -301,3 +473,25 @@ int __android_log_btwrite(int32_t tag, char type, const void *payload, return write_to_log(LOG_ID_EVENTS, vec, 3); } + +/* + * Like __android_log_bwrite, but used for writing strings to the + * event log. + */ +int __android_log_bswrite(int32_t tag, const char *payload) +{ + struct iovec vec[4]; + char type = EVENT_TYPE_STRING; + uint32_t len = strlen(payload); + + vec[0].iov_base = &tag; + vec[0].iov_len = sizeof(tag); + vec[1].iov_base = &type; + vec[1].iov_len = sizeof(type); + vec[2].iov_base = &len; + vec[2].iov_len = sizeof(len); + vec[3].iov_base = (void*)payload; + vec[3].iov_len = len; + + return write_to_log(LOG_ID_EVENTS, vec, 4); +} |