Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cec3964f authored by Mark Salyzyn's avatar Mark Salyzyn Committed by Gerrit Code Review
Browse files

Merge "liblog: event log list logging handler"

parents 51c38147 bd1ad049
Loading
Loading
Loading
Loading
+90 −28
Original line number Original line Diff line number Diff line
@@ -484,12 +484,16 @@ extern "C" {
 */
 */


/*
/*
 * Event log entry types.  These must match up with the declarations in
 * Event log entry types.
 * java/android/android/util/EventLog.java.
 */
 */
typedef enum {
typedef enum {
    EVENT_TYPE_INT      = 0,
    /* Special markers for android_log_list_element type */
    EVENT_TYPE_LONG     = 1,
    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_STRING    = 2,
    EVENT_TYPE_LIST      = 3,
    EVENT_TYPE_LIST      = 3,
    EVENT_TYPE_FLOAT     = 4,
    EVENT_TYPE_FLOAT     = 4,
@@ -522,7 +526,85 @@ typedef enum {
#define LOG_EVENT_STRING(_tag, _value)                                      \
#define LOG_EVENT_STRING(_tag, _value)                                      \
        (void) __android_log_bswrite(_tag, _value);
        (void) __android_log_bswrite(_tag, _value);
#endif
#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)
    (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
#endif
#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
 * 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
 * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 := 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 += logprint.c
liblog_target_sources += log_read.c
liblog_target_sources += log_read.c
liblog_target_sources += log_event_list.c


# Shared and static library for host
# Shared and static library for host
# ========================================================
# ========================================================
+520 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
}
+527 −1

File changed.

Preview size limit exceeded, changes collapsed.