1 /*
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 <audio_utils/fifo.h>
24 #include <utils/Mutex.h>
25 #include <utils/threads.h>
26 
27 #include <vector>
28 
29 namespace android {
30 
31 class String8;
32 
33 class NBLog {
34 
35 public:
36 
37 class Writer;
38 class Reader;
39 
40 private:
41 
42 enum Event {
43     EVENT_RESERVED,
44     EVENT_STRING,               // ASCII string, not NUL-terminated
45     // TODO: make timestamp optional
46     EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
47     EVENT_INTEGER,              // integer value entry
48     EVENT_FLOAT,                // floating point value entry
49     EVENT_PID,                  // process ID and process name
50     EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's original log
51     EVENT_START_FMT,            // logFormat start event: entry includes format string, following
52                                 // entries contain format arguments
53     EVENT_END_FMT,              // end of logFormat argument list
54 };
55 
56 
57 // ---------------------------------------------------------------------------
58 // API for handling format entry operations
59 
60 // a formatted entry has the following structure:
61 //    * START_FMT entry, containing the format string
62 //    * TIMESTAMP entry
63 //    * author entry of the thread that generated it (optional, present in merged log)
64 //    * format arg1
65 //    * format arg2
66 //    * ...
67 //    * END_FMT entry
68 
69 class FormatEntry {
70 public:
71     // build a Format Entry starting in the given pointer
72     class iterator;
73     explicit FormatEntry(const uint8_t *entry);
74     explicit FormatEntry(const iterator &it);
75 
76     // entry representation in memory
77     struct entry {
78         const uint8_t type;
79         const uint8_t length;
80         const uint8_t data[0];
81     };
82 
83     // entry tail representation (after data)
84     struct ending {
85         uint8_t length;
86         uint8_t next[0];
87     };
88 
89     // entry iterator
90     class iterator {
91     public:
92         iterator();
93         iterator(const uint8_t *entry);
94         iterator(const iterator &other);
95 
96         // dereference underlying entry
97         const entry&    operator*() const;
98         const entry*    operator->() const;
99         // advance to next entry
100         iterator&       operator++(); // ++i
101         // back to previous entry
102         iterator&       operator--(); // --i
103         iterator        next() const;
104         iterator        prev() const;
105         bool            operator!=(const iterator &other) const;
106         int             operator-(const iterator &other) const;
107 
108         bool            hasConsistentLength() const;
109         void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
110         void            copyData(uint8_t *dst) const;
111 
112         template<typename T>
payload()113         inline const T& payload() {
114             return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
115         }
116 
117     private:
118         friend class FormatEntry;
119         const uint8_t  *ptr;
120     };
121 
122     // Entry's format string
123     const char* formatString() const;
124 
125     // Enrty's format string length
126     size_t      formatStringLength() const;
127 
128     // Format arguments (excluding format string, timestamp and author)
129     iterator    args() const;
130 
131     // get format entry timestamp
132     timespec    timestamp() const;
133 
134     // entry's author index (-1 if none present)
135     // a Merger has a vector of Readers, author simply points to the index of the
136     // Reader that originated the entry
137     int         author() const;
138 
139     // copy entry, adding author before timestamp, returns size of original entry
140     iterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
141 
142     iterator    begin() const;
143 
144 private:
145     // copies ordinary entry from src to dst, and returns length of entry
146     // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
147     const uint8_t  *mEntry;
148 };
149 
150 // ---------------------------------------------------------------------------
151 
152 // representation of a single log entry in private memory
153 struct Entry {
EntryEntry154     Entry(Event event, const void *data, size_t length)
155         : mEvent(event), mLength(length), mData(data) { }
~EntryEntry156     /*virtual*/ ~Entry() { }
157 
158     int     readAt(size_t offset) const;
159 
160 private:
161     friend class Writer;
162     Event       mEvent;     // event type
163     uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
164     const void *mData;      // event type-specific data
165     static const size_t kMaxLength = 255;
166 public:
167     // mEvent, mLength, mData[...], duplicate mLength
168     static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
169     // endind length of previous entry
170     static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
171                                                 offsetof(FormatEntry::ending, length);
172 };
173 
174 // representation of a single log entry in shared memory
175 //  byte[0]             mEvent
176 //  byte[1]             mLength
177 //  byte[2]             mData[0]
178 //  ...
179 //  byte[2+i]           mData[i]
180 //  ...
181 //  byte[2+mLength-1]   mData[mLength-1]
182 //  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
183 //  byte[3+mLength]     start of next log entry
184 
185     static void    appendInt(String8 *body, const void *data);
186     static void    appendFloat(String8 *body, const void *data);
187     static void    appendPID(String8 *body, const void *data, size_t length);
188     static void    appendTimestamp(String8 *body, const void *data);
189     static size_t  fmtEntryLength(const uint8_t *data);
190 
191 public:
192 
193 // Located in shared memory, must be POD.
194 // Exactly one process must explicitly call the constructor or use placement new.
195 // Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
196 struct Shared {
SharedShared197     Shared() /* mRear initialized via default constructor */ { }
~SharedShared198     /*virtual*/ ~Shared() { }
199 
200     audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
201     char    mBuffer[0];             // circular buffer for entries
202 };
203 
204 public:
205 
206 // ---------------------------------------------------------------------------
207 
208 // FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
209 // For now it is just a namespace for sharedSize().
210 class Timeline : public RefBase {
211 public:
212 #if 0
213     Timeline(size_t size, void *shared = NULL);
214     virtual ~Timeline();
215 #endif
216 
217     // Input parameter 'size' is the desired size of the timeline in byte units.
218     // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
219     static size_t sharedSize(size_t size);
220 
221 #if 0
222 private:
223     friend class    Writer;
224     friend class    Reader;
225 
226     const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
227     bool            mOwn;       // whether I own the memory at mShared
228     Shared* const   mShared;    // pointer to shared memory
229 #endif
230 };
231 
232 // ---------------------------------------------------------------------------
233 
234 // Writer is thread-safe with respect to Reader, but not with respect to multiple threads
235 // calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
236 class Writer : public RefBase {
237 public:
238     Writer();                   // dummy nop implementation without shared memory
239 
240     // Input parameter 'size' is the desired size of the timeline in byte units.
241     // The size of the shared memory must be at least Timeline::sharedSize(size).
242     Writer(void *shared, size_t size);
243     Writer(const sp<IMemory>& iMemory, size_t size);
244 
245     virtual ~Writer();
246 
247     virtual void    log(const char *string);
248     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
249     virtual void    logvf(const char *fmt, va_list ap);
250     virtual void    logTimestamp();
251     virtual void    logTimestamp(const struct timespec &ts);
252     virtual void    logInteger(const int x);
253     virtual void    logFloat(const float x);
254     virtual void    logPID();
255     virtual void    logFormat(const char *fmt, ...);
256     virtual void    logVFormat(const char *fmt, va_list ap);
257     virtual void    logStart(const char *fmt);
258     virtual void    logEnd();
259 
260 
261     virtual bool    isEnabled() const;
262 
263     // return value for all of these is the previous isEnabled()
264     virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
enable()265             bool    enable()    { return setEnabled(true); }
disable()266             bool    disable()   { return setEnabled(false); }
267 
getIMemory()268     sp<IMemory>     getIMemory() const  { return mIMemory; }
269 
270 private:
271     // 0 <= length <= kMaxLength
272     void    log(Event event, const void *data, size_t length);
273     void    log(const Entry *entry, bool trusted = false);
274 
275     Shared* const   mShared;    // raw pointer to shared memory
276     sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor and then const
277     audio_utils_fifo * const mFifo;                 // FIFO itself,
278                                                     // non-NULL unless constructor fails
279     audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO,
280                                                     // non-NULL unless dummy constructor used
281     bool            mEnabled;   // whether to actually log
282 
283     // cached pid and process name to use in %p format specifier
284     // total tag length is mPidTagSize and process name is not zero terminated
285     char   *mPidTag;
286     size_t  mPidTagSize;
287 };
288 
289 // ---------------------------------------------------------------------------
290 
291 // Similar to Writer, but safe for multiple threads to call concurrently
292 class LockedWriter : public Writer {
293 public:
294     LockedWriter();
295     LockedWriter(void *shared, size_t size);
296 
297     virtual void    log(const char *string);
298     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
299     virtual void    logvf(const char *fmt, va_list ap);
300     virtual void    logTimestamp();
301     virtual void    logTimestamp(const struct timespec &ts);
302     virtual void    logInteger(const int x);
303     virtual void    logFloat(const float x);
304     virtual void    logPID();
305     virtual void    logStart(const char *fmt);
306     virtual void    logEnd();
307 
308     virtual bool    isEnabled() const;
309     virtual bool    setEnabled(bool enabled);
310 
311 private:
312     mutable Mutex   mLock;
313 };
314 
315 // ---------------------------------------------------------------------------
316 
317 class Reader : public RefBase {
318 public:
319 
320     // A snapshot of a readers buffer
321     class Snapshot {
322     public:
Snapshot()323         Snapshot() : mData(NULL), mLost(0) {}
324 
Snapshot(size_t bufferSize)325         Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
326 
~Snapshot()327         ~Snapshot() { delete[] mData; }
328 
329         // copy of the buffer
data()330         uint8_t *data() const { return mData; }
331 
332         // amount of data lost (given by audio_utils_fifo_reader)
lost()333         size_t   lost() const { return mLost; }
334 
335         // iterator to beginning of readable segment of snapshot
336         // data between begin and end has valid entries
begin()337         FormatEntry::iterator begin() { return mBegin; }
338 
339         // iterator to end of readable segment of snapshot
end()340         FormatEntry::iterator end() { return mEnd; }
341 
342 
343     private:
344         friend class Reader;
345         uint8_t              *mData;
346         size_t                mLost;
347         FormatEntry::iterator mBegin;
348         FormatEntry::iterator mEnd;
349     };
350 
351     // Input parameter 'size' is the desired size of the timeline in byte units.
352     // The size of the shared memory must be at least Timeline::sharedSize(size).
353     Reader(const void *shared, size_t size);
354     Reader(const sp<IMemory>& iMemory, size_t size);
355 
356     virtual ~Reader();
357 
358     // get snapshot of readers fifo buffer, effectively consuming the buffer
359     std::unique_ptr<Snapshot> getSnapshot();
360     // dump a particular snapshot of the reader
361     void     dump(int fd, size_t indent, Snapshot & snap);
362     // dump the current content of the reader's buffer
363     void     dump(int fd, size_t indent = 0);
364     bool     isIMemory(const sp<IMemory>& iMemory) const;
365 
366 private:
367     /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
368                                         // declared as const because audio_utils_fifo() constructor
369     sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
370     int     mFd;                // file descriptor
371     int     mIndent;            // indentation level
372     audio_utils_fifo * const mFifo;                 // FIFO itself,
373                                                     // non-NULL unless constructor fails
374     audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
375                                                     // non-NULL unless constructor fails
376 
377     void    dumpLine(const String8& timestamp, String8& body);
378 
379     FormatEntry::iterator   handleFormat(const FormatEntry &fmtEntry,
380                                          String8 *timestamp,
381                                          String8 *body);
382     // dummy method for handling absent author entry
handleAuthor(const FormatEntry & fmtEntry,String8 * body)383     virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; }
384 
385     // Searches for the last entry of type <type> in the range [front, back)
386     // back has to be entry-aligned. Returns nullptr if none enconuntered.
387     static uint8_t *findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type);
388 
389     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
390 };
391 
392 // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
393 class NamedReader {
394 public:
NamedReader()395     NamedReader() { mName[0] = '\0'; } // for Vector
NamedReader(const sp<NBLog::Reader> & reader,const char * name)396     NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
397         mReader(reader)
398         { strlcpy(mName, name, sizeof(mName)); }
~NamedReader()399     ~NamedReader() { }
reader()400     const sp<NBLog::Reader>&  reader() const { return mReader; }
name()401     const char*               name() const { return mName; }
402 
403 private:
404     sp<NBLog::Reader>   mReader;
405     static const size_t kMaxName = 32;
406     char                mName[kMaxName];
407 };
408 
409 // ---------------------------------------------------------------------------
410 
411 class Merger : public RefBase {
412 public:
413     Merger(const void *shared, size_t size);
414 
~Merger()415     virtual ~Merger() {}
416 
417     void addReader(const NamedReader &reader);
418     // TODO add removeReader
419     void merge();
420     const std::vector<NamedReader> *getNamedReaders() const;
421 private:
422     // vector of the readers the merger is supposed to merge from.
423     // every reader reads from a writer's buffer
424     std::vector<NamedReader> mNamedReaders;
425     uint8_t *mBuffer;
426     Shared * const mShared;
427     std::unique_ptr<audio_utils_fifo> mFifo;
428     std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
429 
430     static struct timespec getTimestamp(const uint8_t *data);
431 };
432 
433 class MergeReader : public Reader {
434 public:
435     MergeReader(const void *shared, size_t size, Merger &merger);
436 private:
437     const std::vector<NamedReader> *mNamedReaders;
438     // handle author entry by looking up the author's name and appending it to the body
439     // returns number of bytes read from fmtEntry
440     size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
441 };
442 
443 // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
444 // when triggered, it awakes for a lapse of time, during which it periodically merges; if
445 // retriggered, the timeout is reset.
446 // The thread is triggered on AudioFlinger binder activity.
447 class MergeThread : public Thread {
448 public:
449     MergeThread(Merger &merger);
450     virtual ~MergeThread() override;
451 
452     // Reset timeout and activate thread to merge periodically if it's idle
453     void wakeup();
454 
455     // Set timeout period until the merging thread goes idle again
456     void setTimeoutUs(int time);
457 
458 private:
459     virtual bool threadLoop() override;
460 
461     // the merger who actually does the work of merging the logs
462     Merger&     mMerger;
463 
464     // mutex for the condition variable
465     Mutex       mMutex;
466 
467     // condition variable to activate merging on timeout >= 0
468     Condition   mCond;
469 
470     // time left until the thread blocks again (in microseconds)
471     int         mTimeoutUs;
472 
473     // merging period when the thread is awake
474     static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
475 
476     // initial timeout value when triggered
477     static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
478 };
479 
480 };  // class NBLog
481 
482 }   // namespace android
483 
484 #endif  // ANDROID_MEDIA_NBLOG_H
485