blob: 2068a94689571eaa0a1c6bdba61f3288668a833d [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 Rouletad82aa62017-04-03 19:15:20 -070027#include <map>
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070028#include <set>
Nicolas Roulet40a44982017-02-03 13:39:57 -080029#include <vector>
30
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080031namespace android {
32
Glenn Kasten4e01ef62013-07-11 14:29:59 -070033class String8;
34
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080035class NBLog {
36
37public:
38
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070039typedef uint64_t log_hash_t;
40
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080041class Writer;
42class Reader;
43
44private:
45
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070046enum Event : uint8_t {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080047 EVENT_RESERVED,
48 EVENT_STRING, // ASCII string, not NUL-terminated
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080049 // TODO: make timestamp optional
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080050 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080051 EVENT_INTEGER, // integer value entry
52 EVENT_FLOAT, // floating point value entry
53 EVENT_PID, // process ID and process name
54 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080055 EVENT_START_FMT, // logFormat start event: entry includes format string, following
56 // entries contain format arguments
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070057 EVENT_HASH, // unique HASH of log origin, originates from hash of file name
58 // and line number
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070059 EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
60 EVENT_HISTOGRAM_FLUSH, // show histogram on log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080061 EVENT_END_FMT, // end of logFormat argument list
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070062
63 EVENT_UPPER_BOUND, // to check for invalid events
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080064};
65
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080066
67// ---------------------------------------------------------------------------
68// API for handling format entry operations
69
70// a formatted entry has the following structure:
71// * START_FMT entry, containing the format string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080072// * TIMESTAMP entry
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070073// * HASH entry
Nicolas Roulet1ca75122017-03-16 14:19:59 -070074// * author entry of the thread that generated it (optional, present in merged log)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080075// * format arg1
76// * format arg2
77// * ...
78// * END_FMT entry
79
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070080// entry representation in memory
81struct entry {
82 const uint8_t type;
83 const uint8_t length;
84 const uint8_t data[0];
85};
86
87// entry tail representation (after data)
88struct ending {
89 uint8_t length;
90 uint8_t next[0];
91};
92
93// entry iterator
94class EntryIterator {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080095public:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070096 EntryIterator();
97 explicit EntryIterator(const uint8_t *entry);
98 EntryIterator(const EntryIterator &other);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080099
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700100 // dereference underlying entry
101 const entry& operator*() const;
102 const entry* operator->() const;
103 // advance to next entry
104 EntryIterator& operator++(); // ++i
105 // back to previous entry
106 EntryIterator& operator--(); // --i
107 EntryIterator next() const;
108 EntryIterator prev() const;
109 bool operator!=(const EntryIterator &other) const;
110 int operator-(const EntryIterator &other) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800111
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700112 bool hasConsistentLength() const;
113 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
114 void copyData(uint8_t *dst) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800115
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700116 template<typename T>
117 inline const T& payload() {
118 return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
119 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800120
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700121 inline operator const uint8_t*() const {
122 return ptr;
123 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800124
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700125private:
126 const uint8_t *ptr;
127};
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800128
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700129class AbstractEntry {
130public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800131
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700132 // Entry starting in the given pointer
133 explicit AbstractEntry(const uint8_t *entry);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800134
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700135 // build concrete entry of appropriate class from pointer
136 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800137
138 // get format entry timestamp
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700139 // TODO consider changing to uint64_t
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700140 virtual int64_t timestamp() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800141
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700142 // get format entry's unique id
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700143 virtual log_hash_t hash() const = 0;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700144
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800145 // entry's author index (-1 if none present)
146 // a Merger has a vector of Readers, author simply points to the index of the
147 // Reader that originated the entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700148 // TODO consider changing to uint32_t
149 virtual int author() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800150
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700151 // copy entry, adding author before timestamp, returns iterator to end of entry
152 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
153 int author) const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800154
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700155protected:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800156 // copies ordinary entry from src to dst, and returns length of entry
157 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
158 const uint8_t *mEntry;
159};
160
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700161class FormatEntry : public AbstractEntry {
162public:
163 // explicit FormatEntry(const EntryIterator &it);
164 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
165
166 // Entry's format string
167 const char* formatString() const;
168
169 // Enrty's format string length
170 size_t formatStringLength() const;
171
172 // Format arguments (excluding format string, timestamp and author)
173 EntryIterator args() const;
174
175 // get format entry timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700176 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700177
178 // get format entry's unique id
179 virtual log_hash_t hash() const override;
180
181 // entry's author index (-1 if none present)
182 // a Merger has a vector of Readers, author simply points to the index of the
183 // Reader that originated the entry
184 virtual int author() const override;
185
186 // copy entry, adding author before timestamp, returns size of original entry
187 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
188 int author) const override;
189
190 EntryIterator begin() const;
191};
192
193class HistogramEntry : public AbstractEntry {
194public:
195 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
196 }
197
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700198 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700199
200 virtual log_hash_t hash() const override;
201
202 virtual int author() const override;
203
204 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
205 int author) const override;
206
207};
208
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800209// ---------------------------------------------------------------------------
210
211// representation of a single log entry in private memory
212struct Entry {
213 Entry(Event event, const void *data, size_t length)
214 : mEvent(event), mLength(length), mData(data) { }
215 /*virtual*/ ~Entry() { }
216
217 int readAt(size_t offset) const;
218
219private:
220 friend class Writer;
221 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800222 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800223 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800224 static const size_t kMaxLength = 255;
225public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800226 // mEvent, mLength, mData[...], duplicate mLength
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700227 static const size_t kOverhead = sizeof(entry) + sizeof(ending);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800228 // endind length of previous entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700229 static const size_t kPreviousLengthOffset = - sizeof(ending) +
230 offsetof(ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800231};
232
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700233struct HistTsEntry {
234 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700235 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700236}; //TODO __attribute__((packed));
237
238struct HistTsEntryWithAuthor {
239 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700240 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700241 int author;
242}; //TODO __attribute__((packed));
243
244struct HistIntEntry {
245 log_hash_t hash;
246 int value;
247}; //TODO __attribute__((packed));
248
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800249// representation of a single log entry in shared memory
250// byte[0] mEvent
251// byte[1] mLength
252// byte[2] mData[0]
253// ...
254// byte[2+i] mData[i]
255// ...
256// byte[2+mLength-1] mData[mLength-1]
257// byte[2+mLength] duplicate copy of mLength to permit reverse scan
258// byte[3+mLength] start of next log entry
259
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800260 static void appendInt(String8 *body, const void *data);
261 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800262 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800263 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800264 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700265 static String8 bufferDump(const uint8_t *buffer, size_t size);
266 static String8 bufferDump(const EntryIterator &it);
Glenn Kasten535e1612016-12-05 12:19:36 -0800267public:
268
269// Located in shared memory, must be POD.
270// Exactly one process must explicitly call the constructor or use placement new.
271// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800272struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800273 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800274 /*virtual*/ ~Shared() { }
275
Glenn Kasten535e1612016-12-05 12:19:36 -0800276 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
277 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800278};
279
280public:
281
282// ---------------------------------------------------------------------------
283
284// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
285// For now it is just a namespace for sharedSize().
286class Timeline : public RefBase {
287public:
288#if 0
289 Timeline(size_t size, void *shared = NULL);
290 virtual ~Timeline();
291#endif
292
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700293 // Input parameter 'size' is the desired size of the timeline in byte units.
294 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800295 static size_t sharedSize(size_t size);
296
297#if 0
298private:
299 friend class Writer;
300 friend class Reader;
301
302 const size_t mSize; // circular buffer size in bytes, must be a power of 2
303 bool mOwn; // whether I own the memory at mShared
304 Shared* const mShared; // pointer to shared memory
305#endif
306};
307
308// ---------------------------------------------------------------------------
309
310// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
311// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
312class Writer : public RefBase {
313public:
314 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700315
316 // Input parameter 'size' is the desired size of the timeline in byte units.
317 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800318 Writer(void *shared, size_t size);
319 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700320
Glenn Kasten535e1612016-12-05 12:19:36 -0800321 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800322
323 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800324 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800325 virtual void logvf(const char *fmt, va_list ap);
326 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700327 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800328 virtual void logInteger(const int x);
329 virtual void logFloat(const float x);
330 virtual void logPID();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700331 virtual void logFormat(const char *fmt, log_hash_t hash, ...);
332 virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800333 virtual void logStart(const char *fmt);
334 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700335 virtual void logHash(log_hash_t hash);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700336 virtual void logHistTS(log_hash_t hash);
337 virtual void logHistFlush(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800338
339 virtual bool isEnabled() const;
340
341 // return value for all of these is the previous isEnabled()
342 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
343 bool enable() { return setEnabled(true); }
344 bool disable() { return setEnabled(false); }
345
346 sp<IMemory> getIMemory() const { return mIMemory; }
347
348private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800349 // 0 <= length <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800350 void log(Event event, const void *data, size_t length);
351 void log(const Entry *entry, bool trusted = false);
352
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800353 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800354 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
355 audio_utils_fifo * const mFifo; // FIFO itself,
356 // non-NULL unless constructor fails
357 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
358 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800359 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800360
361 // cached pid and process name to use in %p format specifier
362 // total tag length is mPidTagSize and process name is not zero terminated
363 char *mPidTag;
364 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800365};
366
367// ---------------------------------------------------------------------------
368
369// Similar to Writer, but safe for multiple threads to call concurrently
370class LockedWriter : public Writer {
371public:
372 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800373 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800374
375 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800376 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800377 virtual void logvf(const char *fmt, va_list ap);
378 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700379 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800380 virtual void logInteger(const int x);
381 virtual void logFloat(const float x);
382 virtual void logPID();
383 virtual void logStart(const char *fmt);
384 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700385 virtual void logHash(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800386
387 virtual bool isEnabled() const;
388 virtual bool setEnabled(bool enabled);
389
390private:
391 mutable Mutex mLock;
392};
393
394// ---------------------------------------------------------------------------
395
396class Reader : public RefBase {
397public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700398
Nicolas Roulet40a44982017-02-03 13:39:57 -0800399 // A snapshot of a readers buffer
400 class Snapshot {
401 public:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800402 Snapshot() : mData(NULL), mLost(0) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800403
404 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
405
406 ~Snapshot() { delete[] mData; }
407
408 // copy of the buffer
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800409 uint8_t *data() const { return mData; }
Nicolas Roulet40a44982017-02-03 13:39:57 -0800410
411 // amount of data lost (given by audio_utils_fifo_reader)
412 size_t lost() const { return mLost; }
413
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800414 // iterator to beginning of readable segment of snapshot
415 // data between begin and end has valid entries
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700416 EntryIterator begin() { return mBegin; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800417
418 // iterator to end of readable segment of snapshot
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700419 EntryIterator end() { return mEnd; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800420
421
Nicolas Roulet40a44982017-02-03 13:39:57 -0800422 private:
423 friend class Reader;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800424 uint8_t *mData;
425 size_t mLost;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700426 EntryIterator mBegin;
427 EntryIterator mEnd;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800428 };
429
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700430 // Input parameter 'size' is the desired size of the timeline in byte units.
431 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800432 Reader(const void *shared, size_t size);
433 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700434
Glenn Kasten535e1612016-12-05 12:19:36 -0800435 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800436
Nicolas Roulet40a44982017-02-03 13:39:57 -0800437 // get snapshot of readers fifo buffer, effectively consuming the buffer
438 std::unique_ptr<Snapshot> getSnapshot();
439 // dump a particular snapshot of the reader
440 void dump(int fd, size_t indent, Snapshot & snap);
441 // dump the current content of the reader's buffer
442 void dump(int fd, size_t indent = 0);
443 bool isIMemory(const sp<IMemory>& iMemory) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800444
445private:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700446 static const std::set<Event> startingTypes;
447 static const std::set<Event> endingTypes;
Glenn Kasten535e1612016-12-05 12:19:36 -0800448 /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
449 // declared as const because audio_utils_fifo() constructor
450 sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700451 int mFd; // file descriptor
452 int mIndent; // indentation level
Glenn Kasten535e1612016-12-05 12:19:36 -0800453 audio_utils_fifo * const mFifo; // FIFO itself,
454 // non-NULL unless constructor fails
455 audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
456 // non-NULL unless constructor fails
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700457
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700458 std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
459
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700460 void dumpLine(const String8& timestamp, String8& body);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800461
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700462 EntryIterator handleFormat(const FormatEntry &fmtEntry,
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800463 String8 *timestamp,
464 String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800465 // dummy method for handling absent author entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700466 virtual void handleAuthor(const AbstractEntry &fmtEntry, String8 *body) {}
467
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700468 static void drawHistogram(String8 *body, const std::vector<int64_t> &samples,
469 int indent = 0, int maxHeight = 10);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800470
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800471 // Searches for the last entry of type <type> in the range [front, back)
472 // back has to be entry-aligned. Returns nullptr if none enconuntered.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700473 static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
474 const std::set<Event> &types);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800475
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800476 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
477};
478
Nicolas Roulet40a44982017-02-03 13:39:57 -0800479// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
480class NamedReader {
481public:
482 NamedReader() { mName[0] = '\0'; } // for Vector
483 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
484 mReader(reader)
485 { strlcpy(mName, name, sizeof(mName)); }
486 ~NamedReader() { }
487 const sp<NBLog::Reader>& reader() const { return mReader; }
488 const char* name() const { return mName; }
489
490private:
491 sp<NBLog::Reader> mReader;
492 static const size_t kMaxName = 32;
493 char mName[kMaxName];
494};
495
496// ---------------------------------------------------------------------------
497
498class Merger : public RefBase {
499public:
500 Merger(const void *shared, size_t size);
501
502 virtual ~Merger() {}
503
504 void addReader(const NamedReader &reader);
505 // TODO add removeReader
506 void merge();
507 const std::vector<NamedReader> *getNamedReaders() const;
508private:
509 // vector of the readers the merger is supposed to merge from.
510 // every reader reads from a writer's buffer
511 std::vector<NamedReader> mNamedReaders;
512 uint8_t *mBuffer;
513 Shared * const mShared;
514 std::unique_ptr<audio_utils_fifo> mFifo;
515 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800516};
517
518class MergeReader : public Reader {
519public:
520 MergeReader(const void *shared, size_t size, Merger &merger);
521private:
522 const std::vector<NamedReader> *mNamedReaders;
523 // handle author entry by looking up the author's name and appending it to the body
524 // returns number of bytes read from fmtEntry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700525 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800526};
527
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800528// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
529// when triggered, it awakes for a lapse of time, during which it periodically merges; if
530// retriggered, the timeout is reset.
531// The thread is triggered on AudioFlinger binder activity.
532class MergeThread : public Thread {
533public:
534 MergeThread(Merger &merger);
535 virtual ~MergeThread() override;
536
537 // Reset timeout and activate thread to merge periodically if it's idle
538 void wakeup();
539
540 // Set timeout period until the merging thread goes idle again
541 void setTimeoutUs(int time);
542
543private:
544 virtual bool threadLoop() override;
545
546 // the merger who actually does the work of merging the logs
547 Merger& mMerger;
548
549 // mutex for the condition variable
550 Mutex mMutex;
551
552 // condition variable to activate merging on timeout >= 0
553 Condition mCond;
554
555 // time left until the thread blocks again (in microseconds)
556 int mTimeoutUs;
557
558 // merging period when the thread is awake
559 static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
560
561 // initial timeout value when triggered
562 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
563};
564
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800565}; // class NBLog
566
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700567// TODO put somewhere else
568static inline int64_t get_monotonic_ns() {
569 timespec ts;
570 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
571 return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
572 }
573 return 0; // should not happen.
574}
575
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800576} // namespace android
577
578#endif // ANDROID_MEDIA_NBLOG_H