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

Commit cd5dd016 authored by Nicolas Roulet's avatar Nicolas Roulet
Browse files

Implement entry iterators

Some code refactoring

Bug: 35329553
Test: manual
Change-Id: I06e4ac1207b5c707d663ab2f141bb08d80272642
parent 40a4498b
Loading
Loading
Loading
Loading
+85 −32
Original line number Diff line number Diff line
@@ -51,25 +51,6 @@ enum Event {
    EVENT_END_FMT,              // end of logFormat argument list
};

// ---------------------------------------------------------------------------

// representation of a single log entry in private memory
struct Entry {
    Entry(Event event, const void *data, size_t length)
        : mEvent(event), mLength(length), mData(data) { }
    /*virtual*/ ~Entry() { }

    int     readAt(size_t offset) const;

private:
    friend class Writer;
    Event       mEvent;     // event type
    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
    const void *mData;      // event type-specific data
    static const size_t kMaxLength = 255;
public:
    static const size_t kOverhead = 3;  // mEvent, mLength, mData[...], duplicate mLength
};

// ---------------------------------------------------------------------------
// API for handling format entry operations
@@ -86,7 +67,52 @@ public:
class FormatEntry {
public:
    // build a Format Entry starting in the given pointer
    class iterator;
    explicit FormatEntry(const uint8_t *entry);
    explicit FormatEntry(const iterator &it);

    // entry representation in memory
    struct entry {
        const uint8_t type;
        const uint8_t length;
        const uint8_t data[0];
    };

    // entry tail representation (after data)
    struct ending {
        uint8_t length;
        uint8_t next[0];
    };

    // entry iterator
    class iterator {
    public:
        iterator(const uint8_t *entry);
        iterator(const iterator &other);

        // dereference underlying entry
        const entry&    operator*() const;
        const entry*    operator->() const;
        // advance to next entry
        iterator&       operator++(); // ++i
        // back to previous entry
        iterator&       operator--(); // --i
        bool            operator!=(const iterator &other) const;
        int             operator-(const iterator &other) const;

        bool            hasConsistentLength() const;
        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
        void            copyData(uint8_t *dst) const;

        template<typename T>
        inline const T& payload() {
            return *reinterpret_cast<const T *>(ptr + 2);
        }

    private:
        friend class FormatEntry;
        const uint8_t  *ptr;
    };

    // Entry's format string
    const char* formatString() const;
@@ -95,25 +121,51 @@ public:
    size_t      formatStringLength() const;

    // Format arguments (excluding format string, timestamp and author)
    const uint8_t  *args() const;
    iterator    args() const;

    // get format entry timestamp
    timespec    timestamp() const;

    // entry's author index (-1 if none present)
    // a Merger has a vector of Readers, author simply points to the index of the
    // Reader that originated the entry
    int         author() const;

    // copy entry, adding author before timestamp, returns size of original entry
    // (intended for merger)
    size_t      copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;

    iterator    begin() const;

private:
    // copies ordinary entry from src to dst, and returns length of entry
    size_t          copyEntry(std::unique_ptr<audio_utils_fifo_writer> &dst, const uint8_t *src)
                        const;

    // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
    const uint8_t  *mEntry;
};

// ---------------------------------------------------------------------------

// representation of a single log entry in private memory
struct Entry {
    Entry(Event event, const void *data, size_t length)
        : mEvent(event), mLength(length), mData(data) { }
    /*virtual*/ ~Entry() { }

    int     readAt(size_t offset) const;

private:
    friend class Writer;
    Event       mEvent;     // event type
    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
    const void *mData;      // event type-specific data
    static const size_t kMaxLength = 255;
public:
    // mEvent, mLength, mData[...], duplicate mLength
    static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
    // endind length of previous entry
    static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
                                                offsetof(FormatEntry::ending, length);
};

// representation of a single log entry in shared memory
//  byte[0]             mEvent
//  byte[1]             mLength
@@ -312,7 +364,8 @@ private:
                                                    // non-NULL unless constructor fails

    void    dumpLine(const String8& timestamp, String8& body);
    int     handleFormat(const FormatEntry &fmtEntry,

    FormatEntry::iterator   handleFormat(const FormatEntry &fmtEntry,
                                         String8 *timestamp,
                                         String8 *body);
    // dummy method for handling absent author entry
+135 −86
Original line number Diff line number Diff line
@@ -51,70 +51,115 @@ int NBLog::Entry::readAt(size_t offset) const
// ---------------------------------------------------------------------------

NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
    ALOGW_IF(entry[0] != EVENT_START_FMT,
             "Created format entry with invalid event type %d",
             entry[0]);
    ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
        "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
}

NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}

const char *NBLog::FormatEntry::formatString() const {
    return (const char*) mEntry + 2;
    return (const char*) mEntry + offsetof(entry, data);
}

size_t NBLog::FormatEntry::formatStringLength() const {
    return mEntry[1];
    return mEntry[offsetof(entry, length)];
}

const uint8_t *NBLog::FormatEntry::args() const {
    const uint8_t *ptr = mEntry + mEntry[1] + NBLog::Entry::kOverhead;
    if (ptr[0] != EVENT_TIMESTAMP) { // skip author if present
        ptr += ptr[1] + NBLog::Entry::kOverhead;
NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
    auto it = begin();
    // Second entry can be author or timestamp. Skip author if present
    if ((++it)->type == EVENT_AUTHOR) {
        ++it;
    }
    return ptr + ptr[1] + NBLog::Entry::kOverhead;
    return ++it;
}

timespec NBLog::FormatEntry::timestamp() const {
    const uint8_t *ptr = mEntry + mEntry[1] + NBLog::Entry::kOverhead;
    if (ptr[0] != EVENT_TIMESTAMP) { // skip authors if present
        ptr += ptr[1] + NBLog::Entry::kOverhead;
    auto it = begin();
    if ((++it)->type != EVENT_TIMESTAMP) {
        ++it;
    }
    // by this point, we should be standing in the timestamp entry
    return *((struct timespec*) (&ptr[2]));
    return it.payload<timespec>();
}

pid_t NBLog::FormatEntry::author() const {
    size_t authorOffset = mEntry[1] + NBLog::Entry::kOverhead;
    // return -1 if the entry has no author
    if (mEntry[authorOffset] != EVENT_AUTHOR) {
        return -1;
    auto it = begin();
    if ((++it)->type == EVENT_AUTHOR) {
        return it.payload<int>();
    }
    return *(pid_t*)(mEntry + authorOffset + 2);
    return -1;
}

size_t NBLog::FormatEntry::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
    auto it = this->begin();
    // copy fmt start entry
    size_t entryOffset = copyEntry(dst, mEntry);
    it.copyTo(dst);
    // insert author entry
    size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
    uint8_t authorEntry[authorEntrySize];
    authorEntry[0] = EVENT_AUTHOR;
    authorEntry[1] = authorEntry[authorEntrySize - 1] = sizeof(author);
    *(int*) (&authorEntry[2]) = author;
    authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
    authorEntry[offsetof(entry, length)] =
        authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
        sizeof(author);
    *(int*) (&authorEntry[offsetof(entry, data)]) = author;
    dst->write(authorEntry, authorEntrySize);
    // copy rest of entries
    Event lastEvent = EVENT_TIMESTAMP;
    while (lastEvent != EVENT_END_FMT) {
        lastEvent = (Event) mEntry[entryOffset];
        entryOffset += copyEntry(dst, mEntry + entryOffset);
    while ((++it)->type != EVENT_END_FMT) {
        it.copyTo(dst);
    }
    it.copyTo(dst);
    ++it;
    return it - this->begin();
}

void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
    size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
    dst->write(ptr, length);
}

void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
    memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
}

NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
    return iterator(mEntry);
}
    return entryOffset;

NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
    : ptr(entry) {}

NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
    : ptr(other.ptr) {}

const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
    return *(entry*) ptr;
}

const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
    return (entry*) ptr;
}

NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
    ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
    return *this;
}

NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
    ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
    return *this;
}

size_t NBLog::FormatEntry::copyEntry(std::unique_ptr<audio_utils_fifo_writer> &dst,
                                     const uint8_t *src) const {
    size_t length = src[1] + NBLog::Entry::kOverhead;
    dst->write(src, length);
    return length;
int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
    return ptr - other.ptr;
}

bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
    return ptr != other.ptr;
}

bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
    return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
        NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
}

// ---------------------------------------------------------------------------
@@ -553,35 +598,34 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()

void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
{
    size_t i = snapshot.available();
    const uint8_t *snapData = snapshot.data();
    Event event;
    size_t length;
    NBLog::FormatEntry::iterator entry(snapshot.data() + snapshot.available());
    NBLog::FormatEntry::iterator prevEntry = entry;
    --prevEntry;
    NBLog::FormatEntry::iterator start(snapshot.data());

    struct timespec ts;
    time_t maxSec = -1;
    while (i >= Entry::kOverhead) {
        length = snapData[i - 1];
        if (length + Entry::kOverhead > i || snapData[i - length - 2] != length) {

    while (entry - start >= (int) Entry::kOverhead) {
        if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
            break;
        }
        event = (Event) snapData[i - length - Entry::kOverhead];
        if (event == EVENT_TIMESTAMP) {
            if (length != sizeof(struct timespec)) {
        if (prevEntry->type == EVENT_TIMESTAMP) {
            if (prevEntry->length != sizeof(struct timespec)) {
                // corrupt
                break;
            }
            memcpy(&ts, &snapData[i - length - 1], sizeof(struct timespec));
            prevEntry.copyData((uint8_t*) &ts);
            if (ts.tv_sec > maxSec) {
                maxSec = ts.tv_sec;
            }
        }
        i -= length + Entry::kOverhead;
        --entry;
        --prevEntry;
    }
    mFd = fd;
    mIndent = indent;
    String8 timestamp, body;
    size_t lost = snapshot.lost() + i;
    size_t lost = snapshot.lost() + (entry - start);
    if (lost > 0) {
        body.appendFormat("warning: lost %zu bytes worth of events", lost);
        // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
@@ -597,30 +641,29 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho
        timestamp.appendFormat("[%*s]", (int) width + 4, "");
    }
    bool deferredTimestamp = false;
    while (i < snapshot.available()) {
        event = (Event) snapData[i];
        length = snapData[i + 1];
        const void *data = &snapData[i + 2];
        size_t advance = length + Entry::kOverhead;
        switch (event) {
    NBLog::FormatEntry::iterator end(snapshot.data() + snapshot.available());

    while (entry != end) {
        switch (entry->type) {
#if 0
        case EVENT_STRING:
            body.appendFormat("%.*s", (int) length, (const char *) data);
            body.appendFormat("%.*s", (int) entry.length(), entry.data());
            break;
        case EVENT_TIMESTAMP: {
            // already checked that length == sizeof(struct timespec);
            memcpy(&ts, data, sizeof(struct timespec));
            entry.copyData((const uint8_t*) &ts);
            long prevNsec = ts.tv_nsec;
            long deltaMin = LONG_MAX;
            long deltaMax = -1;
            long deltaTotal = 0;
            size_t j = i;
            auto aux(entry);
            for (;;) {
                j += sizeof(struct timespec) + 3 /*Entry::kOverhead?*/;
                if (j >= snapshot.available() || (Event) snapData[j] != EVENT_TIMESTAMP) {
                ++aux;
                if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
                    break;
                }
                struct timespec tsNext;
                memcpy(&tsNext, &snapData[j + 2], sizeof(struct timespec));
                aux.copyData((const uint8_t*) &tsNext);
                if (tsNext.tv_sec != ts.tv_sec) {
                    break;
                }
@@ -637,7 +680,7 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho
                deltaTotal += delta;
                prevNsec = tsNext.tv_nsec;
            }
            size_t n = (j - i) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
            size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
            if (deferredTimestamp) {
                dumpLine(timestamp, body);
                deferredTimestamp = false;
@@ -648,35 +691,37 @@ void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapsho
                        (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
                        (int) ((ts.tv_nsec + deltaTotal) / 1000000),
                        (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
                i = j;
                advance = 0;
                entry = aux;
                // advance = 0;
                break;
            }
            timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
                    (int) (ts.tv_nsec / 1000000));
            deferredTimestamp = true;
            } break;
            }
            break;
        case EVENT_INTEGER:
            appendInt(&body, data);
            appendInt(&body, entry.data());
            break;
        case EVENT_FLOAT:
            appendFloat(&body, data);
            appendFloat(&body, entry.data());
            break;
        case EVENT_PID:
            appendPID(&body, data, length);
            appendPID(&body, entry.data(), entry.length());
            break;
#endif
        case EVENT_START_FMT:
            advance += handleFormat(FormatEntry(snapData + i), &timestamp, &body);
            // right now, this is the only supported case
            entry = handleFormat(FormatEntry(entry), &timestamp, &body);
            break;
        case EVENT_END_FMT:
            body.appendFormat("warning: got to end format event");
            break;
        case EVENT_RESERVED:
        default:
            body.appendFormat("warning: unknown event %d", event);
            body.appendFormat("warning: unknown event %d", entry->type);
            break;
        }
        i += advance;

        if (!body.isEmpty()) {
            dumpLine(timestamp, body);
@@ -734,20 +779,20 @@ void NBLog::appendPID(String8 *body, const void* data, size_t length) {
    body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
}

int NBLog::Reader::handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body) {
NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
                                                         String8 *timestamp,
                                                         String8 *body) {
    // log timestamp
    struct timespec ts = fmtEntry.timestamp();
    timestamp->clear();
    timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
                    (int) (ts.tv_nsec / 1000000));
    size_t fullLength = NBLog::Entry::kOverhead + sizeof(ts);

    // log author (if present)
    fullLength += handleAuthor(fmtEntry, body);
    handleAuthor(fmtEntry, body);

    // log string
    const uint8_t *args = fmtEntry.args();
    size_t args_offset = 0;
    NBLog::FormatEntry::iterator arg = fmtEntry.args();

    const char* fmt = fmtEntry.formatString();
    size_t fmt_length = fmtEntry.formatStringLength();
@@ -757,28 +802,33 @@ int NBLog::Reader::handleFormat(const FormatEntry &fmtEntry, String8 *timestamp,
            body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
            continue;
        }
        // case "%%""
        if (fmt[++fmt_offset] == '%') {
            body->append("%");
            continue;
        }
        // case "%\0"
        if (fmt_offset == fmt_length) {
            continue;
        }

        NBLog::Event event = (NBLog::Event) args[args_offset];
        size_t length = args[args_offset + 1];
        NBLog::Event event = (NBLog::Event) arg->type;
        size_t length = arg->length;

        // TODO check length for event type is correct
        if(length != args[args_offset + length + 2]) {
            ALOGW("NBLog Reader received different lengths %zu and %d for event %d", length,
                  args[args_offset + length + 2], event);
        if (!arg.hasConsistentLength()) {
            // TODO: corrupt, resync buffer
            body->append("<invalid entry>");
            ++fmt_offset;
            continue;
        }

        if (event == EVENT_END_FMT) {
            break;
        }

        // TODO: implement more complex formatting such as %.3f
        void * datum = (void*) &args[args_offset + 2]; // pointer to the current event args
        const uint8_t *datum = arg->data; // pointer to the current event args
        switch(fmt[fmt_offset])
        {
        case 's': // string
@@ -814,12 +864,11 @@ int NBLog::Reader::handleFormat(const FormatEntry &fmtEntry, String8 *timestamp,
        default:
            ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
        }

        args_offset += length + Entry::kOverhead;

        ++arg;
    }
    fullLength += args_offset + Entry::kOverhead;
    return fullLength;
    ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
    ++arg;
    return arg;
}

// ---------------------------------------------------------------------------