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