| /* |
| * Copyright (C) 2018 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. |
| */ |
| |
| #define LOG_TAG "NBLog" |
| //#define LOG_NDEBUG 0 |
| |
| #include <memory> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <audio_utils/fifo.h> |
| #include <media/nblog/Entry.h> |
| #include <media/nblog/Events.h> |
| #include <utils/Log.h> |
| |
| namespace android { |
| namespace NBLog { |
| |
| int Entry::copyEntryDataAt(size_t offset) const |
| { |
| // FIXME This is too slow |
| if (offset == 0) { |
| return mEvent; |
| } else if (offset == 1) { |
| return mLength; |
| } else if (offset < (size_t) (mLength + 2)) { |
| return (int) ((char *) mData)[offset - 2]; |
| } else if (offset == (size_t) (mLength + 2)) { |
| return mLength; |
| } else { |
| return 0; // FIXME is this an error? |
| } |
| } |
| |
| EntryIterator::EntryIterator() // Dummy initialization. |
| : mPtr(nullptr) |
| { |
| } |
| |
| EntryIterator::EntryIterator(const uint8_t *entry) |
| : mPtr(entry) |
| { |
| } |
| |
| EntryIterator::EntryIterator(const EntryIterator &other) |
| : mPtr(other.mPtr) |
| { |
| } |
| |
| const entry& EntryIterator::operator*() const |
| { |
| return *(entry*) mPtr; |
| } |
| |
| const entry* EntryIterator::operator->() const |
| { |
| return (entry*) mPtr; |
| } |
| |
| EntryIterator& EntryIterator::operator++() |
| { |
| mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead; |
| return *this; |
| } |
| |
| EntryIterator& EntryIterator::operator--() |
| { |
| mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead; |
| return *this; |
| } |
| |
| EntryIterator EntryIterator::next() const |
| { |
| EntryIterator aux(*this); |
| return ++aux; |
| } |
| |
| EntryIterator EntryIterator::prev() const |
| { |
| EntryIterator aux(*this); |
| return --aux; |
| } |
| |
| bool EntryIterator::operator!=(const EntryIterator &other) const |
| { |
| return mPtr != other.mPtr; |
| } |
| |
| int EntryIterator::operator-(const EntryIterator &other) const |
| { |
| return mPtr - other.mPtr; |
| } |
| |
| bool EntryIterator::hasConsistentLength() const |
| { |
| return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] + |
| Entry::kOverhead + Entry::kPreviousLengthOffset]; |
| } |
| |
| void EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const |
| { |
| size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead; |
| dst->write(mPtr, length); |
| } |
| |
| void EntryIterator::copyData(uint8_t *dst) const |
| { |
| memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]); |
| } |
| |
| // --------------------------------------------------------------------------- |
| |
| std::unique_ptr<AbstractEntry> AbstractEntry::buildEntry(const uint8_t *ptr) |
| { |
| if (ptr == nullptr) { |
| return nullptr; |
| } |
| const uint8_t type = EntryIterator(ptr)->type; |
| switch (type) { |
| case EVENT_FMT_START: |
| return std::make_unique<FormatEntry>(FormatEntry(ptr)); |
| case EVENT_AUDIO_STATE: |
| case EVENT_HISTOGRAM_ENTRY_TS: |
| return std::make_unique<HistogramEntry>(HistogramEntry(ptr)); |
| default: |
| ALOGW("Tried to create AbstractEntry of type %d", type); |
| return nullptr; |
| } |
| } |
| |
| EntryIterator FormatEntry::begin() const |
| { |
| return EntryIterator(mEntry); |
| } |
| |
| const char *FormatEntry::formatString() const |
| { |
| return (const char*) mEntry + offsetof(entry, data); |
| } |
| |
| size_t FormatEntry::formatStringLength() const |
| { |
| return mEntry[offsetof(entry, length)]; |
| } |
| |
| EntryIterator FormatEntry::args() const |
| { |
| auto it = begin(); |
| ++it; // skip start fmt |
| ++it; // skip timestamp |
| ++it; // skip hash |
| // Skip author if present |
| if (it->type == EVENT_FMT_AUTHOR) { |
| ++it; |
| } |
| return it; |
| } |
| |
| int64_t FormatEntry::timestamp() const |
| { |
| auto it = begin(); |
| ++it; // skip start fmt |
| return it.payload<int64_t>(); |
| } |
| |
| log_hash_t FormatEntry::hash() const |
| { |
| auto it = begin(); |
| ++it; // skip start fmt |
| ++it; // skip timestamp |
| // unaligned 64-bit read not supported |
| log_hash_t hash; |
| memcpy(&hash, it->data, sizeof(hash)); |
| return hash; |
| } |
| |
| int FormatEntry::author() const |
| { |
| auto it = begin(); |
| ++it; // skip start fmt |
| ++it; // skip timestamp |
| ++it; // skip hash |
| // if there is an author entry, return it, return -1 otherwise |
| return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1; |
| } |
| |
| EntryIterator FormatEntry::copyWithAuthor( |
| std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const |
| { |
| auto it = begin(); |
| it.copyTo(dst); // copy fmt start entry |
| (++it).copyTo(dst); // copy timestamp |
| (++it).copyTo(dst); // copy hash |
| // insert author entry |
| size_t authorEntrySize = Entry::kOverhead + sizeof(author); |
| uint8_t authorEntry[authorEntrySize]; |
| authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR; |
| authorEntry[offsetof(entry, length)] = |
| authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] = |
| sizeof(author); |
| *(int*) (&authorEntry[offsetof(entry, data)]) = author; |
| dst->write(authorEntry, authorEntrySize); |
| // copy rest of entries |
| while ((++it)->type != EVENT_FMT_END) { |
| it.copyTo(dst); |
| } |
| it.copyTo(dst); |
| ++it; |
| return it; |
| } |
| |
| int64_t HistogramEntry::timestamp() const |
| { |
| return EntryIterator(mEntry).payload<HistTsEntry>().ts; |
| } |
| |
| log_hash_t HistogramEntry::hash() const |
| { |
| return EntryIterator(mEntry).payload<HistTsEntry>().hash; |
| } |
| |
| int HistogramEntry::author() const |
| { |
| EntryIterator it(mEntry); |
| return it->length == sizeof(HistTsEntryWithAuthor) |
| ? it.payload<HistTsEntryWithAuthor>().author : -1; |
| } |
| |
| EntryIterator HistogramEntry::copyWithAuthor( |
| std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const |
| { |
| // Current histogram entry has {type, length, struct HistTsEntry, length}. |
| // We now want {type, length, struct HistTsEntryWithAuthor, length} |
| uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)]; |
| // Copy content until the point we want to add the author |
| memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry)); |
| // Copy the author |
| *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author; |
| // Update lengths |
| buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor); |
| buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)] |
| = sizeof(HistTsEntryWithAuthor); |
| // Write new buffer into FIFO |
| dst->write(buffer, sizeof(buffer)); |
| return EntryIterator(mEntry).next(); |
| } |
| |
| } // namespace NBLog |
| } // namespace android |