Home | History | Annotate | Download | only in nbaio
      1 /*
      2  * Copyright (C) 2017 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 <map>
     28 #include <deque>
     29 #include <set>
     30 #include <vector>
     31 
     32 namespace android {
     33 
     34 class String8;
     35 
     36 class NBLog {
     37 
     38 public:
     39 
     40 typedef uint64_t log_hash_t;
     41 
     42 // FIXME Everything needed for client (writer API and registration) should be isolated
     43 //       from the rest of the implementation.
     44 class Writer;
     45 class Reader;
     46 
     47 enum Event : uint8_t {
     48     EVENT_RESERVED,
     49     EVENT_STRING,               // ASCII string, not NUL-terminated
     50     // TODO: make timestamp optional
     51     EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
     52     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
     56     EVENT_START_FMT,            // logFormat start event: entry includes format string, following
     57                                 // entries contain format arguments
     58     EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
     59                                 // and line number
     60     EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
     61     EVENT_AUDIO_STATE,          // audio on/off event: logged upon FastMixer::onStateChange() call
     62     EVENT_END_FMT,              // end of logFormat argument list
     63 
     64     EVENT_UPPER_BOUND,          // to check for invalid events
     65 };
     66 
     67 private:
     68 
     69 // ---------------------------------------------------------------------------
     70 // API for handling format entry operations
     71 
     72 // a formatted entry has the following structure:
     73 //    * START_FMT entry, containing the format string
     74 //    * TIMESTAMP entry
     75 //    * HASH entry
     76 //    * author entry of the thread that generated it (optional, present in merged log)
     77 //    * format arg1
     78 //    * format arg2
     79 //    * ...
     80 //    * END_FMT entry
     81 
     82 // entry representation in memory
     83 struct entry {
     84     const uint8_t type;
     85     const uint8_t length;
     86     const uint8_t data[0];
     87 };
     88 
     89 // entry tail representation (after data)
     90 struct ending {
     91     uint8_t length;
     92     uint8_t next[0];
     93 };
     94 
     95 // entry iterator
     96 class EntryIterator {
     97 public:
     98     EntryIterator();
     99     explicit EntryIterator(const uint8_t *entry);
    100     EntryIterator(const EntryIterator &other);
    101 
    102     // dereference underlying entry
    103     const entry&    operator*() const;
    104     const entry*    operator->() const;
    105     // advance to next entry
    106     EntryIterator&       operator++(); // ++i
    107     // back to previous entry
    108     EntryIterator&       operator--(); // --i
    109     EntryIterator        next() const;
    110     EntryIterator        prev() const;
    111     bool            operator!=(const EntryIterator &other) const;
    112     int             operator-(const EntryIterator &other) const;
    113 
    114     bool            hasConsistentLength() const;
    115     void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
    116     void            copyData(uint8_t *dst) const;
    117 
    118     template<typename T>
    119     inline const T& payload() {
    120         return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
    121     }
    122 
    123     inline operator const uint8_t*() const {
    124         return ptr;
    125     }
    126 
    127 private:
    128     const uint8_t  *ptr;
    129 };
    130 
    131 class AbstractEntry {
    132 public:
    133 
    134     // Entry starting in the given pointer
    135     explicit AbstractEntry(const uint8_t *entry);
    136     virtual ~AbstractEntry() {}
    137 
    138     // build concrete entry of appropriate class from pointer
    139     static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
    140 
    141     // get format entry timestamp
    142     // TODO consider changing to uint64_t
    143     virtual int64_t      timestamp() const = 0;
    144 
    145     // get format entry's unique id
    146     virtual log_hash_t   hash() const = 0;
    147 
    148     // entry's author index (-1 if none present)
    149     // a Merger has a vector of Readers, author simply points to the index of the
    150     // Reader that originated the entry
    151     // TODO consider changing to uint32_t
    152     virtual int          author() const = 0;
    153 
    154     // copy entry, adding author before timestamp, returns iterator to end of entry
    155     virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
    156                                        int author) const = 0;
    157 
    158 protected:
    159     // copies ordinary entry from src to dst, and returns length of entry
    160     // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
    161     const uint8_t  *mEntry;
    162 };
    163 
    164 class FormatEntry : public AbstractEntry {
    165 public:
    166     // explicit FormatEntry(const EntryIterator &it);
    167     explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
    168     virtual ~FormatEntry() {}
    169 
    170     EntryIterator begin() const;
    171 
    172     // Entry's format string
    173     const   char* formatString() const;
    174 
    175     // Enrty's format string length
    176             size_t      formatStringLength() const;
    177 
    178     // Format arguments (excluding format string, timestamp and author)
    179             EntryIterator    args() const;
    180 
    181     // get format entry timestamp
    182     virtual int64_t     timestamp() const override;
    183 
    184     // get format entry's unique id
    185     virtual log_hash_t  hash() const override;
    186 
    187     // entry's author index (-1 if none present)
    188     // a Merger has a vector of Readers, author simply points to the index of the
    189     // Reader that originated the entry
    190     virtual int         author() const override;
    191 
    192     // copy entry, adding author before timestamp, returns size of original entry
    193     virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
    194                                        int author) const override;
    195 
    196 };
    197 
    198 class HistogramEntry : public AbstractEntry {
    199 public:
    200     explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
    201     }
    202     virtual ~HistogramEntry() {}
    203 
    204     virtual int64_t     timestamp() const override;
    205 
    206     virtual log_hash_t  hash() const override;
    207 
    208     virtual int         author() const override;
    209 
    210     virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
    211                                        int author) const override;
    212 
    213 };
    214 
    215 // ---------------------------------------------------------------------------
    216 
    217 // representation of a single log entry in private memory
    218 struct Entry {
    219     Entry(Event event, const void *data, size_t length)
    220         : mEvent(event), mLength(length), mData(data) { }
    221     /*virtual*/ ~Entry() { }
    222 
    223     // used during writing to format Entry information as follows: [type][length][data ... ][length]
    224     int     copyEntryDataAt(size_t offset) const;
    225 
    226 private:
    227     friend class Writer;
    228     Event       mEvent;     // event type
    229     uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
    230     const void *mData;      // event type-specific data
    231     static const size_t kMaxLength = 255;
    232 public:
    233     // mEvent, mLength, mData[...], duplicate mLength
    234     static const size_t kOverhead = sizeof(entry) + sizeof(ending);
    235     // endind length of previous entry
    236     static const size_t kPreviousLengthOffset = - sizeof(ending) +
    237                                                 offsetof(ending, length);
    238 };
    239 
    240 struct HistTsEntry {
    241     log_hash_t hash;
    242     int64_t ts;
    243 }; //TODO __attribute__((packed));
    244 
    245 struct HistTsEntryWithAuthor {
    246     log_hash_t hash;
    247     int64_t ts;
    248     int author;
    249 }; //TODO __attribute__((packed));
    250 
    251 using StateTsEntryWithAuthor = HistTsEntryWithAuthor;
    252 
    253 struct HistIntEntry {
    254     log_hash_t hash;
    255     int value;
    256 }; //TODO __attribute__((packed));
    257 
    258 // representation of a single log entry in shared memory
    259 //  byte[0]             mEvent
    260 //  byte[1]             mLength
    261 //  byte[2]             mData[0]
    262 //  ...
    263 //  byte[2+i]           mData[i]
    264 //  ...
    265 //  byte[2+mLength-1]   mData[mLength-1]
    266 //  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
    267 //  byte[3+mLength]     start of next log entry
    268 
    269     static void    appendInt(String8 *body, const void *data);
    270     static void    appendFloat(String8 *body, const void *data);
    271     static void    appendPID(String8 *body, const void *data, size_t length);
    272     static void    appendTimestamp(String8 *body, const void *data);
    273     static size_t  fmtEntryLength(const uint8_t *data);
    274     static String8 bufferDump(const uint8_t *buffer, size_t size);
    275     static String8 bufferDump(const EntryIterator &it);
    276 public:
    277 
    278 // Located in shared memory, must be POD.
    279 // Exactly one process must explicitly call the constructor or use placement new.
    280 // Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
    281 struct Shared {
    282     Shared() /* mRear initialized via default constructor */ { }
    283     /*virtual*/ ~Shared() { }
    284 
    285     audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
    286     char    mBuffer[0];             // circular buffer for entries
    287 };
    288 
    289 public:
    290 
    291 // ---------------------------------------------------------------------------
    292 
    293 // FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
    294 // For now it is just a namespace for sharedSize().
    295 class Timeline : public RefBase {
    296 public:
    297 #if 0
    298     Timeline(size_t size, void *shared = NULL);
    299     virtual ~Timeline();
    300 #endif
    301 
    302     // Input parameter 'size' is the desired size of the timeline in byte units.
    303     // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
    304     static size_t sharedSize(size_t size);
    305 
    306 #if 0
    307 private:
    308     friend class    Writer;
    309     friend class    Reader;
    310 
    311     const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
    312     bool            mOwn;       // whether I own the memory at mShared
    313     Shared* const   mShared;    // pointer to shared memory
    314 #endif
    315 };
    316 
    317 // ---------------------------------------------------------------------------
    318 
    319 // Writer is thread-safe with respect to Reader, but not with respect to multiple threads
    320 // calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
    321 class Writer : public RefBase {
    322 public:
    323     Writer();                   // dummy nop implementation without shared memory
    324 
    325     // Input parameter 'size' is the desired size of the timeline in byte units.
    326     // The size of the shared memory must be at least Timeline::sharedSize(size).
    327     Writer(void *shared, size_t size);
    328     Writer(const sp<IMemory>& iMemory, size_t size);
    329 
    330     virtual ~Writer();
    331 
    332     // FIXME needs comments, and some should be private
    333     virtual void    log(const char *string);
    334     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
    335     virtual void    logvf(const char *fmt, va_list ap);
    336     virtual void    logTimestamp();
    337     virtual void    logTimestamp(const int64_t ts);
    338     virtual void    logInteger(const int x);
    339     virtual void    logFloat(const float x);
    340     virtual void    logPID();
    341     virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
    342     virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
    343     virtual void    logStart(const char *fmt);
    344     virtual void    logEnd();
    345     virtual void    logHash(log_hash_t hash);
    346     virtual void    logEventHistTs(Event event, log_hash_t hash);
    347 
    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 
    357 private:
    358     // 0 <= length <= kMaxLength
    359     // writes a single Entry to the FIFO
    360     void    log(Event event, const void *data, size_t length);
    361     // checks validity of an event before calling log above this one
    362     void    log(const Entry *entry, bool trusted = false);
    363 
    364     Shared* const   mShared;    // raw pointer to shared memory
    365     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
    370     bool            mEnabled;   // whether to actually log
    371 
    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;
    376 };
    377 
    378 // ---------------------------------------------------------------------------
    379 
    380 // Similar to Writer, but safe for multiple threads to call concurrently
    381 class LockedWriter : public Writer {
    382 public:
    383     LockedWriter();
    384     LockedWriter(void *shared, size_t size);
    385 
    386     virtual void    log(const char *string);
    387     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
    388     virtual void    logvf(const char *fmt, va_list ap);
    389     virtual void    logTimestamp();
    390     virtual void    logTimestamp(const int64_t ts);
    391     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();
    396     virtual void    logHash(log_hash_t hash);
    397 
    398     virtual bool    isEnabled() const;
    399     virtual bool    setEnabled(bool enabled);
    400 
    401 private:
    402     mutable Mutex   mLock;
    403 };
    404 
    405 // ---------------------------------------------------------------------------
    406 
    407 class Reader : public RefBase {
    408 public:
    409 
    410     // A snapshot of a readers buffer
    411     // This is raw data. No analysis has been done on it
    412     class Snapshot {
    413     public:
    414         Snapshot() : mData(NULL), mLost(0) {}
    415 
    416         Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
    417 
    418         ~Snapshot() { delete[] mData; }
    419 
    420         // copy of the buffer
    421         uint8_t *data() const { return mData; }
    422 
    423         // amount of data lost (given by audio_utils_fifo_reader)
    424         size_t   lost() const { return mLost; }
    425 
    426         // iterator to beginning of readable segment of snapshot
    427         // data between begin and end has valid entries
    428         EntryIterator begin() { return mBegin; }
    429 
    430         // iterator to end of readable segment of snapshot
    431         EntryIterator end() { return mEnd; }
    432 
    433     private:
    434         friend class Reader;
    435         uint8_t              *mData;
    436         size_t                mLost;
    437         EntryIterator mBegin;
    438         EntryIterator mEnd;
    439     };
    440 
    441     // Input parameter 'size' is the desired size of the timeline in byte units.
    442     // The size of the shared memory must be at least Timeline::sharedSize(size).
    443     Reader(const void *shared, size_t size);
    444     Reader(const sp<IMemory>& iMemory, size_t size);
    445 
    446     virtual ~Reader();
    447 
    448     // get snapshot of readers fifo buffer, effectively consuming the buffer
    449     std::unique_ptr<Snapshot> getSnapshot();
    450     // dump a particular snapshot of the reader
    451     // TODO: move dump to PerformanceAnalysis. Model/view/controller design
    452     void     dump(int fd, size_t indent, Snapshot & snap);
    453     // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
    454     void     dump(int fd, size_t indent = 0);
    455     bool     isIMemory(const sp<IMemory>& iMemory) const;
    456 
    457 private:
    458 
    459     static const std::set<Event> startingTypes;
    460     static const std::set<Event> endingTypes;
    461     /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
    462                                         // declared as const because audio_utils_fifo() constructor
    463     sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
    464     int     mFd;                // file descriptor
    465     int     mIndent;            // indentation level
    466     audio_utils_fifo * const mFifo;                 // FIFO itself,
    467                                                     // non-NULL unless constructor fails
    468     audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
    469                                                     // non-NULL unless constructor fails
    470 
    471     // TODO: it might be clearer, instead of a direct map from source location to vector of
    472     // timestamps, if we instead first mapped from source location to an object that
    473     // represented that location. And one_of its fields would be a vector of timestamps.
    474     // That would allow us to record other information about the source location beyond timestamps.
    475     void    dumpLine(const String8& timestamp, String8& body);
    476 
    477     EntryIterator   handleFormat(const FormatEntry &fmtEntry,
    478                                          String8 *timestamp,
    479                                          String8 *body);
    480     // dummy method for handling absent author entry
    481     virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
    482 
    483     // Searches for the last entry of type <type> in the range [front, back)
    484     // back has to be entry-aligned. Returns nullptr if none enconuntered.
    485     static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
    486                                          const std::set<Event> &types);
    487 
    488     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
    489 };
    490 
    491 // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
    492 class NamedReader {
    493 public:
    494     NamedReader() { mName[0] = '\0'; } // for Vector
    495     NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
    496         mReader(reader)
    497         { strlcpy(mName, name, sizeof(mName)); }
    498     ~NamedReader() { }
    499     const sp<NBLog::Reader>&  reader() const { return mReader; }
    500     const char*               name() const { return mName; }
    501 
    502 private:
    503     sp<NBLog::Reader>   mReader;
    504     static const size_t kMaxName = 32;
    505     char                mName[kMaxName];
    506 };
    507 
    508 // ---------------------------------------------------------------------------
    509 
    510 class Merger : public RefBase {
    511 public:
    512     Merger(const void *shared, size_t size);
    513 
    514     virtual ~Merger() {}
    515 
    516     void addReader(const NamedReader &reader);
    517     // TODO add removeReader
    518     void merge();
    519     // FIXME This is returning a reference to a shared variable that needs a lock
    520     const std::vector<NamedReader>& getNamedReaders() const;
    521 private:
    522     // vector of the readers the merger is supposed to merge from.
    523     // every reader reads from a writer's buffer
    524     // FIXME Needs to be protected by a lock
    525     std::vector<NamedReader> mNamedReaders;
    526 
    527     // TODO Need comments on all of these
    528     Shared * const mShared;
    529     std::unique_ptr<audio_utils_fifo> mFifo;
    530     std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
    531 };
    532 
    533 class MergeReader : public Reader {
    534 public:
    535     MergeReader(const void *shared, size_t size, Merger &merger);
    536 private:
    537     // FIXME Needs to be protected by a lock,
    538     //       because even though our use of it is read-only there may be asynchronous updates
    539     const std::vector<NamedReader>& mNamedReaders;
    540     // handle author entry by looking up the author's name and appending it to the body
    541     // returns number of bytes read from fmtEntry
    542     void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
    543 };
    544 
    545 // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
    546 // when triggered, it awakes for a lapse of time, during which it periodically merges; if
    547 // retriggered, the timeout is reset.
    548 // The thread is triggered on AudioFlinger binder activity.
    549 class MergeThread : public Thread {
    550 public:
    551     MergeThread(Merger &merger);
    552     virtual ~MergeThread() override;
    553 
    554     // Reset timeout and activate thread to merge periodically if it's idle
    555     void wakeup();
    556 
    557     // Set timeout period until the merging thread goes idle again
    558     void setTimeoutUs(int time);
    559 
    560 private:
    561     virtual bool threadLoop() override;
    562 
    563     // the merger who actually does the work of merging the logs
    564     Merger&     mMerger;
    565 
    566     // mutex for the condition variable
    567     Mutex       mMutex;
    568 
    569     // condition variable to activate merging on timeout >= 0
    570     Condition   mCond;
    571 
    572     // time left until the thread blocks again (in microseconds)
    573     int         mTimeoutUs;
    574 
    575     // merging period when the thread is awake
    576     static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
    577 
    578     // initial timeout value when triggered
    579     static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
    580 };
    581 
    582 };  // class NBLog
    583 
    584 // TODO put somewhere else
    585 static inline int64_t get_monotonic_ns() {
    586     timespec ts;
    587     if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
    588         return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
    589     }
    590     return 0; // should not happen.
    591 }
    592 
    593 }   // namespace android
    594 
    595 #endif  // ANDROID_MEDIA_NBLOG_H
    596