Home | History | Annotate | Download | only in nblog
      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:
     57     Entry(Event event, const void *data, size_t length)
     58         : mEvent(event), mLength(length), mData(data) {}
     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>
    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:
    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.
    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);
    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:
    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