blob: 785b9c273207403e26c247eceddc3f07112ba084 [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 Kasten1c446272017-04-07 09:49:07 -070041// FIXME Everything needed for client (writer API and registration) should be isolated
42// from the rest of the implementation.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080043class Writer;
44class Reader;
45
46private:
47
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070048enum Event : uint8_t {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080049 EVENT_RESERVED,
50 EVENT_STRING, // ASCII string, not NUL-terminated
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080051 // TODO: make timestamp optional
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080052 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080053 EVENT_INTEGER, // integer value entry
54 EVENT_FLOAT, // floating point value entry
55 EVENT_PID, // process ID and process name
56 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080057 EVENT_START_FMT, // logFormat start event: entry includes format string, following
58 // entries contain format arguments
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070059 EVENT_HASH, // unique HASH of log origin, originates from hash of file name
60 // and line number
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070061 EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
62 EVENT_HISTOGRAM_FLUSH, // show histogram on log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080063 EVENT_END_FMT, // end of logFormat argument list
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070064
65 EVENT_UPPER_BOUND, // to check for invalid events
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080066};
67
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080068
69// ---------------------------------------------------------------------------
70// API for handling format entry operations
71
72// a formatted entry has the following structure:
73// * START_FMT entry, containing the format string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080074// * TIMESTAMP entry
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070075// * HASH entry
Nicolas Roulet1ca75122017-03-16 14:19:59 -070076// * author entry of the thread that generated it (optional, present in merged log)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080077// * format arg1
78// * format arg2
79// * ...
80// * END_FMT entry
81
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070082// entry representation in memory
83struct entry {
84 const uint8_t type;
85 const uint8_t length;
86 const uint8_t data[0];
87};
88
89// entry tail representation (after data)
90struct ending {
91 uint8_t length;
92 uint8_t next[0];
93};
94
95// entry iterator
96class EntryIterator {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080097public:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070098 EntryIterator();
99 explicit EntryIterator(const uint8_t *entry);
100 EntryIterator(const EntryIterator &other);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800101
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700102 // dereference underlying entry
103 const entry& operator*() const;
104 const entry* operator->() const;
105 // advance to next entry
106 EntryIterator& operator++(); // ++i
107 // back to previous entry
108 EntryIterator& operator--(); // --i
109 EntryIterator next() const;
110 EntryIterator prev() const;
111 bool operator!=(const EntryIterator &other) const;
112 int operator-(const EntryIterator &other) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800113
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700114 bool hasConsistentLength() const;
115 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
116 void copyData(uint8_t *dst) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800117
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700118 template<typename T>
119 inline const T& payload() {
120 return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
121 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800122
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700123 inline operator const uint8_t*() const {
124 return ptr;
125 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800126
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700127private:
128 const uint8_t *ptr;
129};
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800130
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700131class AbstractEntry {
132public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800133
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700134 // Entry starting in the given pointer
135 explicit AbstractEntry(const uint8_t *entry);
Colin Cross6f51c152017-04-28 12:46:17 -0700136 virtual ~AbstractEntry() {}
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800137
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700138 // build concrete entry of appropriate class from pointer
139 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800140
141 // get format entry timestamp
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700142 // TODO consider changing to uint64_t
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700143 virtual int64_t timestamp() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800144
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700145 // get format entry's unique id
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700146 virtual log_hash_t hash() const = 0;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700147
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800148 // entry's author index (-1 if none present)
149 // a Merger has a vector of Readers, author simply points to the index of the
150 // Reader that originated the entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700151 // TODO consider changing to uint32_t
152 virtual int author() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800153
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700154 // copy entry, adding author before timestamp, returns iterator to end of entry
155 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
156 int author) const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800157
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700158protected:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800159 // copies ordinary entry from src to dst, and returns length of entry
160 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
161 const uint8_t *mEntry;
162};
163
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700164class FormatEntry : public AbstractEntry {
165public:
166 // explicit FormatEntry(const EntryIterator &it);
167 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
Colin Cross6f51c152017-04-28 12:46:17 -0700168 virtual ~FormatEntry() {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700169
Sanna Catherine de Treville Wagerdd92d7e2017-05-15 14:56:53 -0700170 EntryIterator begin() const;
171
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700172 // Entry's format string
173 const char* formatString() const;
174
175 // Enrty's format string length
176 size_t formatStringLength() const;
177
178 // Format arguments (excluding format string, timestamp and author)
179 EntryIterator args() const;
180
181 // get format entry timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700182 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700183
184 // get format entry's unique id
185 virtual log_hash_t hash() const override;
186
187 // entry's author index (-1 if none present)
188 // a Merger has a vector of Readers, author simply points to the index of the
189 // Reader that originated the entry
190 virtual int author() const override;
191
192 // copy entry, adding author before timestamp, returns size of original entry
193 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
194 int author) const override;
195
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700196};
197
198class HistogramEntry : public AbstractEntry {
199public:
200 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
201 }
Colin Cross6f51c152017-04-28 12:46:17 -0700202 virtual ~HistogramEntry() {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700203
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700204 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700205
206 virtual log_hash_t hash() const override;
207
208 virtual int author() const override;
209
210 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
211 int author) const override;
212
213};
214
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800215// ---------------------------------------------------------------------------
216
217// representation of a single log entry in private memory
218struct Entry {
219 Entry(Event event, const void *data, size_t length)
220 : mEvent(event), mLength(length), mData(data) { }
221 /*virtual*/ ~Entry() { }
222
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700223 // used during writing to format Entry information as follows: [type][length][data ... ][length]
224 int copyEntryDataAt(size_t offset) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800225
226private:
227 friend class Writer;
228 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800229 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800230 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800231 static const size_t kMaxLength = 255;
232public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800233 // mEvent, mLength, mData[...], duplicate mLength
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700234 static const size_t kOverhead = sizeof(entry) + sizeof(ending);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800235 // endind length of previous entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700236 static const size_t kPreviousLengthOffset = - sizeof(ending) +
237 offsetof(ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800238};
239
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700240struct HistTsEntry {
241 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700242 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700243}; //TODO __attribute__((packed));
244
245struct HistTsEntryWithAuthor {
246 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700247 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700248 int author;
249}; //TODO __attribute__((packed));
250
251struct HistIntEntry {
252 log_hash_t hash;
253 int value;
254}; //TODO __attribute__((packed));
255
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800256// representation of a single log entry in shared memory
257// byte[0] mEvent
258// byte[1] mLength
259// byte[2] mData[0]
260// ...
261// byte[2+i] mData[i]
262// ...
263// byte[2+mLength-1] mData[mLength-1]
264// byte[2+mLength] duplicate copy of mLength to permit reverse scan
265// byte[3+mLength] start of next log entry
266
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800267 static void appendInt(String8 *body, const void *data);
268 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800269 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800270 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800271 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700272 static String8 bufferDump(const uint8_t *buffer, size_t size);
273 static String8 bufferDump(const EntryIterator &it);
Glenn Kasten535e1612016-12-05 12:19:36 -0800274public:
275
276// Located in shared memory, must be POD.
277// Exactly one process must explicitly call the constructor or use placement new.
278// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800279struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800280 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800281 /*virtual*/ ~Shared() { }
282
Glenn Kasten535e1612016-12-05 12:19:36 -0800283 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
284 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800285};
286
287public:
288
289// ---------------------------------------------------------------------------
290
291// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
292// For now it is just a namespace for sharedSize().
293class Timeline : public RefBase {
294public:
295#if 0
296 Timeline(size_t size, void *shared = NULL);
297 virtual ~Timeline();
298#endif
299
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700300 // Input parameter 'size' is the desired size of the timeline in byte units.
301 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800302 static size_t sharedSize(size_t size);
303
304#if 0
305private:
306 friend class Writer;
307 friend class Reader;
308
309 const size_t mSize; // circular buffer size in bytes, must be a power of 2
310 bool mOwn; // whether I own the memory at mShared
311 Shared* const mShared; // pointer to shared memory
312#endif
313};
314
315// ---------------------------------------------------------------------------
316
317// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
318// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
319class Writer : public RefBase {
320public:
321 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700322
323 // Input parameter 'size' is the desired size of the timeline in byte units.
324 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800325 Writer(void *shared, size_t size);
326 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700327
Glenn Kasten535e1612016-12-05 12:19:36 -0800328 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800329
Glenn Kasten1c446272017-04-07 09:49:07 -0700330 // FIXME needs comments, and some should be private
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800331 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800332 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800333 virtual void logvf(const char *fmt, va_list ap);
334 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700335 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800336 virtual void logInteger(const int x);
337 virtual void logFloat(const float x);
338 virtual void logPID();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700339 virtual void logFormat(const char *fmt, log_hash_t hash, ...);
340 virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800341 virtual void logStart(const char *fmt);
342 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700343 virtual void logHash(log_hash_t hash);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700344 virtual void logHistTS(log_hash_t hash);
345 virtual void logHistFlush(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800346
347 virtual bool isEnabled() const;
348
349 // return value for all of these is the previous isEnabled()
350 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
351 bool enable() { return setEnabled(true); }
352 bool disable() { return setEnabled(false); }
353
354 sp<IMemory> getIMemory() const { return mIMemory; }
355
356private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800357 // 0 <= length <= kMaxLength
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700358 // writes a single Entry to the FIFO
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800359 void log(Event event, const void *data, size_t length);
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700360 // checks validity of an event before calling log above this one
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800361 void log(const Entry *entry, bool trusted = false);
362
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800363 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800364 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
365 audio_utils_fifo * const mFifo; // FIFO itself,
366 // non-NULL unless constructor fails
367 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
368 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800369 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800370
371 // cached pid and process name to use in %p format specifier
372 // total tag length is mPidTagSize and process name is not zero terminated
373 char *mPidTag;
374 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800375};
376
377// ---------------------------------------------------------------------------
378
379// Similar to Writer, but safe for multiple threads to call concurrently
380class LockedWriter : public Writer {
381public:
382 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800383 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800384
385 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800386 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800387 virtual void logvf(const char *fmt, va_list ap);
388 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700389 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800390 virtual void logInteger(const int x);
391 virtual void logFloat(const float x);
392 virtual void logPID();
393 virtual void logStart(const char *fmt);
394 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700395 virtual void logHash(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800396
397 virtual bool isEnabled() const;
398 virtual bool setEnabled(bool enabled);
399
400private:
401 mutable Mutex mLock;
402};
403
404// ---------------------------------------------------------------------------
405
406class Reader : public RefBase {
407public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700408
Nicolas Roulet40a44982017-02-03 13:39:57 -0800409 // A snapshot of a readers buffer
410 class Snapshot {
411 public:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800412 Snapshot() : mData(NULL), mLost(0) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800413
414 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
415
416 ~Snapshot() { delete[] mData; }
417
418 // copy of the buffer
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800419 uint8_t *data() const { return mData; }
Nicolas Roulet40a44982017-02-03 13:39:57 -0800420
421 // amount of data lost (given by audio_utils_fifo_reader)
422 size_t lost() const { return mLost; }
423
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800424 // iterator to beginning of readable segment of snapshot
425 // data between begin and end has valid entries
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700426 EntryIterator begin() { return mBegin; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800427
428 // iterator to end of readable segment of snapshot
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700429 EntryIterator end() { return mEnd; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800430
Nicolas Roulet40a44982017-02-03 13:39:57 -0800431 private:
432 friend class Reader;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800433 uint8_t *mData;
434 size_t mLost;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700435 EntryIterator mBegin;
436 EntryIterator mEnd;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800437 };
438
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700439 // Input parameter 'size' is the desired size of the timeline in byte units.
440 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800441 Reader(const void *shared, size_t size);
442 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700443
Glenn Kasten535e1612016-12-05 12:19:36 -0800444 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800445
Sanna Catherine de Treville Wager201079a2017-05-18 16:36:29 -0700446 void alertIfGlitch(const std::vector<int64_t> &samples);
447
Nicolas Roulet40a44982017-02-03 13:39:57 -0800448 // get snapshot of readers fifo buffer, effectively consuming the buffer
449 std::unique_ptr<Snapshot> getSnapshot();
450 // dump a particular snapshot of the reader
451 void dump(int fd, size_t indent, Snapshot & snap);
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700452 // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
Nicolas Roulet40a44982017-02-03 13:39:57 -0800453 void dump(int fd, size_t indent = 0);
454 bool isIMemory(const sp<IMemory>& iMemory) const;
Sanna Catherine de Treville Wager201079a2017-05-18 16:36:29 -0700455 // if findGlitch is true, log warning when buffer periods caused glitch
456 void setFindGlitch(bool s);
457 bool isFindGlitch() const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800458
459private:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700460 static const std::set<Event> startingTypes;
461 static const std::set<Event> endingTypes;
Glenn Kasten535e1612016-12-05 12:19:36 -0800462 /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
463 // declared as const because audio_utils_fifo() constructor
464 sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700465 int mFd; // file descriptor
466 int mIndent; // indentation level
Glenn Kasten535e1612016-12-05 12:19:36 -0800467 audio_utils_fifo * const mFifo; // FIFO itself,
468 // non-NULL unless constructor fails
469 audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
470 // non-NULL unless constructor fails
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700471
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700472 // each pair contains a sequence of timestamps (one histogram's worth)
473 // pair's log_hash_t is the hash of the source code location where the timestamp was taken
474 // pair's int points to the Reader that originated the entry
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700475 std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700476 // TODO: it might be clearer, instead of a direct map from source location to vector of
477 // timestamps, if we instead first mapped from source location to an object that
478 // represented that location. And one_of its fields would be a vector of timestamps.
479 // That would allow us to record other information about the source location beyond timestamps.
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700480 void dumpLine(const String8& timestamp, String8& body);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800481
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700482 EntryIterator handleFormat(const FormatEntry &fmtEntry,
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800483 String8 *timestamp,
484 String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800485 // dummy method for handling absent author entry
Colin Crossb8c35f92017-04-27 16:15:51 -0700486 virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700487
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700488 static void drawHistogram(String8 *body, const std::vector<int64_t> &samples,
Nicolas Roulet4f033492017-04-03 19:17:03 -0700489 bool logScale, int indent = 0, int maxHeight = 10);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800490
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800491 // Searches for the last entry of type <type> in the range [front, back)
492 // back has to be entry-aligned. Returns nullptr if none enconuntered.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700493 static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
494 const std::set<Event> &types);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800495
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800496 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
Sanna Catherine de Treville Wager201079a2017-05-18 16:36:29 -0700497
498 bool findGlitch; // alert if a local buffer period sequence caused an audio glitch
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800499};
500
Nicolas Roulet40a44982017-02-03 13:39:57 -0800501// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
502class NamedReader {
503public:
504 NamedReader() { mName[0] = '\0'; } // for Vector
505 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
506 mReader(reader)
507 { strlcpy(mName, name, sizeof(mName)); }
508 ~NamedReader() { }
509 const sp<NBLog::Reader>& reader() const { return mReader; }
510 const char* name() const { return mName; }
511
512private:
513 sp<NBLog::Reader> mReader;
514 static const size_t kMaxName = 32;
515 char mName[kMaxName];
516};
517
518// ---------------------------------------------------------------------------
519
520class Merger : public RefBase {
521public:
522 Merger(const void *shared, size_t size);
523
524 virtual ~Merger() {}
525
526 void addReader(const NamedReader &reader);
527 // TODO add removeReader
528 void merge();
Glenn Kasten1c446272017-04-07 09:49:07 -0700529 // FIXME This is returning a reference to a shared variable that needs a lock
530 const std::vector<NamedReader>& getNamedReaders() const;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800531private:
532 // vector of the readers the merger is supposed to merge from.
533 // every reader reads from a writer's buffer
Glenn Kasten1c446272017-04-07 09:49:07 -0700534 // FIXME Needs to be protected by a lock
Nicolas Roulet40a44982017-02-03 13:39:57 -0800535 std::vector<NamedReader> mNamedReaders;
Glenn Kasten1c446272017-04-07 09:49:07 -0700536
537 // TODO Need comments on all of these
Nicolas Roulet40a44982017-02-03 13:39:57 -0800538 Shared * const mShared;
539 std::unique_ptr<audio_utils_fifo> mFifo;
540 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800541};
542
543class MergeReader : public Reader {
544public:
545 MergeReader(const void *shared, size_t size, Merger &merger);
546private:
Glenn Kasten1c446272017-04-07 09:49:07 -0700547 // FIXME Needs to be protected by a lock,
548 // because even though our use of it is read-only there may be asynchronous updates
549 const std::vector<NamedReader>& mNamedReaders;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800550 // handle author entry by looking up the author's name and appending it to the body
551 // returns number of bytes read from fmtEntry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700552 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800553};
554
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800555// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
556// when triggered, it awakes for a lapse of time, during which it periodically merges; if
557// retriggered, the timeout is reset.
558// The thread is triggered on AudioFlinger binder activity.
559class MergeThread : public Thread {
560public:
561 MergeThread(Merger &merger);
562 virtual ~MergeThread() override;
563
564 // Reset timeout and activate thread to merge periodically if it's idle
565 void wakeup();
566
567 // Set timeout period until the merging thread goes idle again
568 void setTimeoutUs(int time);
569
570private:
571 virtual bool threadLoop() override;
572
573 // the merger who actually does the work of merging the logs
574 Merger& mMerger;
575
576 // mutex for the condition variable
577 Mutex mMutex;
578
579 // condition variable to activate merging on timeout >= 0
580 Condition mCond;
581
582 // time left until the thread blocks again (in microseconds)
583 int mTimeoutUs;
584
585 // merging period when the thread is awake
586 static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
587
588 // initial timeout value when triggered
589 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
590};
591
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800592}; // class NBLog
593
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700594// TODO put somewhere else
595static inline int64_t get_monotonic_ns() {
596 timespec ts;
597 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
598 return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
599 }
600 return 0; // should not happen.
601}
602
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800603} // namespace android
604
605#endif // ANDROID_MEDIA_NBLOG_H