blob: e875639b7c65f1900db9f230fac0c9594b4765fb [file] [log] [blame]
Eric Tanace588c2018-09-12 11:44:43 -07001/*
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
29namespace android {
30namespace NBLog {
31
32int 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
48EntryIterator::EntryIterator() // Dummy initialization.
49 : mPtr(nullptr)
50{
51}
52
53EntryIterator::EntryIterator(const uint8_t *entry)
54 : mPtr(entry)
55{
56}
57
58EntryIterator::EntryIterator(const EntryIterator &other)
59 : mPtr(other.mPtr)
60{
61}
62
63const entry& EntryIterator::operator*() const
64{
65 return *(entry*) mPtr;
66}
67
68const entry* EntryIterator::operator->() const
69{
70 return (entry*) mPtr;
71}
72
73EntryIterator& EntryIterator::operator++()
74{
75 mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
76 return *this;
77}
78
79EntryIterator& EntryIterator::operator--()
80{
81 mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
82 return *this;
83}
84
85EntryIterator EntryIterator::next() const
86{
87 EntryIterator aux(*this);
88 return ++aux;
89}
90
91EntryIterator EntryIterator::prev() const
92{
93 EntryIterator aux(*this);
94 return --aux;
95}
96
97bool EntryIterator::operator!=(const EntryIterator &other) const
98{
99 return mPtr != other.mPtr;
100}
101
102int EntryIterator::operator-(const EntryIterator &other) const
103{
104 return mPtr - other.mPtr;
105}
106
107bool EntryIterator::hasConsistentLength() const
108{
109 return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
110 Entry::kOverhead + Entry::kPreviousLengthOffset];
111}
112
113void 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
119void EntryIterator::copyData(uint8_t *dst) const
120{
121 memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
122}
123
124// ---------------------------------------------------------------------------
125
126std::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
144EntryIterator FormatEntry::begin() const
145{
146 return EntryIterator(mEntry);
147}
148
149const char *FormatEntry::formatString() const
150{
151 return (const char*) mEntry + offsetof(entry, data);
152}
153
154size_t FormatEntry::formatStringLength() const
155{
156 return mEntry[offsetof(entry, length)];
157}
158
159EntryIterator 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
172int64_t FormatEntry::timestamp() const
173{
174 auto it = begin();
175 ++it; // skip start fmt
176 return it.payload<int64_t>();
177}
178
179log_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
190int 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
200EntryIterator 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
225int64_t HistogramEntry::timestamp() const
226{
227 return EntryIterator(mEntry).payload<HistTsEntry>().ts;
228}
229
230log_hash_t HistogramEntry::hash() const
231{
232 return EntryIterator(mEntry).payload<HistTsEntry>().hash;
233}
234
235int HistogramEntry::author() const
236{
237 EntryIterator it(mEntry);
238 return it->length == sizeof(HistTsEntryWithAuthor)
239 ? it.payload<HistTsEntryWithAuthor>().author : -1;
240}
241
242EntryIterator 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