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 #define LOG_TAG "NBLog" 18 //#define LOG_NDEBUG 0 19 20 #include <memory> 21 #include <stddef.h> 22 #include <stdint.h> 23 24 #include <audio_utils/fifo.h> 25 #include <media/nblog/Entry.h> 26 #include <media/nblog/Events.h> 27 #include <utils/Log.h> 28 29 namespace android { 30 namespace NBLog { 31 32 int Entry::copyEntryDataAt(size_t offset) const 33 { 34 // FIXME This is too slow 35 if (offset == 0) { 36 return mEvent; 37 } else if (offset == 1) { 38 return mLength; 39 } else if (offset < (size_t) (mLength + 2)) { 40 return (int) ((char *) mData)[offset - 2]; 41 } else if (offset == (size_t) (mLength + 2)) { 42 return mLength; 43 } else { 44 return 0; // FIXME is this an error? 45 } 46 } 47 48 EntryIterator::EntryIterator() // Dummy initialization. 49 : mPtr(nullptr) 50 { 51 } 52 53 EntryIterator::EntryIterator(const uint8_t *entry) 54 : mPtr(entry) 55 { 56 } 57 58 EntryIterator::EntryIterator(const EntryIterator &other) 59 : mPtr(other.mPtr) 60 { 61 } 62 63 const entry& EntryIterator::operator*() const 64 { 65 return *(entry*) mPtr; 66 } 67 68 const entry* EntryIterator::operator->() const 69 { 70 return (entry*) mPtr; 71 } 72 73 EntryIterator& EntryIterator::operator++() 74 { 75 mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead; 76 return *this; 77 } 78 79 EntryIterator& EntryIterator::operator--() 80 { 81 mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead; 82 return *this; 83 } 84 85 EntryIterator EntryIterator::next() const 86 { 87 EntryIterator aux(*this); 88 return ++aux; 89 } 90 91 EntryIterator EntryIterator::prev() const 92 { 93 EntryIterator aux(*this); 94 return --aux; 95 } 96 97 bool EntryIterator::operator!=(const EntryIterator &other) const 98 { 99 return mPtr != other.mPtr; 100 } 101 102 int EntryIterator::operator-(const EntryIterator &other) const 103 { 104 return mPtr - other.mPtr; 105 } 106 107 bool EntryIterator::hasConsistentLength() const 108 { 109 return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] + 110 Entry::kOverhead + Entry::kPreviousLengthOffset]; 111 } 112 113 void EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const 114 { 115 size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead; 116 dst->write(mPtr, length); 117 } 118 119 void EntryIterator::copyData(uint8_t *dst) const 120 { 121 memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]); 122 } 123 124 // --------------------------------------------------------------------------- 125 126 std::unique_ptr<AbstractEntry> AbstractEntry::buildEntry(const uint8_t *ptr) 127 { 128 if (ptr == nullptr) { 129 return nullptr; 130 } 131 const uint8_t type = EntryIterator(ptr)->type; 132 switch (type) { 133 case EVENT_FMT_START: 134 return std::make_unique<FormatEntry>(FormatEntry(ptr)); 135 case EVENT_AUDIO_STATE: 136 case EVENT_HISTOGRAM_ENTRY_TS: 137 return std::make_unique<HistogramEntry>(HistogramEntry(ptr)); 138 default: 139 ALOGW("Tried to create AbstractEntry of type %d", type); 140 return nullptr; 141 } 142 } 143 144 EntryIterator FormatEntry::begin() const 145 { 146 return EntryIterator(mEntry); 147 } 148 149 const char *FormatEntry::formatString() const 150 { 151 return (const char*) mEntry + offsetof(entry, data); 152 } 153 154 size_t FormatEntry::formatStringLength() const 155 { 156 return mEntry[offsetof(entry, length)]; 157 } 158 159 EntryIterator FormatEntry::args() const 160 { 161 auto it = begin(); 162 ++it; // skip start fmt 163 ++it; // skip timestamp 164 ++it; // skip hash 165 // Skip author if present 166 if (it->type == EVENT_FMT_AUTHOR) { 167 ++it; 168 } 169 return it; 170 } 171 172 int64_t FormatEntry::timestamp() const 173 { 174 auto it = begin(); 175 ++it; // skip start fmt 176 return it.payload<int64_t>(); 177 } 178 179 log_hash_t FormatEntry::hash() const 180 { 181 auto it = begin(); 182 ++it; // skip start fmt 183 ++it; // skip timestamp 184 // unaligned 64-bit read not supported 185 log_hash_t hash; 186 memcpy(&hash, it->data, sizeof(hash)); 187 return hash; 188 } 189 190 int FormatEntry::author() const 191 { 192 auto it = begin(); 193 ++it; // skip start fmt 194 ++it; // skip timestamp 195 ++it; // skip hash 196 // if there is an author entry, return it, return -1 otherwise 197 return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1; 198 } 199 200 EntryIterator FormatEntry::copyWithAuthor( 201 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const 202 { 203 auto it = begin(); 204 it.copyTo(dst); // copy fmt start entry 205 (++it).copyTo(dst); // copy timestamp 206 (++it).copyTo(dst); // copy hash 207 // insert author entry 208 size_t authorEntrySize = Entry::kOverhead + sizeof(author); 209 uint8_t authorEntry[authorEntrySize]; 210 authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR; 211 authorEntry[offsetof(entry, length)] = 212 authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] = 213 sizeof(author); 214 *(int*) (&authorEntry[offsetof(entry, data)]) = author; 215 dst->write(authorEntry, authorEntrySize); 216 // copy rest of entries 217 while ((++it)->type != EVENT_FMT_END) { 218 it.copyTo(dst); 219 } 220 it.copyTo(dst); 221 ++it; 222 return it; 223 } 224 225 int64_t HistogramEntry::timestamp() const 226 { 227 return EntryIterator(mEntry).payload<HistTsEntry>().ts; 228 } 229 230 log_hash_t HistogramEntry::hash() const 231 { 232 return EntryIterator(mEntry).payload<HistTsEntry>().hash; 233 } 234 235 int HistogramEntry::author() const 236 { 237 EntryIterator it(mEntry); 238 return it->length == sizeof(HistTsEntryWithAuthor) 239 ? it.payload<HistTsEntryWithAuthor>().author : -1; 240 } 241 242 EntryIterator HistogramEntry::copyWithAuthor( 243 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const 244 { 245 // Current histogram entry has {type, length, struct HistTsEntry, length}. 246 // We now want {type, length, struct HistTsEntryWithAuthor, length} 247 uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)]; 248 // Copy content until the point we want to add the author 249 memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry)); 250 // Copy the author 251 *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author; 252 // Update lengths 253 buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor); 254 buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)] 255 = sizeof(HistTsEntryWithAuthor); 256 // Write new buffer into FIFO 257 dst->write(buffer, sizeof(buffer)); 258 return EntryIterator(mEntry).next(); 259 } 260 261 } // namespace NBLog 262 } // namespace android 263