blob: 043f15eb482e0c0d834b21bb9986950169a2bc7f [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>
23#include <utils/Mutex.h>
Glenn Kasten535e1612016-12-05 12:19:36 -080024#include <audio_utils/fifo.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080025
Nicolas Roulet40a44982017-02-03 13:39:57 -080026#include <vector>
27
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080028namespace android {
29
Glenn Kasten4e01ef62013-07-11 14:29:59 -070030class String8;
31
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080032class NBLog {
33
34public:
35
36class Writer;
37class Reader;
38
39private:
40
41enum Event {
42 EVENT_RESERVED,
43 EVENT_STRING, // ASCII string, not NUL-terminated
44 EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
Nicolas Roulet40a44982017-02-03 13:39:57 -080045 EVENT_INTEGER, // integer value entry
46 EVENT_FLOAT, // floating point value entry
47 EVENT_PID, // process ID and process name
48 EVENT_AUTHOR, // author index (present in merged logs) tracks entry's original log
Nicolas Rouletfe1e1442017-01-30 12:02:03 -080049 EVENT_START_FMT, // logFormat start event: entry includes format string, following
50 // entries contain format arguments
51 EVENT_END_FMT, // end of logFormat argument list
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080052};
53
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080054
55// ---------------------------------------------------------------------------
56// API for handling format entry operations
57
58// a formatted entry has the following structure:
59// * START_FMT entry, containing the format string
60// * author entry of the thread that generated it (optional, present in merged log)
61// * TIMESTAMP entry
62// * format arg1
63// * format arg2
64// * ...
65// * END_FMT entry
66
67class FormatEntry {
68public:
69 // build a Format Entry starting in the given pointer
70 class iterator;
71 explicit FormatEntry(const uint8_t *entry);
72 explicit FormatEntry(const iterator &it);
73
74 // entry representation in memory
75 struct entry {
76 const uint8_t type;
77 const uint8_t length;
78 const uint8_t data[0];
79 };
80
81 // entry tail representation (after data)
82 struct ending {
83 uint8_t length;
84 uint8_t next[0];
85 };
86
87 // entry iterator
88 class iterator {
89 public:
90 iterator(const uint8_t *entry);
91 iterator(const iterator &other);
92
93 // dereference underlying entry
94 const entry& operator*() const;
95 const entry* operator->() const;
96 // advance to next entry
97 iterator& operator++(); // ++i
98 // back to previous entry
99 iterator& operator--(); // --i
100 bool operator!=(const iterator &other) const;
101 int operator-(const iterator &other) const;
102
103 bool hasConsistentLength() const;
104 void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
105 void copyData(uint8_t *dst) const;
106
107 template<typename T>
108 inline const T& payload() {
109 return *reinterpret_cast<const T *>(ptr + 2);
110 }
111
112 private:
113 friend class FormatEntry;
114 const uint8_t *ptr;
115 };
116
117 // Entry's format string
118 const char* formatString() const;
119
120 // Enrty's format string length
121 size_t formatStringLength() const;
122
123 // Format arguments (excluding format string, timestamp and author)
124 iterator args() const;
125
126 // get format entry timestamp
127 timespec timestamp() const;
128
129 // entry's author index (-1 if none present)
130 // a Merger has a vector of Readers, author simply points to the index of the
131 // Reader that originated the entry
132 int author() const;
133
134 // copy entry, adding author before timestamp, returns size of original entry
135 size_t copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
136
137 iterator begin() const;
138
139private:
140 // copies ordinary entry from src to dst, and returns length of entry
141 // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
142 const uint8_t *mEntry;
143};
144
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800145// ---------------------------------------------------------------------------
146
147// representation of a single log entry in private memory
148struct Entry {
149 Entry(Event event, const void *data, size_t length)
150 : mEvent(event), mLength(length), mData(data) { }
151 /*virtual*/ ~Entry() { }
152
153 int readAt(size_t offset) const;
154
155private:
156 friend class Writer;
157 Event mEvent; // event type
Glenn Kasten535e1612016-12-05 12:19:36 -0800158 uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800159 const void *mData; // event type-specific data
Glenn Kasten535e1612016-12-05 12:19:36 -0800160 static const size_t kMaxLength = 255;
161public:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800162 // mEvent, mLength, mData[...], duplicate mLength
163 static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
164 // endind length of previous entry
165 static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
166 offsetof(FormatEntry::ending, length);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800167};
168
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800169// representation of a single log entry in shared memory
170// byte[0] mEvent
171// byte[1] mLength
172// byte[2] mData[0]
173// ...
174// byte[2+i] mData[i]
175// ...
176// byte[2+mLength-1] mData[mLength-1]
177// byte[2+mLength] duplicate copy of mLength to permit reverse scan
178// byte[3+mLength] start of next log entry
179
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800180 static void appendInt(String8 *body, const void *data);
181 static void appendFloat(String8 *body, const void *data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800182 static void appendPID(String8 *body, const void *data, size_t length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800183 static void appendTimestamp(String8 *body, const void *data);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800184 static size_t fmtEntryLength(const uint8_t *data);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800185
Glenn Kasten535e1612016-12-05 12:19:36 -0800186public:
187
188// Located in shared memory, must be POD.
189// Exactly one process must explicitly call the constructor or use placement new.
190// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800191struct Shared {
Glenn Kasten535e1612016-12-05 12:19:36 -0800192 Shared() /* mRear initialized via default constructor */ { }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800193 /*virtual*/ ~Shared() { }
194
Glenn Kasten535e1612016-12-05 12:19:36 -0800195 audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
196 char mBuffer[0]; // circular buffer for entries
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800197};
198
199public:
200
201// ---------------------------------------------------------------------------
202
203// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
204// For now it is just a namespace for sharedSize().
205class Timeline : public RefBase {
206public:
207#if 0
208 Timeline(size_t size, void *shared = NULL);
209 virtual ~Timeline();
210#endif
211
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700212 // Input parameter 'size' is the desired size of the timeline in byte units.
213 // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800214 static size_t sharedSize(size_t size);
215
216#if 0
217private:
218 friend class Writer;
219 friend class Reader;
220
221 const size_t mSize; // circular buffer size in bytes, must be a power of 2
222 bool mOwn; // whether I own the memory at mShared
223 Shared* const mShared; // pointer to shared memory
224#endif
225};
226
227// ---------------------------------------------------------------------------
228
229// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
230// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
231class Writer : public RefBase {
232public:
233 Writer(); // dummy nop implementation without shared memory
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700234
235 // Input parameter 'size' is the desired size of the timeline in byte units.
236 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800237 Writer(void *shared, size_t size);
238 Writer(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700239
Glenn Kasten535e1612016-12-05 12:19:36 -0800240 virtual ~Writer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800241
242 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800243 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800244 virtual void logvf(const char *fmt, va_list ap);
245 virtual void logTimestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800246 virtual void logTimestamp(const struct timespec &ts);
247 virtual void logInteger(const int x);
248 virtual void logFloat(const float x);
249 virtual void logPID();
250 virtual void logFormat(const char *fmt, ...);
251 virtual void logVFormat(const char *fmt, va_list ap);
252 virtual void logStart(const char *fmt);
253 virtual void logEnd();
254
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800255
256 virtual bool isEnabled() const;
257
258 // return value for all of these is the previous isEnabled()
259 virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
260 bool enable() { return setEnabled(true); }
261 bool disable() { return setEnabled(false); }
262
263 sp<IMemory> getIMemory() const { return mIMemory; }
264
265private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800266 // 0 <= length <= kMaxLength
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800267 void log(Event event, const void *data, size_t length);
268 void log(const Entry *entry, bool trusted = false);
269
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800270 Shared* const mShared; // raw pointer to shared memory
Glenn Kasten535e1612016-12-05 12:19:36 -0800271 sp<IMemory> mIMemory; // ref-counted version, initialized in constructor and then const
272 audio_utils_fifo * const mFifo; // FIFO itself,
273 // non-NULL unless constructor fails
274 audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO,
275 // non-NULL unless dummy constructor used
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800276 bool mEnabled; // whether to actually log
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800277
278 // cached pid and process name to use in %p format specifier
279 // total tag length is mPidTagSize and process name is not zero terminated
280 char *mPidTag;
281 size_t mPidTagSize;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800282};
283
284// ---------------------------------------------------------------------------
285
286// Similar to Writer, but safe for multiple threads to call concurrently
287class LockedWriter : public Writer {
288public:
289 LockedWriter();
Glenn Kasten535e1612016-12-05 12:19:36 -0800290 LockedWriter(void *shared, size_t size);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800291
292 virtual void log(const char *string);
Glenn Kastenab7d72f2013-02-27 09:05:28 -0800293 virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800294 virtual void logvf(const char *fmt, va_list ap);
295 virtual void logTimestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800296 virtual void logTimestamp(const struct timespec &ts);
297 virtual void logInteger(const int x);
298 virtual void logFloat(const float x);
299 virtual void logPID();
300 virtual void logStart(const char *fmt);
301 virtual void logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800302
303 virtual bool isEnabled() const;
304 virtual bool setEnabled(bool enabled);
305
306private:
307 mutable Mutex mLock;
308};
309
310// ---------------------------------------------------------------------------
311
312class Reader : public RefBase {
313public:
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700314
Nicolas Roulet40a44982017-02-03 13:39:57 -0800315 // A snapshot of a readers buffer
316 class Snapshot {
317 public:
318 Snapshot() : mData(NULL), mAvail(0), mLost(0) {}
319
320 Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
321
322 ~Snapshot() { delete[] mData; }
323
324 // copy of the buffer
325 const uint8_t *data() const { return mData; }
326
327 // amount of data available (given by audio_utils_fifo_reader)
328 size_t available() const { return mAvail; }
329
330 // amount of data lost (given by audio_utils_fifo_reader)
331 size_t lost() const { return mLost; }
332
333 private:
334 friend class Reader;
335 const uint8_t *mData;
336 size_t mAvail;
337 size_t mLost;
338 };
339
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700340 // Input parameter 'size' is the desired size of the timeline in byte units.
341 // The size of the shared memory must be at least Timeline::sharedSize(size).
Glenn Kasten535e1612016-12-05 12:19:36 -0800342 Reader(const void *shared, size_t size);
343 Reader(const sp<IMemory>& iMemory, size_t size);
Glenn Kastenfb1fdc92013-07-10 17:03:19 -0700344
Glenn Kasten535e1612016-12-05 12:19:36 -0800345 virtual ~Reader();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800346
Nicolas Roulet40a44982017-02-03 13:39:57 -0800347 // get snapshot of readers fifo buffer, effectively consuming the buffer
348 std::unique_ptr<Snapshot> getSnapshot();
349 // dump a particular snapshot of the reader
350 void dump(int fd, size_t indent, Snapshot & snap);
351 // dump the current content of the reader's buffer
352 void dump(int fd, size_t indent = 0);
353 bool isIMemory(const sp<IMemory>& iMemory) const;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800354
355private:
Glenn Kasten535e1612016-12-05 12:19:36 -0800356 /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
357 // declared as const because audio_utils_fifo() constructor
358 sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700359 int mFd; // file descriptor
360 int mIndent; // indentation level
Glenn Kasten535e1612016-12-05 12:19:36 -0800361 audio_utils_fifo * const mFifo; // FIFO itself,
362 // non-NULL unless constructor fails
363 audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
364 // non-NULL unless constructor fails
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700365
366 void dumpLine(const String8& timestamp, String8& body);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800367
368 FormatEntry::iterator handleFormat(const FormatEntry &fmtEntry,
369 String8 *timestamp,
370 String8 *body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800371 // dummy method for handling absent author entry
372 virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800373
374 static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
375};
376
Nicolas Roulet40a44982017-02-03 13:39:57 -0800377// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
378class NamedReader {
379public:
380 NamedReader() { mName[0] = '\0'; } // for Vector
381 NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
382 mReader(reader)
383 { strlcpy(mName, name, sizeof(mName)); }
384 ~NamedReader() { }
385 const sp<NBLog::Reader>& reader() const { return mReader; }
386 const char* name() const { return mName; }
387
388private:
389 sp<NBLog::Reader> mReader;
390 static const size_t kMaxName = 32;
391 char mName[kMaxName];
392};
393
394// ---------------------------------------------------------------------------
395
396class Merger : public RefBase {
397public:
398 Merger(const void *shared, size_t size);
399
400 virtual ~Merger() {}
401
402 void addReader(const NamedReader &reader);
403 // TODO add removeReader
404 void merge();
405 const std::vector<NamedReader> *getNamedReaders() const;
406private:
407 // vector of the readers the merger is supposed to merge from.
408 // every reader reads from a writer's buffer
409 std::vector<NamedReader> mNamedReaders;
410 uint8_t *mBuffer;
411 Shared * const mShared;
412 std::unique_ptr<audio_utils_fifo> mFifo;
413 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
414
415 static struct timespec getTimestamp(const uint8_t *data);
416};
417
418class MergeReader : public Reader {
419public:
420 MergeReader(const void *shared, size_t size, Merger &merger);
421private:
422 const std::vector<NamedReader> *mNamedReaders;
423 // handle author entry by looking up the author's name and appending it to the body
424 // returns number of bytes read from fmtEntry
425 size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
426};
427
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800428}; // class NBLog
429
430} // namespace android
431
432#endif // ANDROID_MEDIA_NBLOG_H