blob: 53f00b6b23282df341e452e0437b2760e36a41a4 [file] [log] [blame]
/*
* 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.
*/
#ifndef ANDROID_MEDIA_NBLOG_ENTRY_H
#define ANDROID_MEDIA_NBLOG_ENTRY_H
#include <memory>
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
#include <media/nblog/Events.h>
class audio_utils_fifo_writer;
namespace android {
namespace NBLog {
// 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];
};
// representation of a single log entry in shared memory
// byte[0] mEvent
// byte[1] mLength
// byte[2] mData[0]
// ...
// byte[2+i] mData[i]
// ...
// byte[2+mLength-1] mData[mLength-1]
// byte[2+mLength] duplicate copy of mLength to permit reverse scan
// byte[3+mLength] start of next log entry
class Entry {
public:
Entry(Event event, const void *data, size_t length)
: mEvent(event), mLength(length), mData(data) {}
~Entry() {}
// used during writing to format Entry information as follows:
// [type][length][data ... ][length]
int copyEntryDataAt(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(entry) + sizeof(ending);
// endind length of previous entry
static const ssize_t kPreviousLengthOffset = - sizeof(ending) +
offsetof(ending, length);
};
// entry iterator
class EntryIterator {
public:
// Used for dummy initialization. Performing operations on a default-constructed
// EntryIterator other than assigning it to another valid EntryIterator
// is undefined behavior.
EntryIterator();
// Caller's responsibility to make sure entry is not nullptr.
// Passing in nullptr can result in undefined behavior.
explicit EntryIterator(const uint8_t *entry);
EntryIterator(const EntryIterator &other);
// dereference underlying entry
const entry& operator*() const;
const entry* operator->() const;
// advance to next entry
EntryIterator& operator++(); // ++i
// back to previous entry
EntryIterator& operator--(); // --i
// returns an EntryIterator corresponding to the next entry
EntryIterator next() const;
// returns an EntryIterator corresponding to the previous entry
EntryIterator prev() const;
bool operator!=(const EntryIterator &other) const;
int operator-(const EntryIterator &other) const;
bool hasConsistentLength() const;
void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
void copyData(uint8_t *dst) const;
// memcpy preferred to reinterpret_cast to avoid potentially unsupported
// unaligned memory access.
#if 0
template<typename T>
inline const T& payload() {
return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
}
#else
template<typename T>
inline T payload() const {
static_assert(std::is_trivially_copyable<T>::value
&& !std::is_pointer<T>::value,
"NBLog::EntryIterator payload must be trivially copyable, non-pointer type.");
T payload;
memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload));
return payload;
}
#endif
inline operator const uint8_t*() const {
return mPtr;
}
private:
const uint8_t *mPtr; // Should not be nullptr except for dummy initialization
};
// ---------------------------------------------------------------------------
// The following classes are used for merging into the Merger's buffer.
class AbstractEntry {
public:
virtual ~AbstractEntry() {}
// build concrete entry of appropriate class from ptr.
static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
// get format entry timestamp
virtual int64_t timestamp() const = 0;
// get format entry's unique id
virtual log_hash_t hash() const = 0;
// 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
// TODO consider changing to uint32_t
virtual int author() const = 0;
// copy entry, adding author before timestamp, returns iterator to end of entry
virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
int author) const = 0;
protected:
// Entry starting in the given pointer, which shall not be nullptr.
explicit AbstractEntry(const uint8_t *entry) : mEntry(entry) {}
// copies ordinary entry from src to dst, and returns length of entry
// size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
const uint8_t * const mEntry;
};
// API for handling format entry operations
// a formatted entry has the following structure:
// * FMT_START entry, containing the format string
// * TIMESTAMP entry
// * HASH entry
// * author entry of the thread that generated it (optional, present in merged log)
// * format arg1
// * format arg2
// * ...
// * FMT_END entry
class FormatEntry : public AbstractEntry {
public:
// explicit FormatEntry(const EntryIterator &it);
explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
~FormatEntry() override = default;
EntryIterator begin() const;
// Entry's format string
const char* formatString() const;
// Enrty's format string length
size_t formatStringLength() const;
// Format arguments (excluding format string, timestamp and author)
EntryIterator args() const;
// get format entry timestamp
int64_t timestamp() const override;
// get format entry's unique id
log_hash_t hash() const override;
// 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 override;
// copy entry, adding author before timestamp, returns size of original entry
EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
int author) const override;
};
class HistogramEntry : public AbstractEntry {
public:
explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
~HistogramEntry() override = default;
int64_t timestamp() const override;
log_hash_t hash() const override;
int author() const override;
EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
int author) const override;
};
} // namespace NBLog
} // namespace android
#endif // ANDROID_MEDIA_NBLOG_ENTRY_H