1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_MEDIA_NBLOG_ENTRY_H 18 #define ANDROID_MEDIA_NBLOG_ENTRY_H 19 20 #include <memory> 21 #include <stddef.h> 22 #include <stdint.h> 23 #include <type_traits> 24 25 #include <media/nblog/Events.h> 26 27 class audio_utils_fifo_writer; 28 29 namespace android { 30 namespace NBLog { 31 32 // entry representation in memory 33 struct entry { 34 const uint8_t type; 35 const uint8_t length; 36 const uint8_t data[0]; 37 }; 38 39 // entry tail representation (after data) 40 struct ending { 41 uint8_t length; 42 uint8_t next[0]; 43 }; 44 45 // representation of a single log entry in shared memory 46 // byte[0] mEvent 47 // byte[1] mLength 48 // byte[2] mData[0] 49 // ... 50 // byte[2+i] mData[i] 51 // ... 52 // byte[2+mLength-1] mData[mLength-1] 53 // byte[2+mLength] duplicate copy of mLength to permit reverse scan 54 // byte[3+mLength] start of next log entry 55 class Entry { 56 public: Entry(Event event,const void * data,size_t length)57 Entry(Event event, const void *data, size_t length) 58 : mEvent(event), mLength(length), mData(data) {} ~Entry()59 ~Entry() {} 60 61 // used during writing to format Entry information as follows: 62 // [type][length][data ... ][length] 63 int copyEntryDataAt(size_t offset) const; 64 65 private: 66 friend class Writer; 67 Event mEvent; // event type 68 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength 69 const void *mData; // event type-specific data 70 static const size_t kMaxLength = 255; 71 public: 72 // mEvent, mLength, mData[...], duplicate mLength 73 static const size_t kOverhead = sizeof(entry) + sizeof(ending); 74 // endind length of previous entry 75 static const ssize_t kPreviousLengthOffset = - sizeof(ending) + 76 offsetof(ending, length); 77 }; 78 79 // entry iterator 80 class EntryIterator { 81 public: 82 // Used for dummy initialization. Performing operations on a default-constructed 83 // EntryIterator other than assigning it to another valid EntryIterator 84 // is undefined behavior. 85 EntryIterator(); 86 // Caller's responsibility to make sure entry is not nullptr. 87 // Passing in nullptr can result in undefined behavior. 88 explicit EntryIterator(const uint8_t *entry); 89 EntryIterator(const EntryIterator &other); 90 91 // dereference underlying entry 92 const entry& operator*() const; 93 const entry* operator->() const; 94 // advance to next entry 95 EntryIterator& operator++(); // ++i 96 // back to previous entry 97 EntryIterator& operator--(); // --i 98 // returns an EntryIterator corresponding to the next entry 99 EntryIterator next() const; 100 // returns an EntryIterator corresponding to the previous entry 101 EntryIterator prev() const; 102 bool operator!=(const EntryIterator &other) const; 103 int operator-(const EntryIterator &other) const; 104 105 bool hasConsistentLength() const; 106 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const; 107 void copyData(uint8_t *dst) const; 108 109 // memcpy preferred to reinterpret_cast to avoid potentially unsupported 110 // unaligned memory access. 111 #if 0 112 template<typename T> 113 inline const T& payload() { 114 return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data)); 115 } 116 #else 117 template<typename T> payload()118 inline T payload() const { 119 static_assert(std::is_trivially_copyable<T>::value 120 && !std::is_pointer<T>::value, 121 "NBLog::EntryIterator payload must be trivially copyable, non-pointer type."); 122 T payload; 123 memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload)); 124 return payload; 125 } 126 #endif 127 128 inline operator const uint8_t*() const { 129 return mPtr; 130 } 131 132 private: 133 const uint8_t *mPtr; // Should not be nullptr except for dummy initialization 134 }; 135 136 // --------------------------------------------------------------------------- 137 // The following classes are used for merging into the Merger's buffer. 138 139 class AbstractEntry { 140 public: ~AbstractEntry()141 virtual ~AbstractEntry() {} 142 143 // build concrete entry of appropriate class from ptr. 144 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr); 145 146 // get format entry timestamp 147 virtual int64_t timestamp() const = 0; 148 149 // get format entry's unique id 150 virtual log_hash_t hash() const = 0; 151 152 // entry's author index (-1 if none present) 153 // a Merger has a vector of Readers, author simply points to the index of the 154 // Reader that originated the entry 155 // TODO consider changing to uint32_t 156 virtual int author() const = 0; 157 158 // copy entry, adding author before timestamp, returns iterator to end of entry 159 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, 160 int author) const = 0; 161 162 protected: 163 // Entry starting in the given pointer, which shall not be nullptr. AbstractEntry(const uint8_t * entry)164 explicit AbstractEntry(const uint8_t *entry) : mEntry(entry) {} 165 // copies ordinary entry from src to dst, and returns length of entry 166 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it); 167 const uint8_t * const mEntry; 168 }; 169 170 // API for handling format entry operations 171 172 // a formatted entry has the following structure: 173 // * FMT_START entry, containing the format string 174 // * TIMESTAMP entry 175 // * HASH entry 176 // * author entry of the thread that generated it (optional, present in merged log) 177 // * format arg1 178 // * format arg2 179 // * ... 180 // * FMT_END entry 181 class FormatEntry : public AbstractEntry { 182 public: 183 // explicit FormatEntry(const EntryIterator &it); FormatEntry(const uint8_t * ptr)184 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {} 185 ~FormatEntry() override = default; 186 187 EntryIterator begin() const; 188 189 // Entry's format string 190 const char* formatString() const; 191 192 // Enrty's format string length 193 size_t formatStringLength() const; 194 195 // Format arguments (excluding format string, timestamp and author) 196 EntryIterator args() const; 197 198 // get format entry timestamp 199 int64_t timestamp() const override; 200 201 // get format entry's unique id 202 log_hash_t hash() const override; 203 204 // entry's author index (-1 if none present) 205 // a Merger has a vector of Readers, author simply points to the index of the 206 // Reader that originated the entry 207 int author() const override; 208 209 // copy entry, adding author before timestamp, returns size of original entry 210 EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, 211 int author) const override; 212 }; 213 214 class HistogramEntry : public AbstractEntry { 215 public: HistogramEntry(const uint8_t * ptr)216 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {} 217 ~HistogramEntry() override = default; 218 219 int64_t timestamp() const override; 220 221 log_hash_t hash() const override; 222 223 int author() const override; 224 225 EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, 226 int author) const override; 227 }; 228 229 } // namespace NBLog 230 } // namespace android 231 232 #endif // ANDROID_MEDIA_NBLOG_ENTRY_H 233