AC_DEFINE_UNQUOTED([DLOG_SERVER_GROUP], "$dlog_server_group")
AC_SUBST([DLOG_SERVER_GROUP], "$dlog_server_group")
+AC_ARG_ENABLE([android-monotonic],
+ AS_HELP_STRING([--enable-android-monotonic], [use monotonic send timestamp with log message when using android backend (EXPERIMENTAL)]),
+ [android_monotonic=true],
+ [android_monotonic=false])
+if test x$android_monotonic = xtrue; then
+ AC_DEFINE_UNQUOTED([USE_ANDROID_MONOTONIC])
+fi
+
# output files
AC_SUBST([datadir])
AC_SUBST([libexecdir])
char msg[];
};
+#ifdef USE_ANDROID_MONOTONIC
+
+#define ANDROID_LOGGER_FOOTER_MAGIC 0xa1379841
+
+struct android_logger_footer {
+ uint32_t sec_sent_mono; /* time sent, seconds, monotonic */
+ uint32_t nsec_sent_mono; /* time sent, nanoseconds, monotonic */
+ uint32_t magic; /* arbitrary magic number, encode other info here (e.g. version number) in future versions, last field of structure no matter real version is */
+};
+
+#endif /* USE_ANDROID_MONOTONIC */
+
struct pipe_logger_entry {
/* same meanings as above */
uint16_t len;
#include <stdio.h>
#include <fcntl.h>
+#include <time.h>
#include <sys/socket.h>
#include <logcommon.h>
{
ssize_t ret;
int log_fd;
- struct iovec vec[3];
if (log_id > LOG_ID_INVALID && log_id < LOG_ID_MAX)
log_fd = log_fds[log_id];
if (!msg)
return DLOG_ERROR_INVALID_PARAMETER;
+#ifdef USE_ANDROID_MONOTONIC
+ struct iovec vec[4];
+
+ struct timespec ts;
+ struct android_logger_footer alf;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ alf.magic = ANDROID_LOGGER_FOOTER_MAGIC;
+ alf.sec_sent_mono = ts.tv_sec;
+ alf.nsec_sent_mono = ts.tv_nsec;
+
+ vec[3].iov_base = (void *) &alf;
+ vec[3].iov_len = sizeof alf;
+#else
+ struct iovec vec[3];
+#endif /* USE_ANDROID_MONOTONIC */
+
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
vec[2].iov_base = (void *) msg;
vec[2].iov_len = strlen(msg) + 1;
- ret = writev(log_fd, vec, 3);
+ ret = writev(log_fd, vec, NELEMS(vec));
if (ret < 0)
ret = -errno; // LCOV_EXCL_LINE
memmove(le->msg, xle->msg + 1, payload_size); \
}
+#ifdef USE_ANDROID_MONOTONIC
+static void parse_android_logger_footer(struct android_logger_entry *ale, struct logger_entry *le, size_t *payload_size)
+{
+ assert(ale);
+ assert(le);
+ assert(payload_size);
+
+ struct android_logger_footer *alf;
+ if (*payload_size <= sizeof *alf)
+ return;
+
+ alf = ale->msg + *payload_size - sizeof *alf;
+ if (alf->magic != ANDROID_LOGGER_FOOTER_MAGIC)
+ return;
+
+ *payload_size -= sizeof *alf;
+ le->sec_sent_mono = alf->sec_sent_mono;
+ le->nsec_sent_mono = alf->nsec_sent_mono;
+}
+#endif
+
/**
* @brief Parse AL message
* @details Parses an Android Logger message into DLog's internal format
void parse_androidlogger_message(struct android_logger_entry *ale, struct logger_entry *le, size_t dgram_size)
{
size_t payload_size = dgram_size - sizeof *ale;
- assert(payload_size <= LOG_MAX_PAYLOAD_SIZE);
+ assert(payload_size > 0);
+
+ le->sec_sent_mono = 0;
+ le->nsec_sent_mono = 0;
+#ifdef USE_ANDROID_MONOTONIC
+ /* there may be android_logger_footer at the end of payload, right after log message,
+ * but only if the message has been prepared and sent by libdlog,
+ * not directly from shell script via /dev file */
+ parse_android_logger_footer(ale, le, &payload_size);
+#endif
SHARED_PROCESS_MESSAGE(ale);
le->sec_sent_real = ale->sec_sent;
le->nsec_sent_real = ale->nsec_sent;
- le->sec_sent_mono = 0;
- le->nsec_sent_mono = 0;
le->default_send_ts_type = LOGGER_ENTRY_REALTIME;
}