blob: 79e1679bb268c4940fd414f46e27a38bc47d76a3 [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 Kasten1c446272017-04-07 09:49:07 -070040// FIXME Everything needed for client (writer API and registration) should be isolated
41// from the rest of the implementation.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080042class Writer;
43class Reader;
44
45private:
46
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070047enum Event : uint8_t {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080048 EVENT_RESERVED,
49 EVENT_STRING, // ASCII string, not NUL-terminated
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080050 // TODO: make timestamp optional
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080051 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080052 EVENT_INTEGER, // integer value entry
53 EVENT_FLOAT, // floating point value entry
54 EVENT_PID, // process ID and process name
55 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080056 EVENT_START_FMT, // logFormat start event: entry includes format string, following
57 // entries contain format arguments
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070058 EVENT_HASH, // unique HASH of log origin, originates from hash of file name
59 // and line number
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070060 EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
61 EVENT_HISTOGRAM_FLUSH, // show histogram on log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080062 EVENT_END_FMT, // end of logFormat argument list
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070063
64 EVENT_UPPER_BOUND, // to check for invalid events
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080065};
66
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080067
68// ---------------------------------------------------------------------------
69// API for handling format entry operations
70
71// a formatted entry has the following structure:
72// * START_FMT entry, containing the format string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080073// * TIMESTAMP entry
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070074// * HASH entry
Nicolas Roulet1ca75122017-03-16 14:19:59 -070075// * author entry of the thread that generated it (optional, present in merged log)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080076// * format arg1
77// * format arg2
78// * ...
79// * END_FMT entry
80
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070081// entry representation in memory
82struct entry {
83 const uint8_t type;
84 const uint8_t length;
85 const uint8_t data[0];
86};
87
88// entry tail representation (after data)
89struct ending {
90 uint8_t length;
91 uint8_t next[0];
92};
93
94// entry iterator
95class EntryIterator {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080096public:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070097 EntryIterator();
98 explicit EntryIterator(const uint8_t *entry);
99 EntryIterator(const EntryIterator &other);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800100
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700101 // dereference underlying entry
102 const entry& operator*() const;
103 const entry* operator->() const;
104 // advance to next entry
105 EntryIterator& operator++(); // ++i
106 // back to previous entry
107 EntryIterator& operator--(); // --i
108 EntryIterator next() const;
109 EntryIterator prev() const;
110 bool operator!=(const EntryIterator &other) const;
111 int operator-(const EntryIterator &other) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800112
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700113 bool hasConsistentLength() const;
114 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
115 void copyData(uint8_t *dst) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800116
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700117 template<typename T>
118 inline const T& payload() {
119 return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
120 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800121
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700122 inline operator const uint8_t*() const {
123 return ptr;
124 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800125
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700126private:
127 const uint8_t *ptr;
128};
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800129
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700130class AbstractEntry {
131public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800132
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700133 // Entry starting in the given pointer
134 explicit AbstractEntry(const uint8_t *entry);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800135
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700136 // build concrete entry of appropriate class from pointer
137 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800138
139 // get format entry timestamp
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700140 // TODO consider changing to uint64_t
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700141 virtual int64_t timestamp() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800142
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700143 // get format entry's unique id
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700144 virtual log_hash_t hash() const = 0;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700145
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800146 // entry's author index (-1 if none present)
147 // a Merger has a vector of Readers, author simply points to the index of the
148 // Reader that originated the entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700149 // TODO consider changing to uint32_t
150 virtual int author() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800151
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700152 // copy entry, adding author before timestamp, returns iterator to end of entry
153 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
154 int author) const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800155
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700156protected:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800157 // copies ordinary entry from src to dst, and returns length of entry
158 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
159 const uint8_t *mEntry;
160};
161
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700162class FormatEntry : public AbstractEntry {
163public:
164 // explicit FormatEntry(const EntryIterator &it);
165 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
166
167 // Entry's format string
168 const char* formatString() const;
169
170 // Enrty's format string length
171 size_t formatStringLength() const;
172
173 // Format arguments (excluding format string, timestamp and author)
174 EntryIterator args() const;
175
176 // get format entry timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700177 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700178
179 // get format entry's unique id
180 virtual log_hash_t hash() const override;
181
182 // entry's author index (-1 if none present)
183 // a Merger has a vector of Readers, author simply points to the index of the
184 // Reader that originated the entry
185 virtual int author() const override;
186
187 // copy entry, adding author before timestamp, returns size of original entry
188 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
189 int author) const override;
190
191 EntryIterator begin() const;
192};
193
194class HistogramEntry : public AbstractEntry {
195public:
196 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
197 }
198
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700199 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700200
201 virtual log_hash_t hash() const override;
202
203 virtual int author() const override;
204
205 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
206 int author) const override;
207
208};
209
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800210// ---------------------------------------------------------------------------
211
212// representation of a single log entry in private memory
213struct Entry {
214 Entry(Event event, const void *data, size_t length)
215 : mEvent(event), mLength(length), mData(data) { }
216 /*virtual*/ ~Entry() { }
217
218 int readAt(size_t offset) const;
219
220private:
221 friend class Writer;
222 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800223 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800224 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800225 static const size_t kMaxLength = 255;
226public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800227 // mEvent, mLength, mData[...], duplicate mLength
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700228 static const size_t kOverhead = sizeof(entry) + sizeof(ending);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800229 // endind length of previous entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700230 static const size_t kPreviousLengthOffset = - sizeof(ending) +
231 offsetof(ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800232};
233
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700234struct HistTsEntry {
235 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700236 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700237}; //TODO __attribute__((packed));
238
239struct HistTsEntryWithAuthor {
240 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700241 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700242 int author;
243}; //TODO __attribute__((packed));
244
245struct HistIntEntry {
246 log_hash_t hash;
247 int value;
248}; //TODO __attribute__((packed));
249
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800250// representation of a single log entry in shared memory
251// byte[0] mEvent
252// byte[1] mLength
253// byte[2] mData[0]
254// ...
255// byte[2+i] mData[i]
256// ...
257// byte[2+mLength-1] mData[mLength-1]
258// byte[2+mLength] duplicate copy of mLength to permit reverse scan
259// byte[3+mLength] start of next log entry
260
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800261 static void appendInt(String8 *body, const void *data);
262 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800263 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800264 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800265 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700266 static String8 bufferDump(const uint8_t *buffer, size_t size);
267 static String8 bufferDump(const EntryIterator &it);
Glenn Kasten535e1612016-12-05 12:19:36 -0800268public:
269
270// Located in shared memory, must be POD.
271// Exactly one process must explicitly call the constructor or use placement new.
272// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800273struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800274 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800275 /*virtual*/ ~Shared() { }
276
Glenn Kasten535e1612016-12-05 12:19:36 -0800277 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
278 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800279};
280
281public:
282
283// ---------------------------------------------------------------------------
284
285// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
286// For now it is just a namespace for sharedSize().
287class Timeline : public RefBase {
288public:
289#if 0
290 Timeline(size_t size, void *shared = NULL);
291 virtual ~Timeline();
292#endif
293
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700294 // Input parameter 'size' is the desired size of the timeline in byte units.
295 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800296 static size_t sharedSize(size_t size);
297
298#if 0
299private:
300 friend class Writer;
301 friend class Reader;
302
303 const size_t mSize; // circular buffer size in bytes, must be a power of 2
304 bool mOwn; // whether I own the memory at mShared
305 Shared* const mShared; // pointer to shared memory
306#endif
307};
308
309// ---------------------------------------------------------------------------
310
311// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
312// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
313class Writer : public RefBase {
314public:
315 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700316
317 // Input parameter 'size' is the desired size of the timeline in byte units.
318 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800319 Writer(void *shared, size_t size);
320 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700321
Glenn Kasten535e1612016-12-05 12:19:36 -0800322 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800323
Glenn Kasten1c446272017-04-07 09:49:07 -0700324 // FIXME needs comments, and some should be private
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800325 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800326 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800327 virtual void logvf(const char *fmt, va_list ap);
328 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700329 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800330 virtual void logInteger(const int x);
331 virtual void logFloat(const float x);
332 virtual void logPID();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700333 virtual void logFormat(const char *fmt, log_hash_t hash, ...);
334 virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800335 virtual void logStart(const char *fmt);
336 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700337 virtual void logHash(log_hash_t hash);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700338 virtual void logHistTS(log_hash_t hash);
339 virtual void logHistFlush(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800340
341 virtual bool isEnabled() const;
342
343 // return value for all of these is the previous isEnabled()
344 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
345 bool enable() { return setEnabled(true); }
346 bool disable() { return setEnabled(false); }
347
348 sp<IMemory> getIMemory() const { return mIMemory; }
349
350private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800351 // 0 <= length <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800352 void log(Event event, const void *data, size_t length);
353 void log(const Entry *entry, bool trusted = false);
354
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800355 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800356 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
357 audio_utils_fifo * const mFifo; // FIFO itself,
358 // non-NULL unless constructor fails
359 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
360 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800361 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800362
363 // cached pid and process name to use in %p format specifier
364 // total tag length is mPidTagSize and process name is not zero terminated
365 char *mPidTag;
366 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800367};
368
369// ---------------------------------------------------------------------------
370
371// Similar to Writer, but safe for multiple threads to call concurrently
372class LockedWriter : public Writer {
373public:
374 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800375 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800376
377 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800378 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800379 virtual void logvf(const char *fmt, va_list ap);
380 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700381 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800382 virtual void logInteger(const int x);
383 virtual void logFloat(const float x);
384 virtual void logPID();
385 virtual void logStart(const char *fmt);
386 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700387 virtual void logHash(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800388
389 virtual bool isEnabled() const;
390 virtual bool setEnabled(bool enabled);
391
392private:
393 mutable Mutex mLock;
394};
395
396// ---------------------------------------------------------------------------
397
398class Reader : public RefBase {
399public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700400
Nicolas Roulet40a44982017-02-03 13:39:57 -0800401 // A snapshot of a readers buffer
402 class Snapshot {
403 public:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800404 Snapshot() : mData(NULL), mLost(0) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800405
406 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
407
408 ~Snapshot() { delete[] mData; }
409
410 // copy of the buffer
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800411 uint8_t *data() const { return mData; }
Nicolas Roulet40a44982017-02-03 13:39:57 -0800412
413 // amount of data lost (given by audio_utils_fifo_reader)
414 size_t lost() const { return mLost; }
415
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800416 // iterator to beginning of readable segment of snapshot
417 // data between begin and end has valid entries
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700418 EntryIterator begin() { return mBegin; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800419
420 // iterator to end of readable segment of snapshot
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700421 EntryIterator end() { return mEnd; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800422
423
Nicolas Roulet40a44982017-02-03 13:39:57 -0800424 private:
425 friend class Reader;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800426 uint8_t *mData;
427 size_t mLost;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700428 EntryIterator mBegin;
429 EntryIterator mEnd;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800430 };
431
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700432 // Input parameter 'size' is the desired size of the timeline in byte units.
433 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800434 Reader(const void *shared, size_t size);
435 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700436
Glenn Kasten535e1612016-12-05 12:19:36 -0800437 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800438
Nicolas Roulet40a44982017-02-03 13:39:57 -0800439 // get snapshot of readers fifo buffer, effectively consuming the buffer
440 std::unique_ptr<Snapshot> getSnapshot();
441 // dump a particular snapshot of the reader
442 void dump(int fd, size_t indent, Snapshot & snap);
443 // dump the current content of the reader's buffer
444 void dump(int fd, size_t indent = 0);
445 bool isIMemory(const sp<IMemory>& iMemory) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800446
447private:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700448 static const std::set<Event> startingTypes;
449 static const std::set<Event> endingTypes;
Glenn Kasten535e1612016-12-05 12:19:36 -0800450 /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
451 // declared as const because audio_utils_fifo() constructor
452 sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700453 int mFd; // file descriptor
454 int mIndent; // indentation level
Glenn Kasten535e1612016-12-05 12:19:36 -0800455 audio_utils_fifo * const mFifo; // FIFO itself,
456 // non-NULL unless constructor fails
457 audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
458 // non-NULL unless constructor fails
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700459
460 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
468 static void drawHistogram(String8 *body, const std::vector<int> &samples, int maxHeight = 10);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800469
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800470 // Searches for the last entry of type <type> in the range [front, back)
471 // back has to be entry-aligned. Returns nullptr if none enconuntered.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700472 static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
473 const std::set<Event> &types);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800474
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800475 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
476};
477
Nicolas Roulet40a44982017-02-03 13:39:57 -0800478// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
479class NamedReader {
480public:
481 NamedReader() { mName[0] = '\0'; } // for Vector
482 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
483 mReader(reader)
484 { strlcpy(mName, name, sizeof(mName)); }
485 ~NamedReader() { }
486 const sp<NBLog::Reader>& reader() const { return mReader; }
487 const char* name() const { return mName; }
488
489private:
490 sp<NBLog::Reader> mReader;
491 static const size_t kMaxName = 32;
492 char mName[kMaxName];
493};
494
495// ---------------------------------------------------------------------------
496
497class Merger : public RefBase {
498public:
499 Merger(const void *shared, size_t size);
500
501 virtual ~Merger() {}
502
503 void addReader(const NamedReader &reader);
504 // TODO add removeReader
505 void merge();
Glenn Kasten1c446272017-04-07 09:49:07 -0700506 // FIXME This is returning a reference to a shared variable that needs a lock
507 const std::vector<NamedReader>& getNamedReaders() const;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800508private:
509 // vector of the readers the merger is supposed to merge from.
510 // every reader reads from a writer's buffer
Glenn Kasten1c446272017-04-07 09:49:07 -0700511 // FIXME Needs to be protected by a lock
Nicolas Roulet40a44982017-02-03 13:39:57 -0800512 std::vector<NamedReader> mNamedReaders;
Glenn Kasten1c446272017-04-07 09:49:07 -0700513
514 // TODO Need comments on all of these
Nicolas Roulet40a44982017-02-03 13:39:57 -0800515 uint8_t *mBuffer;
516 Shared * const mShared;
517 std::unique_ptr<audio_utils_fifo> mFifo;
518 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800519};
520
521class MergeReader : public Reader {
522public:
523 MergeReader(const void *shared, size_t size, Merger &merger);
524private:
Glenn Kasten1c446272017-04-07 09:49:07 -0700525 // FIXME Needs to be protected by a lock,
526 // because even though our use of it is read-only there may be asynchronous updates
527 const std::vector<NamedReader>& mNamedReaders;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800528 // handle author entry by looking up the author's name and appending it to the body
529 // returns number of bytes read from fmtEntry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700530 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800531};
532
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800533// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
534// when triggered, it awakes for a lapse of time, during which it periodically merges; if
535// retriggered, the timeout is reset.
536// The thread is triggered on AudioFlinger binder activity.
537class MergeThread : public Thread {
538public:
539 MergeThread(Merger &merger);
540 virtual ~MergeThread() override;
541
542 // Reset timeout and activate thread to merge periodically if it's idle
543 void wakeup();
544
545 // Set timeout period until the merging thread goes idle again
546 void setTimeoutUs(int time);
547
548private:
549 virtual bool threadLoop() override;
550
551 // the merger who actually does the work of merging the logs
552 Merger& mMerger;
553
554 // mutex for the condition variable
555 Mutex mMutex;
556
557 // condition variable to activate merging on timeout >= 0
558 Condition mCond;
559
560 // time left until the thread blocks again (in microseconds)
561 int mTimeoutUs;
562
563 // merging period when the thread is awake
564 static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
565
566 // initial timeout value when triggered
567 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
568};
569
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800570}; // class NBLog
571
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700572// TODO put somewhere else
573static inline int64_t get_monotonic_ns() {
574 timespec ts;
575 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
576 return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
577 }
578 return 0; // should not happen.
579}
580
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800581} // namespace android
582
583#endif // ANDROID_MEDIA_NBLOG_H