Home | History | Annotate | Download | only in libnblog
      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