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