You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
6.7 KiB
263 lines
6.7 KiB
/*
|
|
* 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
|