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