blob: f2a74272f8caf70fdb492abd7591777a387b0bac [file] [log] [blame]
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001/*
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -07002 * Copyright (C) 2017 The Android Open Source Project
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08003 *
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>
Sanna Catherine de Treville Wager9484bae2017-06-15 14:39:44 -070028#include <deque>
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070029#include <set>
Nicolas Roulet40a44982017-02-03 13:39:57 -080030#include <vector>
31
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080032namespace android {
33
Glenn Kasten4e01ef62013-07-11 14:29:59 -070034class String8;
35
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080036class NBLog {
37
38public:
39
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070040typedef uint64_t log_hash_t;
41
Glenn Kasten1c446272017-04-07 09:49:07 -070042// FIXME Everything needed for client (writer API and registration) should be isolated
43// from the rest of the implementation.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080044class Writer;
45class Reader;
46
47private:
48
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070049enum Event : uint8_t {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080050 EVENT_RESERVED,
51 EVENT_STRING, // ASCII string, not NUL-terminated
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080052 // TODO: make timestamp optional
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080053 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080054 EVENT_INTEGER, // integer value entry
55 EVENT_FLOAT, // floating point value entry
56 EVENT_PID, // process ID and process name
57 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080058 EVENT_START_FMT, // logFormat start event: entry includes format string, following
59 // entries contain format arguments
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070060 EVENT_HASH, // unique HASH of log origin, originates from hash of file name
61 // and line number
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070062 EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
63 EVENT_HISTOGRAM_FLUSH, // show histogram on log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080064 EVENT_END_FMT, // end of logFormat argument list
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070065
66 EVENT_UPPER_BOUND, // to check for invalid events
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080067};
68
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080069
70// ---------------------------------------------------------------------------
71// API for handling format entry operations
72
73// a formatted entry has the following structure:
74// * START_FMT entry, containing the format string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080075// * TIMESTAMP entry
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070076// * HASH entry
Nicolas Roulet1ca75122017-03-16 14:19:59 -070077// * author entry of the thread that generated it (optional, present in merged log)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080078// * format arg1
79// * format arg2
80// * ...
81// * END_FMT entry
82
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070083// entry representation in memory
84struct entry {
85 const uint8_t type;
86 const uint8_t length;
87 const uint8_t data[0];
88};
89
90// entry tail representation (after data)
91struct ending {
92 uint8_t length;
93 uint8_t next[0];
94};
95
96// entry iterator
97class EntryIterator {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080098public:
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070099 EntryIterator();
100 explicit EntryIterator(const uint8_t *entry);
101 EntryIterator(const EntryIterator &other);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800102
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700103 // dereference underlying entry
104 const entry& operator*() const;
105 const entry* operator->() const;
106 // advance to next entry
107 EntryIterator& operator++(); // ++i
108 // back to previous entry
109 EntryIterator& operator--(); // --i
110 EntryIterator next() const;
111 EntryIterator prev() const;
112 bool operator!=(const EntryIterator &other) const;
113 int operator-(const EntryIterator &other) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800114
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700115 bool hasConsistentLength() const;
116 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
117 void copyData(uint8_t *dst) const;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800118
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700119 template<typename T>
120 inline const T& payload() {
121 return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
122 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800123
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700124 inline operator const uint8_t*() const {
125 return ptr;
126 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800127
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700128private:
129 const uint8_t *ptr;
130};
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800131
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700132class AbstractEntry {
133public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800134
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700135 // Entry starting in the given pointer
136 explicit AbstractEntry(const uint8_t *entry);
Colin Cross6f51c152017-04-28 12:46:17 -0700137 virtual ~AbstractEntry() {}
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800138
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700139 // build concrete entry of appropriate class from pointer
140 static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800141
142 // get format entry timestamp
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700143 // TODO consider changing to uint64_t
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700144 virtual int64_t timestamp() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800145
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700146 // get format entry's unique id
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700147 virtual log_hash_t hash() const = 0;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700148
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800149 // entry's author index (-1 if none present)
150 // a Merger has a vector of Readers, author simply points to the index of the
151 // Reader that originated the entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700152 // TODO consider changing to uint32_t
153 virtual int author() const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800154
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700155 // copy entry, adding author before timestamp, returns iterator to end of entry
156 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
157 int author) const = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800158
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700159protected:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800160 // copies ordinary entry from src to dst, and returns length of entry
161 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
162 const uint8_t *mEntry;
163};
164
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700165class FormatEntry : public AbstractEntry {
166public:
167 // explicit FormatEntry(const EntryIterator &it);
168 explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
Colin Cross6f51c152017-04-28 12:46:17 -0700169 virtual ~FormatEntry() {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700170
Sanna Catherine de Treville Wagerdd92d7e2017-05-15 14:56:53 -0700171 EntryIterator begin() const;
172
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700173 // Entry's format string
174 const char* formatString() const;
175
176 // Enrty's format string length
177 size_t formatStringLength() const;
178
179 // Format arguments (excluding format string, timestamp and author)
180 EntryIterator args() const;
181
182 // get format entry timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700183 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700184
185 // get format entry's unique id
186 virtual log_hash_t hash() const override;
187
188 // entry's author index (-1 if none present)
189 // a Merger has a vector of Readers, author simply points to the index of the
190 // Reader that originated the entry
191 virtual int author() const override;
192
193 // copy entry, adding author before timestamp, returns size of original entry
194 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
195 int author) const override;
196
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700197};
198
199class HistogramEntry : public AbstractEntry {
200public:
201 explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
202 }
Colin Cross6f51c152017-04-28 12:46:17 -0700203 virtual ~HistogramEntry() {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700204
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700205 virtual int64_t timestamp() const override;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700206
207 virtual log_hash_t hash() const override;
208
209 virtual int author() const override;
210
211 virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
212 int author) const override;
213
214};
215
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800216// ---------------------------------------------------------------------------
217
218// representation of a single log entry in private memory
219struct Entry {
220 Entry(Event event, const void *data, size_t length)
221 : mEvent(event), mLength(length), mData(data) { }
222 /*virtual*/ ~Entry() { }
223
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700224 // used during writing to format Entry information as follows: [type][length][data ... ][length]
225 int copyEntryDataAt(size_t offset) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800226
227private:
228 friend class Writer;
229 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800230 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800231 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800232 static const size_t kMaxLength = 255;
233public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800234 // mEvent, mLength, mData[...], duplicate mLength
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700235 static const size_t kOverhead = sizeof(entry) + sizeof(ending);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800236 // endind length of previous entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700237 static const size_t kPreviousLengthOffset = - sizeof(ending) +
238 offsetof(ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800239};
240
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700241struct HistTsEntry {
242 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700243 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700244}; //TODO __attribute__((packed));
245
246struct HistTsEntryWithAuthor {
247 log_hash_t hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700248 int64_t ts;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700249 int author;
250}; //TODO __attribute__((packed));
251
252struct HistIntEntry {
253 log_hash_t hash;
254 int value;
255}; //TODO __attribute__((packed));
256
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800257// representation of a single log entry in shared memory
258// byte[0] mEvent
259// byte[1] mLength
260// byte[2] mData[0]
261// ...
262// byte[2+i] mData[i]
263// ...
264// byte[2+mLength-1] mData[mLength-1]
265// byte[2+mLength] duplicate copy of mLength to permit reverse scan
266// byte[3+mLength] start of next log entry
267
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800268 static void appendInt(String8 *body, const void *data);
269 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800270 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800271 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800272 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700273 static String8 bufferDump(const uint8_t *buffer, size_t size);
274 static String8 bufferDump(const EntryIterator &it);
Glenn Kasten535e1612016-12-05 12:19:36 -0800275public:
276
277// Located in shared memory, must be POD.
278// Exactly one process must explicitly call the constructor or use placement new.
279// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800280struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800281 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800282 /*virtual*/ ~Shared() { }
283
Glenn Kasten535e1612016-12-05 12:19:36 -0800284 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
285 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800286};
287
288public:
289
290// ---------------------------------------------------------------------------
291
292// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
293// For now it is just a namespace for sharedSize().
294class Timeline : public RefBase {
295public:
296#if 0
297 Timeline(size_t size, void *shared = NULL);
298 virtual ~Timeline();
299#endif
300
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700301 // Input parameter 'size' is the desired size of the timeline in byte units.
302 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800303 static size_t sharedSize(size_t size);
304
305#if 0
306private:
307 friend class Writer;
308 friend class Reader;
309
310 const size_t mSize; // circular buffer size in bytes, must be a power of 2
311 bool mOwn; // whether I own the memory at mShared
312 Shared* const mShared; // pointer to shared memory
313#endif
314};
315
316// ---------------------------------------------------------------------------
317
318// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
319// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
320class Writer : public RefBase {
321public:
322 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700323
324 // Input parameter 'size' is the desired size of the timeline in byte units.
325 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800326 Writer(void *shared, size_t size);
327 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700328
Glenn Kasten535e1612016-12-05 12:19:36 -0800329 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800330
Glenn Kasten1c446272017-04-07 09:49:07 -0700331 // FIXME needs comments, and some should be private
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800332 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800333 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800334 virtual void logvf(const char *fmt, va_list ap);
335 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700336 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800337 virtual void logInteger(const int x);
338 virtual void logFloat(const float x);
339 virtual void logPID();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700340 virtual void logFormat(const char *fmt, log_hash_t hash, ...);
341 virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800342 virtual void logStart(const char *fmt);
343 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700344 virtual void logHash(log_hash_t hash);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700345 virtual void logHistTS(log_hash_t hash);
346 virtual void logHistFlush(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800347
348 virtual bool isEnabled() const;
349
350 // return value for all of these is the previous isEnabled()
351 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
352 bool enable() { return setEnabled(true); }
353 bool disable() { return setEnabled(false); }
354
355 sp<IMemory> getIMemory() const { return mIMemory; }
356
357private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800358 // 0 <= length <= kMaxLength
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700359 // writes a single Entry to the FIFO
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800360 void log(Event event, const void *data, size_t length);
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700361 // checks validity of an event before calling log above this one
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800362 void log(const Entry *entry, bool trusted = false);
363
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800364 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800365 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
366 audio_utils_fifo * const mFifo; // FIFO itself,
367 // non-NULL unless constructor fails
368 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
369 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800370 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800371
372 // cached pid and process name to use in %p format specifier
373 // total tag length is mPidTagSize and process name is not zero terminated
374 char *mPidTag;
375 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800376};
377
378// ---------------------------------------------------------------------------
379
380// Similar to Writer, but safe for multiple threads to call concurrently
381class LockedWriter : public Writer {
382public:
383 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800384 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800385
386 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800387 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800388 virtual void logvf(const char *fmt, va_list ap);
389 virtual void logTimestamp();
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700390 virtual void logTimestamp(const int64_t ts);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800391 virtual void logInteger(const int x);
392 virtual void logFloat(const float x);
393 virtual void logPID();
394 virtual void logStart(const char *fmt);
395 virtual void logEnd();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700396 virtual void logHash(log_hash_t hash);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800397
398 virtual bool isEnabled() const;
399 virtual bool setEnabled(bool enabled);
400
401private:
402 mutable Mutex mLock;
403};
404
405// ---------------------------------------------------------------------------
406
407class Reader : public RefBase {
408public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700409
Nicolas Roulet40a44982017-02-03 13:39:57 -0800410 // A snapshot of a readers buffer
411 class Snapshot {
412 public:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800413 Snapshot() : mData(NULL), mLost(0) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800414
415 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
416
417 ~Snapshot() { delete[] mData; }
418
419 // copy of the buffer
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800420 uint8_t *data() const { return mData; }
Nicolas Roulet40a44982017-02-03 13:39:57 -0800421
422 // amount of data lost (given by audio_utils_fifo_reader)
423 size_t lost() const { return mLost; }
424
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800425 // iterator to beginning of readable segment of snapshot
426 // data between begin and end has valid entries
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700427 EntryIterator begin() { return mBegin; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800428
429 // iterator to end of readable segment of snapshot
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700430 EntryIterator end() { return mEnd; }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800431
Nicolas Roulet40a44982017-02-03 13:39:57 -0800432 private:
433 friend class Reader;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800434 uint8_t *mData;
435 size_t mLost;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700436 EntryIterator mBegin;
437 EntryIterator mEnd;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800438 };
439
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700440 // Input parameter 'size' is the desired size of the timeline in byte units.
441 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800442 Reader(const void *shared, size_t size);
443 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700444
Glenn Kasten535e1612016-12-05 12:19:36 -0800445 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800446
Nicolas Roulet40a44982017-02-03 13:39:57 -0800447 // get snapshot of readers fifo buffer, effectively consuming the buffer
448 std::unique_ptr<Snapshot> getSnapshot();
449 // dump a particular snapshot of the reader
450 void dump(int fd, size_t indent, Snapshot & snap);
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700451 // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
Nicolas Roulet40a44982017-02-03 13:39:57 -0800452 void dump(int fd, size_t indent = 0);
453 bool isIMemory(const sp<IMemory>& iMemory) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800454
455private:
Sanna Catherine de Treville Wager9484bae2017-06-15 14:39:44 -0700456
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700457 // TODO: decide whether these belong in NBLog::Reader or in PerformanceAnalysis
Sanna Catherine de Treville Wager9484bae2017-06-15 14:39:44 -0700458 static const int kShortHistSize = 50; // number of samples in a short-term histogram
459 static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
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 Wager9484bae2017-06-15 14:39:44 -0700472 // stores a short-term histogram of size determined by kShortHistSize
473 // TODO: unsigned, unsigned
474 using short_histogram = std::map<int, int>;
475
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700476 // each pair contains a sequence of timestamps (one histogram's worth)
477 // pair's log_hash_t is the hash of the source code location where the timestamp was taken
478 // pair's int points to the Reader that originated the entry
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700479 std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
Sanna Catherine de Treville Wager9484bae2017-06-15 14:39:44 -0700480
481 // mHistsCopy stores timestamp vectors whose key is the reader thread index.
482 // TODO remove old mHists after changing the code
483 std::map<int, std::vector<int64_t>> mTimeStampSeries;
484
485 // stores fixed-size short buffer period histograms with hash and thread data
486 // TODO: Turn it into a circular buffer for better data flow
487 std::deque<std::pair<int, short_histogram>> mRecentHists;
488
Sanna Catherine de Treville Wager2d1631e2017-05-30 16:12:36 -0700489 // TODO: it might be clearer, instead of a direct map from source location to vector of
490 // timestamps, if we instead first mapped from source location to an object that
491 // represented that location. And one_of its fields would be a vector of timestamps.
492 // That would allow us to record other information about the source location beyond timestamps.
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700493 void dumpLine(const String8& timestamp, String8& body);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800494
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700495 EntryIterator handleFormat(const FormatEntry &fmtEntry,
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800496 String8 *timestamp,
497 String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800498 // dummy method for handling absent author entry
Colin Crossb8c35f92017-04-27 16:15:51 -0700499 virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700500
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800501 // Searches for the last entry of type <type> in the range [front, back)
502 // back has to be entry-aligned. Returns nullptr if none enconuntered.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700503 static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
504 const std::set<Event> &types);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800505
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800506 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
507};
508
Nicolas Roulet40a44982017-02-03 13:39:57 -0800509// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
510class NamedReader {
511public:
512 NamedReader() { mName[0] = '\0'; } // for Vector
513 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
514 mReader(reader)
515 { strlcpy(mName, name, sizeof(mName)); }
516 ~NamedReader() { }
517 const sp<NBLog::Reader>& reader() const { return mReader; }
518 const char* name() const { return mName; }
519
520private:
521 sp<NBLog::Reader> mReader;
522 static const size_t kMaxName = 32;
523 char mName[kMaxName];
524};
525
526// ---------------------------------------------------------------------------
527
528class Merger : public RefBase {
529public:
530 Merger(const void *shared, size_t size);
531
532 virtual ~Merger() {}
533
534 void addReader(const NamedReader &reader);
535 // TODO add removeReader
536 void merge();
Glenn Kasten1c446272017-04-07 09:49:07 -0700537 // FIXME This is returning a reference to a shared variable that needs a lock
538 const std::vector<NamedReader>& getNamedReaders() const;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800539private:
540 // vector of the readers the merger is supposed to merge from.
541 // every reader reads from a writer's buffer
Glenn Kasten1c446272017-04-07 09:49:07 -0700542 // FIXME Needs to be protected by a lock
Nicolas Roulet40a44982017-02-03 13:39:57 -0800543 std::vector<NamedReader> mNamedReaders;
Glenn Kasten1c446272017-04-07 09:49:07 -0700544
545 // TODO Need comments on all of these
Nicolas Roulet40a44982017-02-03 13:39:57 -0800546 Shared * const mShared;
547 std::unique_ptr<audio_utils_fifo> mFifo;
548 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800549};
550
551class MergeReader : public Reader {
552public:
553 MergeReader(const void *shared, size_t size, Merger &merger);
554private:
Glenn Kasten1c446272017-04-07 09:49:07 -0700555 // FIXME Needs to be protected by a lock,
556 // because even though our use of it is read-only there may be asynchronous updates
557 const std::vector<NamedReader>& mNamedReaders;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800558 // handle author entry by looking up the author's name and appending it to the body
559 // returns number of bytes read from fmtEntry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700560 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800561};
562
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800563// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
564// when triggered, it awakes for a lapse of time, during which it periodically merges; if
565// retriggered, the timeout is reset.
566// The thread is triggered on AudioFlinger binder activity.
567class MergeThread : public Thread {
568public:
569 MergeThread(Merger &merger);
570 virtual ~MergeThread() override;
571
572 // Reset timeout and activate thread to merge periodically if it's idle
573 void wakeup();
574
575 // Set timeout period until the merging thread goes idle again
576 void setTimeoutUs(int time);
577
578private:
579 virtual bool threadLoop() override;
580
581 // the merger who actually does the work of merging the logs
582 Merger& mMerger;
583
584 // mutex for the condition variable
585 Mutex mMutex;
586
587 // condition variable to activate merging on timeout >= 0
588 Condition mCond;
589
590 // time left until the thread blocks again (in microseconds)
591 int mTimeoutUs;
592
593 // merging period when the thread is awake
594 static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
595
596 // initial timeout value when triggered
597 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
598};
599
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800600}; // class NBLog
601
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700602// TODO put somewhere else
603static inline int64_t get_monotonic_ns() {
604 timespec ts;
605 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
606 return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
607 }
608 return 0; // should not happen.
609}
610
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800611} // namespace android
612
613#endif // ANDROID_MEDIA_NBLOG_H