Loading include/media/nbaio/NBLog.h +85 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading media/libnbaio/NBLog.cpp +135 −86 Original line number Diff line number Diff line Loading @@ -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]; } // --------------------------------------------------------------------------- Loading Loading @@ -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 Loading @@ -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; } Loading @@ -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; Loading @@ -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), ×tamp, &body); // right now, this is the only supported case entry = handleFormat(FormatEntry(entry), ×tamp, &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); Loading Loading @@ -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(); Loading @@ -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 Loading Loading @@ -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; } // --------------------------------------------------------------------------- Loading Loading
include/media/nbaio/NBLog.h +85 −32 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading
media/libnbaio/NBLog.cpp +135 −86 Original line number Diff line number Diff line Loading @@ -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]; } // --------------------------------------------------------------------------- Loading Loading @@ -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 Loading @@ -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; } Loading @@ -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; Loading @@ -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), ×tamp, &body); // right now, this is the only supported case entry = handleFormat(FormatEntry(entry), ×tamp, &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); Loading Loading @@ -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(); Loading @@ -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 Loading Loading @@ -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; } // --------------------------------------------------------------------------- Loading