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 
copyEntryDataAt(size_t offset) const32 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 
EntryIterator()48 EntryIterator::EntryIterator()   // Dummy initialization.
49     : mPtr(nullptr)
50 {
51 }
52 
EntryIterator(const uint8_t * entry)53 EntryIterator::EntryIterator(const uint8_t *entry)
54     : mPtr(entry)
55 {
56 }
57 
EntryIterator(const EntryIterator & other)58 EntryIterator::EntryIterator(const EntryIterator &other)
59     : mPtr(other.mPtr)
60 {
61 }
62 
operator *() const63 const entry& EntryIterator::operator*() const
64 {
65     return *(entry*) mPtr;
66 }
67 
operator ->() const68 const entry* EntryIterator::operator->() const
69 {
70     return (entry*) mPtr;
71 }
72 
operator ++()73 EntryIterator& EntryIterator::operator++()
74 {
75     mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
76     return *this;
77 }
78 
operator --()79 EntryIterator& EntryIterator::operator--()
80 {
81     mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
82     return *this;
83 }
84 
next() const85 EntryIterator EntryIterator::next() const
86 {
87     EntryIterator aux(*this);
88     return ++aux;
89 }
90 
prev() const91 EntryIterator EntryIterator::prev() const
92 {
93     EntryIterator aux(*this);
94     return --aux;
95 }
96 
operator !=(const EntryIterator & other) const97 bool EntryIterator::operator!=(const EntryIterator &other) const
98 {
99     return mPtr != other.mPtr;
100 }
101 
operator -(const EntryIterator & other) const102 int EntryIterator::operator-(const EntryIterator &other) const
103 {
104     return mPtr - other.mPtr;
105 }
106 
hasConsistentLength() const107 bool EntryIterator::hasConsistentLength() const
108 {
109     return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
110         Entry::kOverhead + Entry::kPreviousLengthOffset];
111 }
112 
copyTo(std::unique_ptr<audio_utils_fifo_writer> & dst) const113 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 
copyData(uint8_t * dst) const119 void EntryIterator::copyData(uint8_t *dst) const
120 {
121     memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
122 }
123 
124 // ---------------------------------------------------------------------------
125 
buildEntry(const uint8_t * ptr)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 
begin() const144 EntryIterator FormatEntry::begin() const
145 {
146     return EntryIterator(mEntry);
147 }
148 
formatString() const149 const char *FormatEntry::formatString() const
150 {
151     return (const char*) mEntry + offsetof(entry, data);
152 }
153 
formatStringLength() const154 size_t FormatEntry::formatStringLength() const
155 {
156     return mEntry[offsetof(entry, length)];
157 }
158 
args() const159 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 
timestamp() const172 int64_t FormatEntry::timestamp() const
173 {
174     auto it = begin();
175     ++it; // skip start fmt
176     return it.payload<int64_t>();
177 }
178 
hash() const179 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 
author() const190 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 
copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> & dst,int author) const200 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 
timestamp() const225 int64_t HistogramEntry::timestamp() const
226 {
227     return EntryIterator(mEntry).payload<HistTsEntry>().ts;
228 }
229 
hash() const230 log_hash_t HistogramEntry::hash() const
231 {
232     return EntryIterator(mEntry).payload<HistTsEntry>().hash;
233 }
234 
author() const235 int HistogramEntry::author() const
236 {
237     EntryIterator it(mEntry);
238     return it->length == sizeof(HistTsEntryWithAuthor)
239             ? it.payload<HistTsEntryWithAuthor>().author : -1;
240 }
241 
copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> & dst,int author) const242 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