blob: 403f6925f6800b21170a66fd28fa6e873ff11014 [file] [log] [blame]
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001/*
2 * Copyright (C) 2013 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// Non-blocking event logger intended for safe communication between processes via shared memory
18
19#ifndef ANDROID_MEDIA_NBLOG_H
20#define ANDROID_MEDIA_NBLOG_H
21
22#include <binder/IMemory.h>
Glenn Kasten535e1612016-12-05 12:19:36 -080023#include <audio_utils/fifo.h>
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080024#include <utils/Mutex.h>
25#include <utils/threads.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080026
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070027#include <set>
Nicolas Roulet40a44982017-02-03 13:39:57 -080028#include <vector>
29
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080030namespace android {
31
Glenn Kasten4e01ef62013-07-11 14:29:59 -070032class String8;
33
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080034class NBLog {
35
36public:
37
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070038typedef uint64_t log_hash_t;
39
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080040class Writer;
41class Reader;
42
43private:
44
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070045enum Event : uint8_t {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080046 EVENT_RESERVED,
47 EVENT_STRING, // ASCII string, not NUL-terminated
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080048 // TODO: make timestamp optional
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080049 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080050 EVENT_INTEGER, // integer value entry
51 EVENT_FLOAT, // floating point value entry
52 EVENT_PID, // process ID and process name
53 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080054 EVENT_START_FMT, // logFormat start event: entry includes format string, following
55 // entries contain format arguments
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070056 EVENT_HASH, // unique HASH of log origin, originates from hash of file name
57 // and line number
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070058 EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
59 EVENT_HISTOGRAM_FLUSH, // show histogram on log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080060 EVENT_END_FMT, // end of logFormat argument list
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070061
62 EVENT_UPPER_BOUND, // to check for invalid events
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080063};
64
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080065
66// ---------------------------------------------------------------------------
67// API for handling format entry operations
68
69// a formatted entry has the following structure:
70// * START_FMT entry, containing the format string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080071// * TIMESTAMP entry
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070072// * HASH entry
Nicolas Roulet1ca75122017-03-16 14:19:59 -070073// * author entry of the thread that generated it (optional, present in merged log)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080074// * format arg1
75// * format arg2
76// * ...
77// * END_FMT entry
78
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070079// entry representation in memory
80struct entry {
81 const uint8_t type;
82 const uint8_t length;
83 const uint8_t data[0];
84};
85
86// entry tail representation (after data)
87struct ending {
88 uint8_t length;
89 uint8_t next[0];
90};
91
92// entry iterator
93class EntryIterator {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080094public:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070095 EntryIterator();
96 explicit EntryIterator(const uint8_t *entry);
97 EntryIterator(const EntryIterator &other);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080098
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070099 // dereference underlying entry
100 const entry& operator*() const;
101 const entry* operator->() const;
102 // advance to next entry
103 EntryIterator& operator++(); // ++i
104 // back to previous entry
105 EntryIterator& operator--(); // --i
106 EntryIterator next() const;
107 EntryIterator prev() const;
108 bool operator!=(const EntryIterator &other) const;
109 int operator-(const EntryIterator &other) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800110
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700111 bool hasConsistentLength() const;
112 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
113 void copyData(uint8_t *dst) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800114
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700115 template<typename T>
116 inline const T& payload() {
117 return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
118 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800119
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700120 inline operator const uint8_t*() const {
121 return ptr;
122 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800123
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700124private:
125 const uint8_t *ptr;
126};
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800127
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700128class AbstractEntry {
129public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800130
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700131 // Entry starting in the given pointer
132 explicit AbstractEntry(const uint8_t *entry);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800133
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700134 // build concrete entry of appropriate class from pointer
135 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800136
137 // get format entry timestamp
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700138 // TODO consider changing to uint64_t
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700139 virtual int64_t timestamp() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800140
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700141 // get format entry's unique id
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700142 virtual log_hash_t hash() const = 0;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700143
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800144 // entry's author index (-1 if none present)
145 // a Merger has a vector of Readers, author simply points to the index of the
146 // Reader that originated the entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700147 // TODO consider changing to uint32_t
148 virtual int author() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800149
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700150 // copy entry, adding author before timestamp, returns iterator to end of entry
151 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
152 int author) const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800153
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700154protected:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800155 // copies ordinary entry from src to dst, and returns length of entry
156 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
157 const uint8_t *mEntry;
158};
159
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700160class FormatEntry : public AbstractEntry {
161public:
162 // explicit FormatEntry(const EntryIterator &it);
163 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
164
165 // Entry's format string
166 const char* formatString() const;
167
168 // Enrty's format string length
169 size_t formatStringLength() const;
170
171 // Format arguments (excluding format string, timestamp and author)
172 EntryIterator args() const;
173
174 // get format entry timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700175 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700176
177 // get format entry's unique id
178 virtual log_hash_t hash() const override;
179
180 // entry's author index (-1 if none present)
181 // a Merger has a vector of Readers, author simply points to the index of the
182 // Reader that originated the entry
183 virtual int author() const override;
184
185 // copy entry, adding author before timestamp, returns size of original entry
186 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
187 int author) const override;
188
189 EntryIterator begin() const;
190};
191
192class HistogramEntry : public AbstractEntry {
193public:
194 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
195 }
196
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700197 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700198
199 virtual log_hash_t hash() const override;
200
201 virtual int author() const override;
202
203 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
204 int author) const override;
205
206};
207
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800208// ---------------------------------------------------------------------------
209
210// representation of a single log entry in private memory
211struct Entry {
212 Entry(Event event, const void *data, size_t length)
213 : mEvent(event), mLength(length), mData(data) { }
214 /*virtual*/ ~Entry() { }
215
216 int readAt(size_t offset) const;
217
218private:
219 friend class Writer;
220 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800221 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800222 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800223 static const size_t kMaxLength = 255;
224public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800225 // mEvent, mLength, mData[...], duplicate mLength
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700226 static const size_t kOverhead = sizeof(entry) + sizeof(ending);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800227 // endind length of previous entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700228 static const size_t kPreviousLengthOffset = - sizeof(ending) +
229 offsetof(ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800230};
231
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700232struct HistTsEntry {
233 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700234 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700235}; //TODO __attribute__((packed));
236
237struct HistTsEntryWithAuthor {
238 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700239 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700240 int author;
241}; //TODO __attribute__((packed));
242
243struct HistIntEntry {
244 log_hash_t hash;
245 int value;
246}; //TODO __attribute__((packed));
247
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800248// representation of a single log entry in shared memory
249// byte[0] mEvent
250// byte[1] mLength
251// byte[2] mData[0]
252// ...
253// byte[2+i] mData[i]
254// ...
255// byte[2+mLength-1] mData[mLength-1]
256// byte[2+mLength] duplicate copy of mLength to permit reverse scan
257// byte[3+mLength] start of next log entry
258
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800259 static void appendInt(String8 *body, const void *data);
260 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800261 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800262 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800263 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700264 static String8 bufferDump(const uint8_t *buffer, size_t size);
265 static String8 bufferDump(const EntryIterator &it);
Glenn Kasten535e1612016-12-05 12:19:36 -0800266public:
267
268// Located in shared memory, must be POD.
269// Exactly one process must explicitly call the constructor or use placement new.
270// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800271struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800272 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800273 /*virtual*/ ~Shared() { }
274
Glenn Kasten535e1612016-12-05 12:19:36 -0800275 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
276 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800277};
278
279public:
280
281// ---------------------------------------------------------------------------
282
283// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
284// For now it is just a namespace for sharedSize().
285class Timeline : public RefBase {
286public:
287#if 0
288 Timeline(size_t size, void *shared = NULL);
289 virtual ~Timeline();
290#endif
291
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700292 // Input parameter 'size' is the desired size of the timeline in byte units.
293 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800294 static size_t sharedSize(size_t size);
295
296#if 0
297private:
298 friend class Writer;
299 friend class Reader;
300
301 const size_t mSize; // circular buffer size in bytes, must be a power of 2
302 bool mOwn; // whether I own the memory at mShared
303 Shared* const mShared; // pointer to shared memory
304#endif
305};
306
307// ---------------------------------------------------------------------------
308
309// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
310// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
311class Writer : public RefBase {
312public:
313 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700314
315 // Input parameter 'size' is the desired size of the timeline in byte units.
316 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800317 Writer(void *shared, size_t size);
318 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700319
Glenn Kasten535e1612016-12-05 12:19:36 -0800320 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800321
322 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800323 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800324 virtual void logvf(const char *fmt, va_list ap);
325 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700326 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800327 virtual void logInteger(const int x);
328 virtual void logFloat(const float x);
329 virtual void logPID();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700330 virtual void logFormat(const char *fmt, log_hash_t hash, ...);
331 virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800332 virtual void logStart(const char *fmt);
333 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700334 virtual void logHash(log_hash_t hash);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700335 virtual void logHistTS(log_hash_t hash);
336 virtual void logHistFlush(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800337
338 virtual bool isEnabled() const;
339
340 // return value for all of these is the previous isEnabled()
341 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
342 bool enable() { return setEnabled(true); }
343 bool disable() { return setEnabled(false); }
344
345 sp<IMemory> getIMemory() const { return mIMemory; }
346
347private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800348 // 0 <= length <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800349 void log(Event event, const void *data, size_t length);
350 void log(const Entry *entry, bool trusted = false);
351
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800352 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800353 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
354 audio_utils_fifo * const mFifo; // FIFO itself,
355 // non-NULL unless constructor fails
356 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
357 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800358 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800359
360 // cached pid and process name to use in %p format specifier
361 // total tag length is mPidTagSize and process name is not zero terminated
362 char *mPidTag;
363 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800364};
365
366// ---------------------------------------------------------------------------
367
368// Similar to Writer, but safe for multiple threads to call concurrently
369class LockedWriter : public Writer {
370public:
371 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800372 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800373
374 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800375 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800376 virtual void logvf(const char *fmt, va_list ap);
377 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700378 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800379 virtual void logInteger(const int x);
380 virtual void logFloat(const float x);
381 virtual void logPID();
382 virtual void logStart(const char *fmt);
383 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700384 virtual void logHash(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800385
386 virtual bool isEnabled() const;
387 virtual bool setEnabled(bool enabled);
388
389private:
390 mutable Mutex mLock;
391};
392
393// ---------------------------------------------------------------------------
394
395class Reader : public RefBase {
396public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700397
Nicolas Roulet40a44982017-02-03 13:39:57 -0800398 // A snapshot of a readers buffer
399 class Snapshot {
400 public:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800401 Snapshot() : mData(NULL), mLost(0) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800402
403 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
404
405 ~Snapshot() { delete[] mData; }
406
407 // copy of the buffer
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800408 uint8_t *data() const { return mData; }
Nicolas Roulet40a44982017-02-03 13:39:57 -0800409
410 // amount of data lost (given by audio_utils_fifo_reader)
411 size_t lost() const { return mLost; }
412
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800413 // iterator to beginning of readable segment of snapshot
414 // data between begin and end has valid entries
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700415 EntryIterator begin() { return mBegin; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800416
417 // iterator to end of readable segment of snapshot
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700418 EntryIterator end() { return mEnd; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800419
420
Nicolas Roulet40a44982017-02-03 13:39:57 -0800421 private:
422 friend class Reader;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800423 uint8_t *mData;
424 size_t mLost;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700425 EntryIterator mBegin;
426 EntryIterator mEnd;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800427 };
428
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700429 // Input parameter 'size' is the desired size of the timeline in byte units.
430 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800431 Reader(const void *shared, size_t size);
432 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700433
Glenn Kasten535e1612016-12-05 12:19:36 -0800434 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800435
Nicolas Roulet40a44982017-02-03 13:39:57 -0800436 // get snapshot of readers fifo buffer, effectively consuming the buffer
437 std::unique_ptr<Snapshot> getSnapshot();
438 // dump a particular snapshot of the reader
439 void dump(int fd, size_t indent, Snapshot & snap);
440 // dump the current content of the reader's buffer
441 void dump(int fd, size_t indent = 0);
442 bool isIMemory(const sp<IMemory>& iMemory) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800443
444private:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700445 static const std::set<Event> startingTypes;
446 static const std::set<Event> endingTypes;
Glenn Kasten535e1612016-12-05 12:19:36 -0800447 /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
448 // declared as const because audio_utils_fifo() constructor
449 sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700450 int mFd; // file descriptor
451 int mIndent; // indentation level
Glenn Kasten535e1612016-12-05 12:19:36 -0800452 audio_utils_fifo * const mFifo; // FIFO itself,
453 // non-NULL unless constructor fails
454 audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
455 // non-NULL unless constructor fails
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700456
457 void dumpLine(const String8& timestamp, String8& body);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800458
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700459 EntryIterator handleFormat(const FormatEntry &fmtEntry,
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800460 String8 *timestamp,
461 String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800462 // dummy method for handling absent author entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700463 virtual void handleAuthor(const AbstractEntry &fmtEntry, String8 *body) {}
464
465 static void drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight = 10);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800466
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800467 // Searches for the last entry of type <type> in the range [front, back)
468 // back has to be entry-aligned. Returns nullptr if none enconuntered.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700469 static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
470 const std::set<Event> &types);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800471
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800472 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
473};
474
Nicolas Roulet40a44982017-02-03 13:39:57 -0800475// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
476class NamedReader {
477public:
478 NamedReader() { mName[0] = '\0'; } // for Vector
479 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
480 mReader(reader)
481 { strlcpy(mName, name, sizeof(mName)); }
482 ~NamedReader() { }
483 const sp<NBLog::Reader>& reader() const { return mReader; }
484 const char* name() const { return mName; }
485
486private:
487 sp<NBLog::Reader> mReader;
488 static const size_t kMaxName = 32;
489 char mName[kMaxName];
490};
491
492// ---------------------------------------------------------------------------
493
494class Merger : public RefBase {
495public:
496 Merger(const void *shared, size_t size);
497
498 virtual ~Merger() {}
499
500 void addReader(const NamedReader &reader);
501 // TODO add removeReader
502 void merge();
503 const std::vector<NamedReader> *getNamedReaders() const;
504private:
505 // vector of the readers the merger is supposed to merge from.
506 // every reader reads from a writer's buffer
507 std::vector<NamedReader> mNamedReaders;
508 uint8_t *mBuffer;
509 Shared * const mShared;
510 std::unique_ptr<audio_utils_fifo> mFifo;
511 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800512};
513
514class MergeReader : public Reader {
515public:
516 MergeReader(const void *shared, size_t size, Merger &merger);
517private:
518 const std::vector<NamedReader> *mNamedReaders;
519 // handle author entry by looking up the author's name and appending it to the body
520 // returns number of bytes read from fmtEntry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700521 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800522};
523
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800524// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
525// when triggered, it awakes for a lapse of time, during which it periodically merges; if
526// retriggered, the timeout is reset.
527// The thread is triggered on AudioFlinger binder activity.
528class MergeThread : public Thread {
529public:
530 MergeThread(Merger &merger);
531 virtual ~MergeThread() override;
532
533 // Reset timeout and activate thread to merge periodically if it's idle
534 void wakeup();
535
536 // Set timeout period until the merging thread goes idle again
537 void setTimeoutUs(int time);
538
539private:
540 virtual bool threadLoop() override;
541
542 // the merger who actually does the work of merging the logs
543 Merger& mMerger;
544
545 // mutex for the condition variable
546 Mutex mMutex;
547
548 // condition variable to activate merging on timeout >= 0
549 Condition mCond;
550
551 // time left until the thread blocks again (in microseconds)
552 int mTimeoutUs;
553
554 // merging period when the thread is awake
555 static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
556
557 // initial timeout value when triggered
558 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
559};
560
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800561}; // class NBLog
562
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700563// TODO put somewhere else
564static inline int64_t get_monotonic_ns() {
565 timespec ts;
566 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
567 return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
568 }
569 return 0; // should not happen.
570}
571
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800572} // namespace android
573
574#endif // ANDROID_MEDIA_NBLOG_H