liblog: event log list logging handler
(cherry pick from commit bd1ad049b2
)
Based off an initial request and effort by williamluh@google.com
- Added the following functions:
* Composing and Writing:
android_log_context create_android_logger(uint32_t tag)
int android_log_write_list_begin(android_log_context ctx)
int android_log_write_list_end(android_log_context ctx)
int android_log_write_int32(android_log_context ctx, int32_t value)
int android_log_write_int64(android_log_context ctx, int64_t value)
int android_log_write_string8(android_log_context ctx, const char *value)
int android_log_write_float32(android_log_context ctx, float value)
int android_log_write_list(android_log_context ctx, log_id_t id)
* Reading and Interpreting:
android_log_context create_android_log_parser(const char *msg, size_t len)
android_log_list_element android_log_read_next(android_log_context ctx)
android_log_list_element android_log_peek_next(android_log_context ctx)
* Destroy context used above:
int android_log_destroy(android_log_context *ctx);
- Added unit gTests
We moved implemented android_log_buffer_to_string() to the test since
it is an alternate for already existing logprint functionality.
Please move into liblog should it be of some common use, otherwise
as is it is a good means of stessing the reading and interpreting
handlers.
Signed-off-by: Mark Salyzyn <salyzyn@google.com>
Bug: 19235719
Change-Id: I4aa1927e8e6a75f0a129d15a27c891cf1ccd4f5c
This commit is contained in:
parent
ac460fc6de
commit
9dd6510dd0
|
@ -484,15 +484,19 @@ extern "C" {
|
|||
*/
|
||||
|
||||
/*
|
||||
* Event log entry types. These must match up with the declarations in
|
||||
* java/android/android/util/EventLog.java.
|
||||
* Event log entry types.
|
||||
*/
|
||||
typedef enum {
|
||||
EVENT_TYPE_INT = 0,
|
||||
EVENT_TYPE_LONG = 1,
|
||||
EVENT_TYPE_STRING = 2,
|
||||
EVENT_TYPE_LIST = 3,
|
||||
EVENT_TYPE_FLOAT = 4,
|
||||
/* Special markers for android_log_list_element type */
|
||||
EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
|
||||
EVENT_TYPE_UNKNOWN = '?', /* protocol error */
|
||||
|
||||
/* must match with declaration in java/android/android/util/EventLog.java */
|
||||
EVENT_TYPE_INT = 0, /* uint32_t */
|
||||
EVENT_TYPE_LONG = 1, /* uint64_t */
|
||||
EVENT_TYPE_STRING = 2,
|
||||
EVENT_TYPE_LIST = 3,
|
||||
EVENT_TYPE_FLOAT = 4,
|
||||
} AndroidEventLogType;
|
||||
#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
|
||||
#define typeof_AndroidEventLogType unsigned char
|
||||
|
@ -522,7 +526,85 @@ typedef enum {
|
|||
#define LOG_EVENT_STRING(_tag, _value) \
|
||||
(void) __android_log_bswrite(_tag, _value);
|
||||
#endif
|
||||
/* TODO: something for LIST */
|
||||
|
||||
typedef enum log_id {
|
||||
LOG_ID_MIN = 0,
|
||||
|
||||
#ifndef LINT_RLOG
|
||||
LOG_ID_MAIN = 0,
|
||||
#endif
|
||||
LOG_ID_RADIO = 1,
|
||||
#ifndef LINT_RLOG
|
||||
LOG_ID_EVENTS = 2,
|
||||
LOG_ID_SYSTEM = 3,
|
||||
LOG_ID_CRASH = 4,
|
||||
LOG_ID_SECURITY = 5,
|
||||
LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
|
||||
#endif
|
||||
|
||||
LOG_ID_MAX
|
||||
} log_id_t;
|
||||
#define sizeof_log_id_t sizeof(typeof_log_id_t)
|
||||
#define typeof_log_id_t unsigned char
|
||||
|
||||
/* For manipulating lists of events. */
|
||||
|
||||
#define ANDROID_MAX_LIST_NEST_DEPTH 8
|
||||
|
||||
/*
|
||||
* The opaque context used to manipulate lists of events.
|
||||
*/
|
||||
typedef struct android_log_context_internal *android_log_context;
|
||||
|
||||
/*
|
||||
* Elements returned when reading a list of events.
|
||||
*/
|
||||
typedef struct {
|
||||
AndroidEventLogType type;
|
||||
uint16_t complete;
|
||||
uint16_t len;
|
||||
union {
|
||||
int32_t int32;
|
||||
int64_t int64;
|
||||
char *string;
|
||||
float float32;
|
||||
} data;
|
||||
} android_log_list_element;
|
||||
|
||||
/*
|
||||
* Creates a context associated with an event tag to write elements to
|
||||
* the list of events.
|
||||
*/
|
||||
android_log_context create_android_logger(uint32_t tag);
|
||||
|
||||
/* All lists must be braced by a begin and end call */
|
||||
/*
|
||||
* NB: If the first level braces are missing when specifying multiple
|
||||
* elements, we will manufacturer a list to embrace it for your API
|
||||
* convenience. For a single element, it will remain solitary.
|
||||
*/
|
||||
int android_log_write_list_begin(android_log_context ctx);
|
||||
int android_log_write_list_end(android_log_context ctx);
|
||||
|
||||
int android_log_write_int32(android_log_context ctx, int32_t value);
|
||||
int android_log_write_int64(android_log_context ctx, int64_t value);
|
||||
int android_log_write_string8(android_log_context ctx, const char *value);
|
||||
int android_log_write_float32(android_log_context ctx, float value);
|
||||
|
||||
/* Submit the composed list context to the specified logger id */
|
||||
/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
|
||||
int android_log_write_list(android_log_context ctx, log_id_t id);
|
||||
|
||||
/*
|
||||
* Creates a context from a raw buffer representing a list of events to be read.
|
||||
*/
|
||||
android_log_context create_android_log_parser(const char *msg, size_t len);
|
||||
|
||||
android_log_list_element android_log_read_next(android_log_context ctx);
|
||||
android_log_list_element android_log_peek_next(android_log_context ctx);
|
||||
|
||||
/* Finished with reader or writer context */
|
||||
int android_log_destroy(android_log_context *ctx);
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
|
@ -585,26 +667,6 @@ typedef enum {
|
|||
(__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
|
||||
#endif
|
||||
|
||||
typedef enum log_id {
|
||||
LOG_ID_MIN = 0,
|
||||
|
||||
#ifndef LINT_RLOG
|
||||
LOG_ID_MAIN = 0,
|
||||
#endif
|
||||
LOG_ID_RADIO = 1,
|
||||
#ifndef LINT_RLOG
|
||||
LOG_ID_EVENTS = 2,
|
||||
LOG_ID_SYSTEM = 3,
|
||||
LOG_ID_CRASH = 4,
|
||||
LOG_ID_SECURITY = 5,
|
||||
LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
|
||||
#endif
|
||||
|
||||
LOG_ID_MAX
|
||||
} log_id_t;
|
||||
#define sizeof_log_id_t sizeof(typeof_log_id_t)
|
||||
#define typeof_log_id_t unsigned char
|
||||
|
||||
/*
|
||||
* Use the per-tag properties "log.tag.<tagname>" to generate a runtime
|
||||
* result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
|
||||
|
|
|
@ -28,6 +28,7 @@ liblog_host_sources := logd_write.c log_event_write.c fake_log_device.c event.lo
|
|||
liblog_target_sources := logd_write.c log_event_write.c event_tag_map.c log_time.cpp log_is_loggable.c
|
||||
liblog_target_sources += logprint.c
|
||||
liblog_target_sources += log_read.c
|
||||
liblog_target_sources += log_event_list.c
|
||||
|
||||
# Shared and static library for host
|
||||
# ========================================================
|
||||
|
|
|
@ -0,0 +1,520 @@
|
|||
/*
|
||||
* Copyright (C) 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 <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <log/log.h>
|
||||
#include <log/logger.h>
|
||||
|
||||
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
|
||||
|
||||
typedef struct {
|
||||
uint32_t tag;
|
||||
unsigned pos; /* Read/write position into buffer */
|
||||
unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
|
||||
unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
|
||||
unsigned list_nest_depth;
|
||||
unsigned len; /* Length or raw buffer. */
|
||||
bool overflow;
|
||||
bool list_stop; /* next call decrement list_nest_depth and issue a stop */
|
||||
enum {
|
||||
kAndroidLoggerRead = 1,
|
||||
kAndroidLoggerWrite = 2,
|
||||
} read_write_flag;
|
||||
uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
|
||||
} android_log_context_internal;
|
||||
|
||||
android_log_context create_android_logger(uint32_t tag) {
|
||||
size_t needed, i;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = calloc(1, sizeof(android_log_context_internal));
|
||||
if (!context) {
|
||||
return NULL;
|
||||
}
|
||||
context->tag = tag;
|
||||
context->read_write_flag = kAndroidLoggerWrite;
|
||||
needed = sizeof(uint8_t) + sizeof(uint8_t);
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
context->overflow = true;
|
||||
}
|
||||
/* Everything is a list */
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_LIST;
|
||||
context->list[0] = context->pos + 1;
|
||||
context->pos += needed;
|
||||
|
||||
return (android_log_context)context;
|
||||
}
|
||||
|
||||
android_log_context create_android_log_parser(const char *msg, size_t len) {
|
||||
android_log_context_internal *context;
|
||||
size_t i;
|
||||
|
||||
context = calloc(1, sizeof(android_log_context_internal));
|
||||
if (!context) {
|
||||
return NULL;
|
||||
}
|
||||
len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
|
||||
context->len = len;
|
||||
memcpy(context->storage, msg, len);
|
||||
context->read_write_flag = kAndroidLoggerRead;
|
||||
|
||||
return (android_log_context)context;
|
||||
}
|
||||
|
||||
int android_log_destroy(android_log_context *ctx) {
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)*ctx;
|
||||
if (!context) {
|
||||
return -EBADF;
|
||||
}
|
||||
memset(context, 0, sizeof(*context));
|
||||
free(context);
|
||||
*ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_log_write_list_begin(android_log_context ctx) {
|
||||
size_t needed;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context ||
|
||||
(kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
|
||||
context->overflow = true;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
needed = sizeof(uint8_t) + sizeof(uint8_t);
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
context->overflow = true;
|
||||
return -EIO;
|
||||
}
|
||||
context->count[context->list_nest_depth]++;
|
||||
context->list_nest_depth++;
|
||||
if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
|
||||
context->overflow = true;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (context->overflow) {
|
||||
return -EIO;
|
||||
}
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_LIST;
|
||||
context->storage[context->pos + 1] = 0;
|
||||
context->list[context->list_nest_depth] = context->pos + 1;
|
||||
context->count[context->list_nest_depth] = 0;
|
||||
context->pos += needed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void copy4LE(uint8_t *buf, uint32_t val)
|
||||
{
|
||||
buf[0] = val & 0xFF;
|
||||
buf[1] = (val >> 8) & 0xFF;
|
||||
buf[2] = (val >> 16) & 0xFF;
|
||||
buf[3] = (val >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
int android_log_write_int32(android_log_context ctx, int32_t value) {
|
||||
size_t needed;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->overflow) {
|
||||
return -EIO;
|
||||
}
|
||||
needed = sizeof(uint8_t) + sizeof(value);
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
context->overflow = true;
|
||||
return -EIO;
|
||||
}
|
||||
context->count[context->list_nest_depth]++;
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_INT;
|
||||
copy4LE(&context->storage[context->pos + 1], value);
|
||||
context->pos += needed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void copy8LE(uint8_t *buf, uint64_t val)
|
||||
{
|
||||
buf[0] = val & 0xFF;
|
||||
buf[1] = (val >> 8) & 0xFF;
|
||||
buf[2] = (val >> 16) & 0xFF;
|
||||
buf[3] = (val >> 24) & 0xFF;
|
||||
buf[4] = (val >> 32) & 0xFF;
|
||||
buf[5] = (val >> 40) & 0xFF;
|
||||
buf[6] = (val >> 48) & 0xFF;
|
||||
buf[7] = (val >> 56) & 0xFF;
|
||||
}
|
||||
|
||||
int android_log_write_int64(android_log_context ctx, int64_t value) {
|
||||
size_t needed;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->overflow) {
|
||||
return -EIO;
|
||||
}
|
||||
needed = sizeof(uint8_t) + sizeof(value);
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
context->overflow = true;
|
||||
return -EIO;
|
||||
}
|
||||
context->count[context->list_nest_depth]++;
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_LONG;
|
||||
copy8LE(&context->storage[context->pos + 1], value);
|
||||
context->pos += needed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_log_write_string8(android_log_context ctx, const char *value) {
|
||||
size_t needed;
|
||||
int32_t len;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->overflow) {
|
||||
return -EIO;
|
||||
}
|
||||
if (!value) {
|
||||
return -EINVAL;
|
||||
}
|
||||
len = strlen(value);
|
||||
needed = sizeof(uint8_t) + sizeof(len) + len;
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
/* Truncate string for delivery */
|
||||
len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(len);
|
||||
if (len <= 0) {
|
||||
context->overflow = true;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
context->count[context->list_nest_depth]++;
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_STRING;
|
||||
copy4LE(&context->storage[context->pos + 1], len);
|
||||
memcpy(&context->storage[context->pos + 5], value, len);
|
||||
context->pos += needed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_log_write_float32(android_log_context ctx, float value) {
|
||||
size_t needed;
|
||||
uint32_t ivalue;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->overflow) {
|
||||
return -EIO;
|
||||
}
|
||||
needed = sizeof(uint8_t) + sizeof(ivalue);
|
||||
if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
|
||||
context->overflow = true;
|
||||
return -EIO;
|
||||
}
|
||||
ivalue = *(uint32_t *)&value;
|
||||
context->count[context->list_nest_depth]++;
|
||||
context->storage[context->pos + 0] = EVENT_TYPE_FLOAT;
|
||||
copy4LE(&context->storage[context->pos + 1], ivalue);
|
||||
context->pos += needed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_log_write_list_end(android_log_context ctx) {
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
|
||||
context->overflow = true;
|
||||
context->list_nest_depth--;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (!context->list_nest_depth) {
|
||||
context->overflow = true;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (context->list[context->list_nest_depth] <= 0) {
|
||||
context->list_nest_depth--;
|
||||
context->overflow = true;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
context->storage[context->list[context->list_nest_depth]] =
|
||||
context->count[context->list_nest_depth];
|
||||
context->list_nest_depth--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logs the list of elements to the event log.
|
||||
*/
|
||||
int android_log_write_list(android_log_context ctx, log_id_t id) {
|
||||
android_log_context_internal *context;
|
||||
const char *msg;
|
||||
ssize_t len;
|
||||
|
||||
if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
|
||||
return -EBADF;
|
||||
}
|
||||
if (context->list_nest_depth) {
|
||||
return -EIO;
|
||||
}
|
||||
/* NB: if there was overflow, then log is truncated. Nothing reported */
|
||||
context->storage[1] = context->count[0];
|
||||
len = context->len = context->pos;
|
||||
msg = (const char *)context->storage;
|
||||
/* it'snot a list */
|
||||
if (context->count[0] <= 1) {
|
||||
len -= sizeof(uint8_t) + sizeof(uint8_t);
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
}
|
||||
msg += sizeof(uint8_t) + sizeof(uint8_t);
|
||||
}
|
||||
return (id == LOG_ID_EVENTS) ?
|
||||
__android_log_bwrite(context->tag, msg, len) :
|
||||
__android_log_security_bwrite(context->tag, msg, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a 4-byte value from a byte stream.
|
||||
*/
|
||||
static inline uint32_t get4LE(const uint8_t* src)
|
||||
{
|
||||
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract an 8-byte value from a byte stream.
|
||||
*/
|
||||
static inline uint64_t get8LE(const uint8_t* src)
|
||||
{
|
||||
uint32_t low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
uint32_t high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
|
||||
return ((uint64_t) high << 32) | (uint64_t) low;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the next element. Parsing errors result in an EVENT_TYPE_UNKNOWN type.
|
||||
* If there is nothing to process, the complete field is set to non-zero. If
|
||||
* an EVENT_TYPE_UNKNOWN type is returned once, and the caller does not check
|
||||
* this and continues to call this function, the behavior is undefined
|
||||
* (although it won't crash).
|
||||
*/
|
||||
static android_log_list_element android_log_read_next_internal(
|
||||
android_log_context ctx, int peek) {
|
||||
android_log_list_element elem;
|
||||
unsigned pos;
|
||||
android_log_context_internal *context;
|
||||
|
||||
context = (android_log_context_internal *)ctx;
|
||||
|
||||
memset(&elem, 0, sizeof(elem));
|
||||
|
||||
/* Nothing to parse from this context, so return complete. */
|
||||
if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
|
||||
(context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
|
||||
(context->count[context->list_nest_depth] >=
|
||||
(MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
if (context &&
|
||||
(context->list_stop ||
|
||||
((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
|
||||
!context->count[context->list_nest_depth]))) {
|
||||
elem.type = EVENT_TYPE_LIST_STOP;
|
||||
}
|
||||
elem.complete = true;
|
||||
return elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a different variable to update the position in case this
|
||||
* operation is a "peek".
|
||||
*/
|
||||
pos = context->pos;
|
||||
if (context->list_stop) {
|
||||
elem.type = EVENT_TYPE_LIST_STOP;
|
||||
elem.complete = !context->count[0] && (!context->list_nest_depth ||
|
||||
((context->list_nest_depth == 1) && !context->count[1]));
|
||||
if (!peek) {
|
||||
/* Suck in superfluous stop */
|
||||
if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
|
||||
context->pos = pos + 1;
|
||||
}
|
||||
if (context->list_nest_depth) {
|
||||
--context->list_nest_depth;
|
||||
if (context->count[context->list_nest_depth]) {
|
||||
context->list_stop = false;
|
||||
}
|
||||
} else {
|
||||
context->list_stop = false;
|
||||
}
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
if ((pos + 1) > context->len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
elem.complete = true;
|
||||
return elem;
|
||||
}
|
||||
|
||||
elem.type = context->storage[pos++];
|
||||
switch ((int)elem.type) {
|
||||
case EVENT_TYPE_FLOAT:
|
||||
/* Rely on union to translate elem.data.int32 into elem.data.float32 */
|
||||
/* FALLTHRU */
|
||||
case EVENT_TYPE_INT:
|
||||
elem.len = sizeof(int32_t);
|
||||
if ((pos + elem.len) > context->len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
return elem;
|
||||
}
|
||||
elem.data.int32 = get4LE(&context->storage[pos]);
|
||||
/* common tangeable object suffix */
|
||||
pos += elem.len;
|
||||
elem.complete = !context->list_nest_depth && !context->count[0];
|
||||
if (!peek) {
|
||||
if (!context->count[context->list_nest_depth] ||
|
||||
!--(context->count[context->list_nest_depth])) {
|
||||
context->list_stop = true;
|
||||
}
|
||||
context->pos = pos;
|
||||
}
|
||||
return elem;
|
||||
|
||||
case EVENT_TYPE_LONG:
|
||||
elem.len = sizeof(int64_t);
|
||||
if ((pos + elem.len) > context->len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
return elem;
|
||||
}
|
||||
elem.data.int64 = get8LE(&context->storage[pos]);
|
||||
/* common tangeable object suffix */
|
||||
pos += elem.len;
|
||||
elem.complete = !context->list_nest_depth && !context->count[0];
|
||||
if (!peek) {
|
||||
if (!context->count[context->list_nest_depth] ||
|
||||
!--(context->count[context->list_nest_depth])) {
|
||||
context->list_stop = true;
|
||||
}
|
||||
context->pos = pos;
|
||||
}
|
||||
return elem;
|
||||
|
||||
case EVENT_TYPE_STRING:
|
||||
if ((pos + sizeof(int32_t)) > context->len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
elem.complete = true;
|
||||
return elem;
|
||||
}
|
||||
elem.len = get4LE(&context->storage[pos]);
|
||||
pos += sizeof(int32_t);
|
||||
if ((pos + elem.len) > context->len) {
|
||||
elem.len = context->len - pos; /* truncate string */
|
||||
elem.complete = true;
|
||||
if (!elem.len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
elem.data.string = (char *)&context->storage[pos];
|
||||
/* common tangeable object suffix */
|
||||
pos += elem.len;
|
||||
elem.complete = !context->list_nest_depth && !context->count[0];
|
||||
if (!peek) {
|
||||
if (!context->count[context->list_nest_depth] ||
|
||||
!--(context->count[context->list_nest_depth])) {
|
||||
context->list_stop = true;
|
||||
}
|
||||
context->pos = pos;
|
||||
}
|
||||
return elem;
|
||||
|
||||
case EVENT_TYPE_LIST:
|
||||
if ((pos + sizeof(uint8_t)) > context->len) {
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
elem.complete = true;
|
||||
return elem;
|
||||
}
|
||||
elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
|
||||
if (peek) {
|
||||
return elem;
|
||||
}
|
||||
if (context->count[context->list_nest_depth]) {
|
||||
context->count[context->list_nest_depth]--;
|
||||
}
|
||||
context->list_stop = !context->storage[pos];
|
||||
context->list_nest_depth++;
|
||||
if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
|
||||
context->count[context->list_nest_depth] = context->storage[pos];
|
||||
}
|
||||
context->pos = pos + sizeof(uint8_t);
|
||||
return elem;
|
||||
|
||||
case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
|
||||
if (!peek) {
|
||||
context->pos = pos;
|
||||
}
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
elem.complete = !context->list_nest_depth;
|
||||
if (context->list_nest_depth > 0) {
|
||||
elem.type = EVENT_TYPE_LIST_STOP;
|
||||
if (!peek) {
|
||||
context->list_nest_depth--;
|
||||
}
|
||||
}
|
||||
return elem;
|
||||
|
||||
default:
|
||||
elem.type = EVENT_TYPE_UNKNOWN;
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
android_log_list_element android_log_read_next(android_log_context ctx) {
|
||||
return android_log_read_next_internal(ctx, 0);
|
||||
}
|
||||
|
||||
android_log_list_element android_log_peek_next(android_log_context ctx) {
|
||||
return android_log_read_next_internal(ctx, 1);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2014 The Android Open Source Project
|
||||
* Copyright (C) 2013-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.
|
||||
|
@ -1672,3 +1672,529 @@ TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
|
|||
|
||||
android_logger_list_close(logger_list);
|
||||
}
|
||||
|
||||
static int is_real_element(int type) {
|
||||
return ((type == EVENT_TYPE_INT) ||
|
||||
(type == EVENT_TYPE_LONG) ||
|
||||
(type == EVENT_TYPE_STRING) ||
|
||||
(type == EVENT_TYPE_FLOAT));
|
||||
}
|
||||
|
||||
int android_log_buffer_to_string(const char *msg, size_t len,
|
||||
char *strOut, size_t strOutLen) {
|
||||
android_log_context context = create_android_log_parser(msg, len);
|
||||
android_log_list_element elem;
|
||||
bool overflow = false;
|
||||
/* Reserve 1 byte for null terminator. */
|
||||
size_t origStrOutLen = strOutLen--;
|
||||
|
||||
if (!context) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
memset(&elem, 0, sizeof(elem));
|
||||
|
||||
size_t outCount;
|
||||
|
||||
do {
|
||||
elem = android_log_read_next(context);
|
||||
switch ((int)elem.type) {
|
||||
case EVENT_TYPE_LIST:
|
||||
if (strOutLen == 0) {
|
||||
overflow = true;
|
||||
} else {
|
||||
*strOut++ = '[';
|
||||
strOutLen--;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_TYPE_LIST_STOP:
|
||||
if (strOutLen == 0) {
|
||||
overflow = true;
|
||||
} else {
|
||||
*strOut++ = ']';
|
||||
strOutLen--;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_TYPE_INT:
|
||||
/*
|
||||
* snprintf also requires room for the null terminator, which
|
||||
* we don't care about but we have allocated enough room for
|
||||
* that
|
||||
*/
|
||||
outCount = snprintf(strOut, strOutLen + 1,
|
||||
"%" PRId32, elem.data.int32);
|
||||
if (outCount <= strOutLen) {
|
||||
strOut += outCount;
|
||||
strOutLen -= outCount;
|
||||
} else {
|
||||
overflow = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_TYPE_LONG:
|
||||
/*
|
||||
* snprintf also requires room for the null terminator, which
|
||||
* we don't care about but we have allocated enough room for
|
||||
* that
|
||||
*/
|
||||
outCount = snprintf(strOut, strOutLen + 1,
|
||||
"%" PRId64, elem.data.int64);
|
||||
if (outCount <= strOutLen) {
|
||||
strOut += outCount;
|
||||
strOutLen -= outCount;
|
||||
} else {
|
||||
overflow = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_TYPE_FLOAT:
|
||||
/*
|
||||
* snprintf also requires room for the null terminator, which
|
||||
* we don't care about but we have allocated enough room for
|
||||
* that
|
||||
*/
|
||||
outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
|
||||
if (outCount <= strOutLen) {
|
||||
strOut += outCount;
|
||||
strOutLen -= outCount;
|
||||
} else {
|
||||
overflow = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
elem.complete = true;
|
||||
break;
|
||||
|
||||
case EVENT_TYPE_UNKNOWN:
|
||||
#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
|
||||
if (elem.complete) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
elem.data.string = const_cast<char *>("<unknown>");
|
||||
elem.len = strlen(elem.data.string);
|
||||
/* FALLTHRU */
|
||||
case EVENT_TYPE_STRING:
|
||||
if (elem.len <= strOutLen) {
|
||||
memcpy(strOut, elem.data.string, elem.len);
|
||||
strOut += elem.len;
|
||||
strOutLen -= elem.len;
|
||||
} else if (strOutLen > 0) {
|
||||
/* copy what we can */
|
||||
memcpy(strOut, elem.data.string, strOutLen);
|
||||
strOut += strOutLen;
|
||||
strOutLen = 0;
|
||||
overflow = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (elem.complete) {
|
||||
break;
|
||||
}
|
||||
/* Determine whether to put a comma or not. */
|
||||
if (!overflow && (is_real_element(elem.type) ||
|
||||
(elem.type == EVENT_TYPE_LIST_STOP))) {
|
||||
android_log_list_element next = android_log_peek_next(context);
|
||||
if (!next.complete && (is_real_element(next.type) ||
|
||||
(next.type == EVENT_TYPE_LIST))) {
|
||||
if (strOutLen == 0) {
|
||||
overflow = true;
|
||||
} else {
|
||||
*strOut++ = ',';
|
||||
strOutLen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
|
||||
|
||||
android_log_destroy(&context);
|
||||
|
||||
if (overflow) {
|
||||
if (strOutLen < origStrOutLen) {
|
||||
/* leave an indicator */
|
||||
*(strOut-1) = '!';
|
||||
} else {
|
||||
/* nothing was written at all */
|
||||
*strOut++ = '!';
|
||||
}
|
||||
}
|
||||
*strOut++ = '\0';
|
||||
|
||||
if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
|
||||
fprintf(stderr, "Binary log entry conversion failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t);
|
||||
|
||||
return "1076895760";
|
||||
}
|
||||
|
||||
static const char *event_test_int64(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint64_t);
|
||||
|
||||
return "-9191740941672636400";
|
||||
}
|
||||
|
||||
static const char *event_test_list_int64(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint8_t) +
|
||||
sizeof(uint8_t) + sizeof(uint64_t);
|
||||
|
||||
return "[-9191740941672636400]";
|
||||
}
|
||||
|
||||
static const char *event_test_simple_automagic_list(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
// The convenience API where we allow a simple list to be
|
||||
// created without explicit begin or end calls.
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
|
||||
EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint8_t) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint64_t);
|
||||
|
||||
return "[1076895760,-9191740941672636400]";
|
||||
}
|
||||
|
||||
static const char *event_test_list_empty(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint8_t);
|
||||
|
||||
return "[]";
|
||||
}
|
||||
|
||||
static const char *event_test_complex_nested_list(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
|
||||
EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
|
||||
EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
|
||||
EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
|
||||
|
||||
//
|
||||
// This one checks for the automagic list creation because a list
|
||||
// begin and end was missing for it! This is actually an <oops> corner
|
||||
// case, and not the behavior we morally support. The automagic API is to
|
||||
// allow for a simple case of a series of objects in a single list. e.g.
|
||||
// int32,int32,int32,string -> [int32,int32,int32,string]
|
||||
//
|
||||
EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
|
||||
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint8_t) +
|
||||
sizeof(uint8_t) + sizeof(uint8_t) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint64_t) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t) +
|
||||
sizeof("Hello World") - 1 +
|
||||
sizeof(uint8_t) + sizeof(uint8_t) +
|
||||
4 * (sizeof(uint8_t) + sizeof(uint32_t)) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t) +
|
||||
sizeof(uint8_t) + sizeof(uint32_t) +
|
||||
sizeof("dlroW olleH") - 1;
|
||||
|
||||
return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW olleH]";
|
||||
}
|
||||
|
||||
static const char *event_test_7_level_prefix(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 5));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 6));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 7));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) + 7 *
|
||||
(sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
|
||||
|
||||
return "[[[[[[[1],2],3],4],5],6],7]";
|
||||
}
|
||||
|
||||
static const char *event_test_7_level_suffix(uint32_t tag, size_t &expected_len) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 1));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 2));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 3));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 4));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 5));
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, 6));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list_end(ctx));
|
||||
EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
|
||||
expected_len = sizeof(uint32_t) + 6 *
|
||||
(sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
|
||||
|
||||
return "[1,[2,[3,[4,[5,[6]]]]]]";
|
||||
}
|
||||
|
||||
// make sure all user buffers are flushed
|
||||
static void print_barrier() {
|
||||
std::cout.flush();
|
||||
fflush(stdout);
|
||||
std::cerr.flush();
|
||||
fflush(stderr); // everything else is paranoia ...
|
||||
}
|
||||
|
||||
static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
|
||||
struct logger_list *logger_list;
|
||||
|
||||
pid_t pid = getpid();
|
||||
|
||||
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
||||
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
|
||||
|
||||
log_time ts(android_log_clockid());
|
||||
|
||||
size_t expected_len;
|
||||
const char *expected_string = (*fn)(1005, expected_len);
|
||||
|
||||
if (!expected_string) {
|
||||
android_logger_list_close(logger_list);
|
||||
return;
|
||||
}
|
||||
|
||||
usleep(1000000);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (;;) {
|
||||
log_msg log_msg;
|
||||
if (android_logger_list_read(logger_list, &log_msg) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT_EQ(log_msg.entry.pid, pid);
|
||||
|
||||
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|
||||
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
|
||||
|| ((size_t)log_msg.entry.len != expected_len)
|
||||
|| (log_msg.id() != LOG_ID_EVENTS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *eventData = log_msg.msg();
|
||||
|
||||
++count;
|
||||
|
||||
AndroidLogFormat *logformat = android_log_format_new();
|
||||
EXPECT_TRUE(NULL != logformat);
|
||||
AndroidLogEntry entry;
|
||||
char msgBuf[1024];
|
||||
int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
|
||||
&log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
|
||||
EXPECT_EQ(0, processBinaryLogBuffer);
|
||||
if (processBinaryLogBuffer == 0) {
|
||||
print_barrier();
|
||||
int printLogLine = android_log_printLogLine(
|
||||
logformat, fileno(stderr), &entry);
|
||||
print_barrier();
|
||||
EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
|
||||
}
|
||||
android_log_format_free(logformat);
|
||||
|
||||
// test buffer reading API
|
||||
snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
|
||||
print_barrier();
|
||||
fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
|
||||
memset(msgBuf, 0, sizeof(msgBuf));
|
||||
int buffer_to_string = android_log_buffer_to_string(
|
||||
eventData + sizeof(uint32_t),
|
||||
log_msg.entry.len - sizeof(uint32_t),
|
||||
msgBuf, sizeof(msgBuf));
|
||||
fprintf(stderr, "%s\n", msgBuf);
|
||||
print_barrier();
|
||||
EXPECT_EQ(0, buffer_to_string);
|
||||
EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
|
||||
EXPECT_EQ(0, strcmp(expected_string, msgBuf));
|
||||
}
|
||||
|
||||
EXPECT_EQ(1, count);
|
||||
|
||||
android_logger_list_close(logger_list);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_int32) {
|
||||
create_android_logger(event_test_int32);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_int64) {
|
||||
create_android_logger(event_test_int64);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_list_int64) {
|
||||
create_android_logger(event_test_list_int64);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_simple_automagic_list) {
|
||||
create_android_logger(event_test_simple_automagic_list);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_list_empty) {
|
||||
create_android_logger(event_test_list_empty);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_complex_nested_list) {
|
||||
create_android_logger(event_test_complex_nested_list);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_7_level_prefix) {
|
||||
create_android_logger(event_test_7_level_prefix);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_7_level_suffix) {
|
||||
create_android_logger(event_test_7_level_suffix);
|
||||
}
|
||||
|
||||
TEST(liblog, create_android_logger_overflow) {
|
||||
android_log_context ctx;
|
||||
|
||||
EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
|
||||
if (ctx) {
|
||||
for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
}
|
||||
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
||||
/* One more for good measure, must be permanently unhappy */
|
||||
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
EXPECT_TRUE(NULL == ctx);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
|
||||
for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
|
||||
EXPECT_LE(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_write_int32(ctx, i));
|
||||
}
|
||||
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
||||
/* One more for good measure, must be permanently unhappy */
|
||||
EXPECT_GT(0, android_log_write_list_begin(ctx));
|
||||
EXPECT_LE(0, android_log_destroy(&ctx));
|
||||
ASSERT_TRUE(NULL == ctx);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue