summaryrefslogtreecommitdiffstats
path: root/liblog
diff options
context:
space:
mode:
Diffstat (limited to 'liblog')
-rw-r--r--liblog/Android.mk38
-rw-r--r--liblog/README46
-rw-r--r--liblog/event.logtags36
-rw-r--r--liblog/fake_log_device.c22
-rw-r--r--liblog/log_is_loggable.c61
-rw-r--r--liblog/log_read.c193
-rw-r--r--liblog/log_read_kern.c22
-rw-r--r--liblog/log_time.cpp26
-rw-r--r--liblog/logd_write.c239
-rw-r--r--liblog/logd_write_kern.c63
-rw-r--r--liblog/logprint.c121
-rw-r--r--liblog/tests/Android.mk11
-rw-r--r--liblog/tests/benchmark_main.cpp1
-rw-r--r--liblog/tests/libc_test.cpp4
-rw-r--r--liblog/tests/liblog_benchmark.cpp18
-rw-r--r--liblog/tests/liblog_test.cpp14
-rw-r--r--liblog/uio.c4
17 files changed, 634 insertions, 285 deletions
diff --git a/liblog/Android.mk b/liblog/Android.mk
index a4e5f5e..70aff83 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,6 +16,14 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
+# This is what we want to do:
+# liblog_cflags := $(shell \
+# sed -n \
+# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
+# $(LOCAL_PATH)/event.logtags)
+# so make sure we do not regret hard-coding it as follows:
+liblog_cflags := -DLIBLOG_LOG_TAG=1005
+
ifneq ($(TARGET_USES_LOGD),false)
liblog_sources := logd_write.c
else
@@ -25,28 +33,20 @@ endif
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
# which are also hard or even impossible to port to native Win32
-WITH_MINGW :=
-ifeq ($(HOST_OS),windows)
- ifeq ($(strip $(USE_CYGWIN)),)
- WITH_MINGW := true
- endif
-endif
-# USE_MINGW is defined when we build against Mingw on Linux
-ifneq ($(strip $(USE_MINGW)),)
- WITH_MINGW := true
-endif
-ifndef WITH_MINGW
+ifeq ($(strip $(USE_MINGW)),)
liblog_sources += \
- logprint.c \
event_tag_map.c
else
liblog_sources += \
uio.c
endif
-liblog_host_sources := $(liblog_sources) fake_log_device.c
-liblog_target_sources := $(liblog_sources) log_time.cpp
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
+liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c
+ifeq ($(strip $(USE_MINGW)),)
+liblog_target_sources += logprint.c
+endif
ifneq ($(TARGET_USES_LOGD),false)
liblog_target_sources += log_read.c
else
@@ -57,7 +57,7 @@ endif
# ========================================================
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -76,13 +76,17 @@ include $(BUILD_HOST_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
+
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+
include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index d7472e4..f29ac04 100644
--- a/liblog/README
+++ b/liblog/README
@@ -111,24 +111,56 @@ DESCRIPTION
ger_list_alloc, calling in turn the android_logger_open for each log
id. Each entry can be retrieved with android_logger_list_read. The
log(s) can be closed with android_logger_list_free. The logs should be
- opened with an O_RDONLY mode. O_NDELAY mode will report when the log
- reading is done with an EAGAIN error return code, otherwise the
- android_logger_list_read call will block for new entries.
+ opened with an ANDROID_LOG_RDONLY mode. ANDROID_LOG_NONBLOCK mode
+ will report when the log reading is done with an EAGAIN error return
+ code, otherwise the android_logger_list_read call will block for new
+ entries.
+
+ The ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to
+ switch from the active logs to the persistent logs from before the last
+ reboot.
The value returned by android_logger_open can be used as a parameter to
the android_logger_clear function to empty the sub-log. It is recom‐
- mended to only open log O_WRONLY.
+ mended to only open log ANDROID_LOG_WRONLY in that case.
The value returned by android_logger_open can be used as a parameter to
the android_logger_get_log_(size|readable_size|version) to retrieve the
sub-log maximum size, readable size and log buffer format protocol ver‐
sion respectively. android_logger_get_id returns the id that was used
- when opening the sub-log. It is recommended to open the log O_RDONLY
- in these cases.
+ when opening the sub-log. It is recommended to open the log
+ ANDROID_LOG_RDONLY in these cases.
+
+ERRORS
+ If messages fail, a negative error code will be returned to the caller.
+
+ The -ENOTCONN return code indicates that the logger daemon is stopped.
+
+ The -EBADF return code indicates that the log access point can not be
+ opened, or the log buffer id is out of range.
+
+ For the -EAGAIN return code, this means that the logging message was
+ temporarily backed-up either because of Denial Of Service (DOS) logging
+ pressure from some chatty application or service in the Android system,
+ or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen.
+ To aid in diagnosing the occurence of this, a binary event from liblog
+ will be sent to the log daemon once a new message can get through
+ indicating how many messages were dropped as a result. Please take
+ action to resolve the structural problems at the source.
+
+ It is generally not advised for the caller to retry the -EAGAIN return
+ code as this will only make the problem(s) worse and cause your
+ application to temporarily drop to the logger daemon priority, BATCH
+ scheduling policy and background task cgroup. If you require a group of
+ messages to be passed atomically, merge them into one message with
+ embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD.
+
+ Other return codes from writing operation can be returned. Since the
+ library retries on EINTR, -EINTR should never be returned.
SEE ALSO
syslogd(8)
- 17 Dec 2013 LIBLOG(3)
+ 24 Jan 2014 LIBLOG(3)
diff --git a/liblog/event.logtags b/liblog/event.logtags
new file mode 100644
index 0000000..72ecab1
--- /dev/null
+++ b/liblog/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1005 liblog (dropped|1)
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 136792d..8a8ece2 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -29,7 +29,7 @@
#include <log/logd.h>
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
#include <pthread.h>
#endif
@@ -88,7 +88,7 @@ typedef struct LogState {
} LogState;
-#ifdef HAVE_PTHREADS
+#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
@@ -106,10 +106,10 @@ static void unlock()
{
pthread_mutex_unlock(&fakeLogDeviceLock);
}
-#else // !HAVE_PTHREADS
+#else // !defined(_WIN32)
#define lock() ((void)0)
#define unlock() ((void)0)
-#endif // !HAVE_PTHREADS
+#endif // !defined(_WIN32)
/*
@@ -320,9 +320,9 @@ static const char* getPriorityString(int priority)
return priorityStrings[idx];
}
-#ifndef HAVE_WRITEV
+#if defined(_WIN32)
/*
- * Some platforms like WIN32 do not have writev().
+ * WIN32 does not have writev().
* Make up something to replace it.
*/
static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
@@ -352,7 +352,7 @@ static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
static void showLog(LogState *state,
int logPrio, const char* tag, const char* msg)
{
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
struct tm tmBuf;
#endif
struct tm* ptm;
@@ -377,7 +377,7 @@ static void showLog(LogState *state,
* in the time stamp. Don't use forward slashes, parenthesis,
* brackets, asterisks, or other special chars here.
*/
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
ptm = localtime_r(&when, &tmBuf);
#else
ptm = localtime(&when);
@@ -689,3 +689,9 @@ ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count)
/* Assume that open() was called first. */
return redirectWritev(fd, vector, count);
}
+
+int __android_log_is_loggable(int prio, const char *tag __unused, int def)
+{
+ int logLevel = def;
+ return logLevel >= 0 && prio >= logLevel;
+}
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
new file mode 100644
index 0000000..2e09192
--- /dev/null
+++ b/liblog/log_is_loggable.c
@@ -0,0 +1,61 @@
+/*
+** Copyright 2014, 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 <ctype.h>
+#include <string.h>
+#include <sys/system_properties.h>
+
+#include <android/log.h>
+
+static int __android_log_level(const char *tag, int def)
+{
+ char buf[PROP_VALUE_MAX];
+
+ if (!tag || !*tag) {
+ return def;
+ }
+ {
+ static const char log_namespace[] = "persist.log.tag.";
+ char key[sizeof(log_namespace) + strlen(tag)];
+
+ strcpy(key, log_namespace);
+ strcpy(key + sizeof(log_namespace) - 1, tag);
+
+ if (__system_property_get(key + 8, buf) <= 0) {
+ buf[0] = '\0';
+ }
+ if (!buf[0] && __system_property_get(key, buf) <= 0) {
+ buf[0] = '\0';
+ }
+ }
+ switch (toupper(buf[0])) {
+ case 'V': return ANDROID_LOG_VERBOSE;
+ case 'D': return ANDROID_LOG_DEBUG;
+ case 'I': return ANDROID_LOG_INFO;
+ case 'W': return ANDROID_LOG_WARN;
+ case 'E': return ANDROID_LOG_ERROR;
+ case 'F': /* FALLTHRU */ /* Not officially supported */
+ case 'A': return ANDROID_LOG_FATAL;
+ case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+ }
+ return def;
+}
+
+int __android_log_is_loggable(int prio, const char *tag, int def)
+{
+ int logLevel = __android_log_level(tag, def);
+ return logLevel >= 0 && prio >= logLevel;
+}
diff --git a/liblog/log_read.c b/liblog/log_read.c
index ca5a1a7..5364e4f 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <poll.h>
#include <signal.h>
+#include <stdbool.h>
#include <stddef.h>
#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
#include <stdlib.h>
@@ -30,11 +31,17 @@
#include <cutils/sockets.h>
#include <log/log.h>
#include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
/* branchless on many architectures. */
#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+#if (defined(USE_MINGW) || defined(HAVE_WINSOCK))
+#define WEAK static
+#else
#define WEAK __attribute__((weak))
+#endif
#ifndef __unused
#define __unused __attribute__((unused))
#endif
@@ -72,7 +79,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
switch (namespaceId) {
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+#if defined(__linux__)
namelen = strlen(name);
/* Test with length +1 for the *initial* '\0'. */
@@ -87,7 +94,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
p_addr->sun_path[0] = 0;
memcpy(p_addr->sun_path + 1, name, namelen);
-#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#else
/* this OS doesn't have the Linux abstract namespace */
namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
@@ -99,7 +106,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
strcat(p_addr->sun_path, name);
-#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#endif
break;
case ANDROID_SOCKET_NAMESPACE_RESERVED:
@@ -353,10 +360,64 @@ static int check_log_success(char *buf, ssize_t ret)
return 0;
}
+/* Determine the credentials of the caller */
+static bool uid_has_log_permission(uid_t uid)
+{
+ return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+}
+
+static uid_t get_best_effective_uid()
+{
+ uid_t euid;
+ uid_t uid;
+ gid_t gid;
+ ssize_t i;
+ static uid_t last_uid = (uid_t) -1;
+
+ if (last_uid != (uid_t) -1) {
+ return last_uid;
+ }
+ uid = getuid();
+ if (uid_has_log_permission(uid)) {
+ return last_uid = uid;
+ }
+ euid = geteuid();
+ if (uid_has_log_permission(euid)) {
+ return last_uid = euid;
+ }
+ gid = getgid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ gid = getegid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ i = getgroups((size_t) 0, NULL);
+ if (i > 0) {
+ gid_t list[i];
+
+ getgroups(i, list);
+ while (--i >= 0) {
+ if (uid_has_log_permission(list[i])) {
+ return last_uid = list[i];
+ }
+ }
+ }
+ return last_uid = uid;
+}
+
int android_logger_clear(struct logger *logger)
{
char buf[512];
+ if (logger->top->mode & ANDROID_LOG_PSTORE) {
+ if (uid_has_log_permission(get_best_effective_uid())) {
+ return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+ }
+ errno = EPERM;
+ return -1;
+ }
return check_log_success(buf,
send_log_msg(logger, "clear %d", buf, sizeof(buf)));
}
@@ -560,6 +621,116 @@ struct logger_list *android_logger_list_open(log_id_t id,
return logger_list;
}
+static int android_logger_list_read_pstore(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ ssize_t ret;
+ off_t current, next;
+ uid_t uid;
+ struct logger *logger;
+ struct __attribute__((__packed__)) {
+ android_pmsg_log_header_t p;
+ android_log_header_t l;
+ } buf;
+ static uint8_t preread_count;
+
+ memset(log_msg, 0, sizeof(*log_msg));
+
+ if (logger_list->sock < 0) {
+ int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+
+ if (fd < 0) {
+ return -errno;
+ }
+ logger_list->sock = fd;
+ preread_count = 0;
+ }
+
+ ret = 0;
+ while(1) {
+ if (preread_count < sizeof(buf)) {
+ ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+ &buf.p.magic + preread_count,
+ sizeof(buf) - preread_count));
+ if (ret < 0) {
+ return -errno;
+ }
+ preread_count += ret;
+ }
+ if (preread_count != sizeof(buf)) {
+ return preread_count ? -EIO : -EAGAIN;
+ }
+ if ((buf.p.magic != LOGGER_MAGIC)
+ || (buf.p.len <= sizeof(buf))
+ || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
+ || (buf.l.id >= LOG_ID_MAX)
+ || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+ do {
+ memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+ } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+ continue;
+ }
+ preread_count = 0;
+
+ logger_for_each(logger, logger_list) {
+ if (buf.l.id != logger->id) {
+ continue;
+ }
+
+ if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
+ && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
+ || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
+ && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
+ break;
+ }
+
+ if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
+ break;
+ }
+
+ uid = get_best_effective_uid();
+ if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) {
+ break;
+ }
+
+ ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+ log_msg->entry_v3.msg,
+ buf.p.len - sizeof(buf)));
+ if (ret < 0) {
+ return -errno;
+ }
+ if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
+ }
+
+ log_msg->entry_v3.len = buf.p.len - sizeof(buf);
+ log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+ log_msg->entry_v3.pid = buf.p.pid;
+ log_msg->entry_v3.tid = buf.l.tid;
+ log_msg->entry_v3.sec = buf.l.realtime.tv_sec;
+ log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec;
+ log_msg->entry_v3.lid = buf.l.id;
+
+ return ret;
+ }
+
+ current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+ (off_t)0, SEEK_CUR));
+ if (current < 0) {
+ return -errno;
+ }
+ next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+ (off_t)(buf.p.len - sizeof(buf)),
+ SEEK_CUR));
+ if (next < 0) {
+ return -errno;
+ }
+ if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
+ }
+ }
+}
+
static void caught_signal(int signum __unused)
{
}
@@ -578,7 +749,11 @@ int android_logger_list_read(struct logger_list *logger_list,
return -EINVAL;
}
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_PSTORE) {
+ return android_logger_list_read_pstore(logger_list, log_msg);
+ }
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
@@ -598,7 +773,7 @@ int android_logger_list_read(struct logger_list *logger_list,
}
strcpy(buffer,
- (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+ (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
cp = buffer + strlen(buffer);
strcpy(cp, " lids");
@@ -636,14 +811,14 @@ int android_logger_list_read(struct logger_list *logger_list,
cp += ret;
}
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
/* Deal with an unresponsive logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
old_alarm = alarm(30);
}
ret = write(sock, buffer, cp - buffer);
e = errno;
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
if (e == EINTR) {
e = ETIMEDOUT;
}
@@ -669,7 +844,7 @@ int android_logger_list_read(struct logger_list *logger_list,
while(1) {
memset(log_msg, 0, sizeof(*log_msg));
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
/* particularily useful if tombstone is reporting for logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
old_alarm = alarm(30);
@@ -677,7 +852,7 @@ int android_logger_list_read(struct logger_list *logger_list,
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
e = errno;
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
if ((ret == 0) || (e == EINTR)) {
e = EAGAIN;
ret = -1;
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 41b8a51..bdc7b18 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -75,10 +75,10 @@ const char *android_log_id_to_name(log_id_t log_id)
static int accessmode(int mode)
{
- if ((mode & O_ACCMODE) == O_WRONLY) {
+ if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_WRONLY) {
return W_OK;
}
- if ((mode & O_ACCMODE) == O_RDWR) {
+ if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR) {
return R_OK | W_OK;
}
return R_OK;
@@ -117,7 +117,7 @@ log_id_t android_name_to_log_id(const char *logName)
++b;
}
- ret = check_allocate_accessible(&n, b, O_RDONLY);
+ ret = check_allocate_accessible(&n, b, ANDROID_LOG_RDONLY);
free(n);
if (ret) {
return ret;
@@ -201,8 +201,8 @@ static int logger_ioctl(struct logger *logger, int cmd, int mode)
return -EFAULT;
}
- if (((mode & O_ACCMODE) == O_RDWR)
- || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+ if (((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR)
+ || (((mode ^ logger->top->mode) & ANDROID_LOG_ACCMODE) == 0)) {
return ioctl(logger->fd, cmd);
}
@@ -227,13 +227,13 @@ static int logger_ioctl(struct logger *logger, int cmd, int mode)
int android_logger_clear(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+ return logger_ioctl(logger, LOGGER_FLUSH_LOG, ANDROID_LOG_WRONLY);
}
/* returns the total size of the log's ring buffer */
long android_logger_get_log_size(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+ return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, ANDROID_LOG_RDWR);
}
int android_logger_set_log_size(struct logger *logger __unused,
@@ -248,7 +248,7 @@ int android_logger_set_log_size(struct logger *logger __unused,
*/
long android_logger_get_log_readable_size(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+ return logger_ioctl(logger, LOGGER_GET_LOG_LEN, ANDROID_LOG_RDONLY);
}
/*
@@ -256,7 +256,7 @@ long android_logger_get_log_readable_size(struct logger *logger)
*/
int android_logger_get_log_version(struct logger *logger)
{
- int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+ int ret = logger_ioctl(logger, LOGGER_GET_VERSION, ANDROID_LOG_RDWR);
return (ret < 0) ? 1 : ret;
}
@@ -342,7 +342,7 @@ struct logger *android_logger_open(struct logger_list *logger_list,
goto err_name;
}
- logger->fd = open(n, logger_list->mode);
+ logger->fd = open(n, logger_list->mode & (ANDROID_LOG_ACCMODE | ANDROID_LOG_NONBLOCK));
if (logger->fd < 0) {
goto err_name;
}
@@ -565,7 +565,7 @@ int android_logger_list_read(struct logger_list *logger_list,
if (result <= 0) {
if (result) {
error = errno;
- } else if (logger_list->mode & O_NDELAY) {
+ } else if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
error = EAGAIN;
} else {
logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 755c2d9..50742df 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -39,7 +39,7 @@ char *log_time::strptime(const char *s, const char *format) {
#endif
struct tm *ptm;
-#if (defined(HAVE_LOCALTIME_R))
+#if !defined(_WIN32)
struct tm tmBuf;
ptm = localtime_r(&now, &tmBuf);
#else
@@ -78,7 +78,7 @@ char *log_time::strptime(const char *s, const char *format) {
++ret;
}
now = tv_sec;
-#if (defined(HAVE_LOCALTIME_R))
+#if !defined(_WIN32)
ptm = localtime_r(&now, &tmBuf);
#else
ptm = localtime(&now);
@@ -150,6 +150,17 @@ log_time log_time::operator-= (const timespec &T) {
return *this;
}
+log_time log_time::operator+= (const timespec &T) {
+ this->tv_nsec += (unsigned long int)T.tv_nsec;
+ if (this->tv_nsec >= NS_PER_SEC) {
+ this->tv_nsec -= NS_PER_SEC;
+ ++this->tv_sec;
+ }
+ this->tv_sec += T.tv_sec;
+
+ return *this;
+}
+
log_time log_time::operator-= (const log_time &T) {
// No concept of negative time, clamp to EPOCH
if (*this <= T) {
@@ -166,3 +177,14 @@ log_time log_time::operator-= (const log_time &T) {
return *this;
}
+
+log_time log_time::operator+= (const log_time &T) {
+ this->tv_nsec += T.tv_nsec;
+ if (this->tv_nsec >= NS_PER_SEC) {
+ this->tv_nsec -= NS_PER_SEC;
+ ++this->tv_sec;
+ }
+ this->tv_sec += T.tv_sec;
+
+ return *this;
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index b2668ce..c62a246 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#if (FAKE_LOG_DEVICE == 0)
+#include <endian.h>
+#endif
#include <errno.h>
#include <fcntl.h>
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
#include <pthread.h>
#endif
#include <stdarg.h>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,6 +43,7 @@
#include <log/logger.h>
#include <log/log_read.h>
#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#define LOG_BUF_SIZE 1024
@@ -49,7 +54,7 @@
static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
@@ -61,6 +66,7 @@ static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
#else
static int logd_fd = -1;
+static int pstore_fd = -1;
#endif
/*
@@ -71,6 +77,7 @@ static int logd_fd = -1;
static enum {
kLogUninitialized, kLogNotAvailable, kLogAvailable
} g_log_status = kLogUninitialized;
+
int __android_log_dev_available(void)
{
if (g_log_status == kLogUninitialized) {
@@ -83,15 +90,6 @@ int __android_log_dev_available(void)
return (g_log_status == kLogAvailable);
}
-#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()
{
@@ -104,40 +102,38 @@ static int __write_to_log_initialize()
log_fds[i] = fakeLogOpen(buf, O_WRONLY);
}
#else
- if (logd_fd >= 0) {
- i = logd_fd;
- logd_fd = -1;
- close(i);
+ if (pstore_fd < 0) {
+ pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
}
- 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) {
+ if (logd_fd < 0) {
+ i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+ if (i < 0) {
+ ret = -errno;
+ } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
ret = -errno;
close(i);
- i = -1;
+ } 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 (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+ sizeof(struct sockaddr_un))) < 0) {
+ ret = -errno;
+ close(i);
+ } else {
+ logd_fd = i;
+ }
}
}
- logd_fd = i;
#endif
return ret;
}
-static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
{
ssize_t ret;
#if FAKE_LOG_DEVICE
@@ -155,37 +151,32 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
}
} while (ret == -EINTR);
#else
- static const unsigned header_length = 3;
+ static const unsigned header_length = 2;
struct iovec newVec[nr + header_length];
- typeof_log_id_t log_id_buf;
- uint16_t tid;
+ android_log_header_t header;
+ android_pmsg_log_header_t pmsg_header;
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 */
+ static pid_t last_pid = (pid_t) -1;
+ static atomic_int_fast32_t dropped;
+
+ if (!nr) {
+ return -EINVAL;
+ }
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;
+ if (last_pid == (pid_t) -1) {
+ last_pid = getpid();
}
-
/*
* struct {
- * // what we provide
- * typeof_log_id_t log_id;
- * u16 tid;
- * log_time realtime;
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
* // caller provides
* union {
* struct {
@@ -201,18 +192,42 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
*/
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();
+ pmsg_header.magic = LOGGER_MAGIC;
+ pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
+ pmsg_header.uid = last_uid;
+ pmsg_header.pid = last_pid;
+
+ header.tid = gettid();
+ header.realtime.tv_sec = ts.tv_sec;
+ header.realtime.tv_nsec = ts.tv_nsec;
+
+ newVec[0].iov_base = (unsigned char *) &pmsg_header;
+ newVec[0].iov_len = sizeof(pmsg_header);
+ newVec[1].iov_base = (unsigned char *) &header;
+ newVec[1].iov_len = sizeof(header);
+
+ if (logd_fd > 0) {
+ int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+ if (snapshot) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[2].iov_base = &buffer;
+ newVec[2].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+ }
+ }
+ }
- 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);
+ header.id = log_id;
for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
newVec[i].iov_base = vec[i - header_length].iov_base;
@@ -223,25 +238,48 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
if (newVec[i].iov_len) {
++i;
}
+ payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
break;
}
}
+ pmsg_header.len += payload_size;
+
+ if (pstore_fd >= 0) {
+ TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
+ }
+
+ 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;
+ }
/*
* The write below could be lost, but will never block.
*
+ * To logd, we drop the pmsg_header
+ *
* ENOTCONN occurs if logd dies.
* EAGAIN occurs if logd is overloaded.
*/
- ret = writev(logd_fd, newVec, i);
+ ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
if (ret < 0) {
ret = -errno;
if (ret == -ENOTCONN) {
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
pthread_mutex_lock(&log_init_lock);
#endif
+ close(logd_fd);
+ logd_fd = -1;
ret = __write_to_log_initialize();
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
#endif
@@ -249,15 +287,17 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
return ret;
}
- ret = writev(logd_fd, newVec, nr + header_length);
+ ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
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);
+ if (ret > (ssize_t)sizeof(header)) {
+ ret -= sizeof(header);
+ } else if (ret == -EAGAIN) {
+ atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
}
#endif
@@ -284,7 +324,7 @@ const char *android_log_id_to_name(log_id_t log_id)
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
pthread_mutex_lock(&log_init_lock);
#endif
@@ -293,16 +333,21 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
ret = __write_to_log_initialize();
if (ret < 0) {
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
#endif
+#if (FAKE_LOG_DEVICE == 0)
+ if (pstore_fd >= 0) {
+ __write_to_log_daemon(log_id, vec, nr);
+ }
+#endif
return ret;
}
- write_to_log = __write_to_log_kernel;
+ write_to_log = __write_to_log_daemon;
}
-#ifdef HAVE_PTHREADS
+#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
#endif
@@ -311,43 +356,7 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
int __android_log_write(int prio, const char *tag, const char *msg)
{
- struct iovec vec[3];
- log_id_t log_id = LOG_ID_MAIN;
- char tmp_tag[32];
-
- if (!tag)
- tag = "";
-
- /* XXX: This needs to go! */
- if (!strcmp(tag, "HTC_RIL") ||
- !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
- !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
- !strcmp(tag, "AT") ||
- !strcmp(tag, "GSM") ||
- !strcmp(tag, "STK") ||
- !strcmp(tag, "CDMA") ||
- !strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS")) {
- log_id = LOG_ID_RADIO;
- /* 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) {
- android_set_abort_message(msg);
- }
-#endif
-
- vec[0].iov_base = (unsigned char *) &prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *) tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *) msg;
- vec[2].iov_len = strlen(msg) + 1;
-
- return write_to_log(log_id, vec, 3);
+ return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -375,6 +384,12 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms
tag = tmp_tag;
}
+#if __BIONIC__
+ if (prio == ANDROID_LOG_FATAL) {
+ android_set_abort_message(msg);
+ }
+#endif
+
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
@@ -440,7 +455,7 @@ 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 */
+ abort(); /* abort so we have a chance to debug the situation */
/* NOTREACHED */
}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index ae621cb..8742b34 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -16,9 +16,7 @@
#include <errno.h>
#include <fcntl.h>
-#ifdef HAVE_PTHREADS
#include <pthread.h>
-#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -28,9 +26,7 @@
#include <time.h>
#include <unistd.h>
-#ifdef __BIONIC__
#include <android/set_abort_message.h>
-#endif
#include <log/log.h>
#include <log/logd.h>
@@ -43,23 +39,14 @@
#define LOG_BUF_SIZE 1024
-#if FAKE_LOG_DEVICE
-/* 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);
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#ifdef HAVE_PTHREADS
+
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
#ifndef __unused
#define __unused __attribute__((__unused__))
@@ -119,9 +106,7 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
-#ifdef HAVE_PTHREADS
pthread_mutex_lock(&log_init_lock);
-#endif
if (write_to_log == __write_to_log_init) {
log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
@@ -147,52 +132,14 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
}
}
-#ifdef HAVE_PTHREADS
pthread_mutex_unlock(&log_init_lock);
-#endif
return write_to_log(log_id, vec, nr);
}
int __android_log_write(int prio, const char *tag, const char *msg)
{
- struct iovec vec[3];
- log_id_t log_id = LOG_ID_MAIN;
- char tmp_tag[32];
-
- if (!tag)
- tag = "";
-
- /* XXX: This needs to go! */
- if (!strcmp(tag, "HTC_RIL") ||
- !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
- !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
- !strcmp(tag, "AT") ||
- !strcmp(tag, "GSM") ||
- !strcmp(tag, "STK") ||
- !strcmp(tag, "CDMA") ||
- !strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS")) {
- log_id = LOG_ID_RADIO;
- /* 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) {
- android_set_abort_message(msg);
- }
-#endif
-
- vec[0].iov_base = (unsigned char *) &prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *) tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *) msg;
- vec[2].iov_len = strlen(msg) + 1;
-
- return write_to_log(log_id, vec, 3);
+ return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -220,6 +167,10 @@ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *ms
tag = tmp_tag;
}
+ if (prio == ANDROID_LOG_FATAL) {
+ android_set_abort_message(msg);
+ }
+
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
@@ -285,7 +236,7 @@ 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 */
+ abort(); /* abort so we have a chance to debug the situation */
/* NOTREACHED */
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 08e830a..7ba4c8e 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,10 +21,12 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/param.h>
#include <log/logd.h>
#include <log/logprint.h>
@@ -39,8 +41,23 @@ struct AndroidLogFormat_t {
android_LogPriority global_pri;
FilterInfo *filters;
AndroidLogPrintFormat format;
+ bool colored_output;
};
+/*
+ * gnome-terminal color tags
+ * See http://misc.flogisoft.com/bash/tip_colors_and_formatting
+ * for ideas on how to set the forground color of the text for xterm.
+ * The color manipulation character stream is defined as:
+ * ESC [ 3 8 ; 5 ; <color#> m
+ */
+#define ANDROID_COLOR_BLUE 75
+#define ANDROID_COLOR_DEFAULT 231
+#define ANDROID_COLOR_GREEN 40
+#define ANDROID_COLOR_ORANGE 166
+#define ANDROID_COLOR_RED 196
+#define ANDROID_COLOR_YELLOW 226
+
static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
{
FilterInfo *p_ret;
@@ -110,6 +127,23 @@ static char filterPriToChar (android_LogPriority pri)
}
}
+static int colorFromPri (android_LogPriority pri)
+{
+ switch (pri) {
+ case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
+ case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
+ case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
+ case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE;
+ case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
+ case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
+ case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
+
+ case ANDROID_LOG_DEFAULT:
+ case ANDROID_LOG_UNKNOWN:
+ default: return ANDROID_COLOR_DEFAULT;
+ }
+}
+
static android_LogPriority filterPriForTag(
AndroidLogFormat *p_format, const char *tag)
{
@@ -149,6 +183,7 @@ AndroidLogFormat *android_log_format_new()
p_ret->global_pri = ANDROID_LOG_VERBOSE;
p_ret->format = FORMAT_BRIEF;
+ p_ret->colored_output = false;
return p_ret;
}
@@ -174,7 +209,10 @@ void android_log_format_free(AndroidLogFormat *p_format)
void android_log_setPrintFormat(AndroidLogFormat *p_format,
AndroidLogPrintFormat format)
{
- p_format->format=format;
+ if (format == FORMAT_COLOR)
+ p_format->colored_output = true;
+ else
+ p_format->format = format;
}
/**
@@ -192,6 +230,7 @@ AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
+ else if (strcmp(formatString, "color") == 0) format = FORMAT_COLOR;
else format = FORMAT_OFF;
return format;
@@ -305,15 +344,6 @@ error:
return -1;
}
-static inline char * strip_end(char *str)
-{
- char *end = str + strlen(str) - 1;
-
- while (end >= str && isspace(*end))
- *end-- = '\0';
- return str;
-}
-
/**
* Splits a wire-format buffer into an AndroidLogEntry
* entry allocated by caller. Pointers will point directly into buf
@@ -687,7 +717,7 @@ char *android_log_formatLogLine (
const AndroidLogEntry *entry,
size_t *p_outLength)
{
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
struct tm tmBuf;
#endif
struct tm* ptm;
@@ -698,6 +728,8 @@ char *android_log_formatLogLine (
char * ret = NULL;
priChar = filterPriToChar(entry->priority);
+ size_t prefixLen = 0, suffixLen = 0;
+ size_t len;
/*
* Get the current date/time in pretty form
@@ -708,7 +740,7 @@ char *android_log_formatLogLine (
* in the time stamp. Don't use forward slashes, parenthesis,
* brackets, asterisks, or other special chars here.
*/
-#if defined(HAVE_LOCALTIME_R)
+#if !defined(_WIN32)
ptm = localtime_r(&(entry->tv_sec), &tmBuf);
#else
ptm = localtime(&(entry->tv_sec));
@@ -719,73 +751,80 @@ char *android_log_formatLogLine (
/*
* Construct a buffer containing the log header and log message.
*/
- size_t prefixLen, suffixLen;
+ if (p_format->colored_output) {
+ prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm",
+ colorFromPri(entry->priority));
+ prefixLen = MIN(prefixLen, sizeof(prefixBuf));
+ suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m");
+ suffixLen = MIN(suffixLen, sizeof(suffixBuf));
+ }
switch (p_format->format) {
case FORMAT_TAG:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"%c/%-8s: ", priChar, entry->tag);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
case FORMAT_PROCESS:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%c(%5d) ", priChar, entry->pid);
- suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
+ len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
" (%s)\n", entry->tag);
+ suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%c(%5d) ", priChar, entry->pid);
break;
case FORMAT_THREAD:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
- strcpy(suffixBuf, "\n");
- suffixLen = 1;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
case FORMAT_RAW:
- prefixBuf[0] = 0;
- prefixLen = 0;
- strcpy(suffixBuf, "\n");
- suffixLen = 1;
+ prefixBuf[prefixLen] = 0;
+ len = 0;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
case FORMAT_TIME:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
priChar, entry->tag, entry->pid);
- strcpy(suffixBuf, "\n");
- suffixLen = 1;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
case FORMAT_THREADTIME:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
entry->pid, entry->tid, priChar, entry->tag);
- strcpy(suffixBuf, "\n");
- suffixLen = 1;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
case FORMAT_LONG:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"[ %s.%03ld %5d:%5d %c/%-8s ]\n",
timeBuf, entry->tv_nsec / 1000000, entry->pid,
entry->tid, priChar, entry->tag);
- strcpy(suffixBuf, "\n\n");
- suffixLen = 2;
+ strcpy(suffixBuf + suffixLen, "\n\n");
+ suffixLen += 2;
prefixSuffixIsHeaderFooter = 1;
break;
case FORMAT_BRIEF:
default:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
"%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
- strcpy(suffixBuf, "\n");
- suffixLen = 1;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
break;
}
+
/* snprintf has a weird return value. It returns what would have been
* written given a large enough buffer. In the case that the prefix is
* longer then our buffer(128), it messes up the calculations below
* possibly causing heap corruption. To avoid this we double check and
* set the length at the maximum (size minus null byte)
*/
- if(prefixLen >= sizeof(prefixBuf))
- prefixLen = sizeof(prefixBuf) - 1;
- if(suffixLen >= sizeof(suffixBuf))
- suffixLen = sizeof(suffixBuf) - 1;
+ prefixLen += MIN(len, sizeof(prefixBuf) - prefixLen);
+ suffixLen = MIN(suffixLen, sizeof(suffixBuf));
/* the following code is tragically unreadable */
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index cd1bf33..d75bbc9 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -39,16 +39,10 @@ benchmark_src_files := \
include $(CLEAR_VARS)
LOCAL_MODULE := $(test_module_prefix)benchmarks
LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(benchmark_c_flags)
LOCAL_SHARED_LIBRARIES += liblog libm
LOCAL_SRC_FILES := $(benchmark_src_files)
-ifndef LOCAL_SDK_VERSION
-LOCAL_C_INCLUDES += bionic bionic/libstdc++/include external/stlport/stlport
-LOCAL_SHARED_LIBRARIES += libstlport
-endif
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
# -----------------------------------------------------------------------------
# Unit tests.
@@ -71,7 +65,7 @@ ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp)
test_src_files += \
libc_test.cpp
-ifndef ($(TARGET_USES_LOGD),false)
+ifneq ($(TARGET_USES_LOGD),false)
test_c_flags += -DTARGET_USES_LOGD
endif
@@ -82,7 +76,6 @@ endif
include $(CLEAR_VARS)
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(test_c_flags)
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := $(test_src_files)
diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp
index 090394c..e5ef970 100644
--- a/liblog/tests/benchmark_main.cpp
+++ b/liblog/tests/benchmark_main.cpp
@@ -17,6 +17,7 @@
#include <benchmark.h>
#include <inttypes.h>
+#include <math.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 9839729..29501be 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -39,7 +39,7 @@ TEST(libc, __libc_android_log_event_int) {
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -99,7 +99,7 @@ TEST(libc, __libc_fatal_no_abort) {
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
+ (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
char b[80];
struct timespec ts;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 549d79e..b594634 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -130,7 +130,7 @@ static void BM_log_latency(int iters) {
pid_t pid = getpid();
struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
- O_RDONLY, 0, pid);
+ ANDROID_LOG_RDONLY, 0, pid);
if (!logger_list) {
fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -208,7 +208,7 @@ static void BM_log_delay(int iters) {
pid_t pid = getpid();
struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
- O_RDONLY, 0, pid);
+ ANDROID_LOG_RDONLY, 0, pid);
if (!logger_list) {
fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -266,3 +266,17 @@ static void BM_log_delay(int iters) {
android_logger_list_free(logger_list);
}
BENCHMARK(BM_log_delay);
+
+/*
+ * Measure the time it takes for __android_log_is_loggable.
+ */
+static void BM_is_loggable(int iters) {
+ StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; ++i) {
+ __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+ }
+
+ StopBenchmarkTiming();
+}
+BENCHMARK(BM_is_loggable);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 393e2cd..33f6481 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -122,7 +122,7 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) {
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
log_time ts(CLOCK_MONOTONIC);
@@ -223,7 +223,7 @@ TEST(liblog, android_logger_list_read__cpu) {
v += pid & 0xFFFF;
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, O_RDONLY, 1000, pid)));
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
int count = 0;
@@ -443,7 +443,7 @@ TEST(liblog, max_payload) {
struct logger_list *logger_list;
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SYSTEM, O_RDONLY, 100, 0)));
+ LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
bool matches = false;
ssize_t max_len = 0;
@@ -505,7 +505,7 @@ TEST(liblog, too_big_payload) {
struct logger_list *logger_list;
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+ LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
ssize_t max_len = 0;
@@ -552,12 +552,12 @@ TEST(liblog, dual_reader) {
// >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
- LOG_ID_MAIN, O_RDONLY | O_NDELAY, 25, 0)));
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
struct logger_list *logger_list2;
if (NULL == (logger_list2 = android_logger_list_open(
- LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) {
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
android_logger_list_close(logger_list1);
ASSERT_TRUE(NULL != logger_list2);
}
@@ -595,7 +595,7 @@ TEST(liblog, dual_reader) {
}
TEST(liblog, android_logger_get_) {
- struct logger_list * logger_list = android_logger_list_alloc(O_WRONLY, 0, 0);
+ struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
log_id_t id = static_cast<log_id_t>(i);
diff --git a/liblog/uio.c b/liblog/uio.c
index 24a6507..f77cc49 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#ifndef HAVE_SYS_UIO_H
+#if defined(_WIN32)
#include <log/uio.h>
#include <unistd.h>
@@ -73,4 +73,4 @@ Exit:
return total;
}
-#endif /* !HAVE_SYS_UIO_H */
+#endif