blob: 7936ad226355a46b664b747ace3a563fad9ac90b [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#define LOG_TAG "NBLog"
18//#define LOG_NDEBUG 0
19
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -080020#include <climits>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080021#include <stdarg.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <string.h>
Nicolas Rouletc20cb502017-02-01 12:35:24 -080025#include <sys/prctl.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080026#include <time.h>
27#include <new>
Glenn Kasten535e1612016-12-05 12:19:36 -080028#include <audio_utils/roundup.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080029#include <media/nbaio/NBLog.h>
30#include <utils/Log.h>
Glenn Kasten4e01ef62013-07-11 14:29:59 -070031#include <utils/String8.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080032
Nicolas Roulet40a44982017-02-03 13:39:57 -080033#include <queue>
34
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080035namespace android {
36
37int NBLog::Entry::readAt(size_t offset) const
38{
39 // FIXME This is too slow, despite the name it is used during writing
40 if (offset == 0)
41 return mEvent;
42 else if (offset == 1)
43 return mLength;
44 else if (offset < (size_t) (mLength + 2))
45 return ((char *) mData)[offset - 2];
46 else if (offset == (size_t) (mLength + 2))
47 return mLength;
48 else
49 return 0;
50}
51
52// ---------------------------------------------------------------------------
53
Nicolas Roulet40a44982017-02-03 13:39:57 -080054NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080055 ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
56 "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
Nicolas Roulet40a44982017-02-03 13:39:57 -080057}
58
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080059NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}
60
Nicolas Roulet40a44982017-02-03 13:39:57 -080061const char *NBLog::FormatEntry::formatString() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080062 return (const char*) mEntry + offsetof(entry, data);
Nicolas Roulet40a44982017-02-03 13:39:57 -080063}
64
65size_t NBLog::FormatEntry::formatStringLength() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080066 return mEntry[offsetof(entry, length)];
Nicolas Roulet40a44982017-02-03 13:39:57 -080067}
68
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080069NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
70 auto it = begin();
71 // Second entry can be author or timestamp. Skip author if present
72 if ((++it)->type == EVENT_AUTHOR) {
73 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080074 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080075 return ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080076}
77
78timespec NBLog::FormatEntry::timestamp() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080079 auto it = begin();
80 if ((++it)->type != EVENT_TIMESTAMP) {
81 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080082 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080083 return it.payload<timespec>();
Nicolas Roulet40a44982017-02-03 13:39:57 -080084}
85
86pid_t NBLog::FormatEntry::author() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080087 auto it = begin();
88 if ((++it)->type == EVENT_AUTHOR) {
89 return it.payload<int>();
Nicolas Roulet40a44982017-02-03 13:39:57 -080090 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080091 return -1;
Nicolas Roulet40a44982017-02-03 13:39:57 -080092}
93
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -080094NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor(
95 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
96 auto it = begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -080097 // copy fmt start entry
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080098 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -080099 // insert author entry
100 size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
101 uint8_t authorEntry[authorEntrySize];
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800102 authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
103 authorEntry[offsetof(entry, length)] =
104 authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
105 sizeof(author);
106 *(int*) (&authorEntry[offsetof(entry, data)]) = author;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800107 dst->write(authorEntry, authorEntrySize);
108 // copy rest of entries
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800109 while ((++it)->type != EVENT_END_FMT) {
110 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800111 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800112 it.copyTo(dst);
113 ++it;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800114 return it;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800115}
116
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800117void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
118 size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
119 dst->write(ptr, length);
120}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800121
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800122void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
123 memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
124}
125
126NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
127 return iterator(mEntry);
128}
129
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800130NBLog::FormatEntry::iterator::iterator()
131 : ptr(nullptr) {}
132
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800133NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
134 : ptr(entry) {}
135
136NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
137 : ptr(other.ptr) {}
138
139const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
140 return *(entry*) ptr;
141}
142
143const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
144 return (entry*) ptr;
145}
146
147NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
148 ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
149 return *this;
150}
151
152NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
153 ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
154 return *this;
155}
156
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800157NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const {
158 iterator aux(*this);
159 return ++aux;
160}
161
162NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const {
163 iterator aux(*this);
164 return --aux;
165}
166
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800167int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
168 return ptr - other.ptr;
169}
170
171bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
172 return ptr != other.ptr;
173}
174
175bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
176 return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
177 NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
Nicolas Roulet40a44982017-02-03 13:39:57 -0800178}
179
180// ---------------------------------------------------------------------------
181
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800182#if 0 // FIXME see note in NBLog.h
183NBLog::Timeline::Timeline(size_t size, void *shared)
184 : mSize(roundup(size)), mOwn(shared == NULL),
185 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
186{
187 new (mShared) Shared;
188}
189
190NBLog::Timeline::~Timeline()
191{
192 mShared->~Shared();
193 if (mOwn) {
194 delete[] (char *) mShared;
195 }
196}
197#endif
198
199/*static*/
200size_t NBLog::Timeline::sharedSize(size_t size)
201{
Glenn Kastened99c2b2016-12-12 08:31:24 -0800202 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800203 return sizeof(Shared) + roundup(size);
204}
205
206// ---------------------------------------------------------------------------
207
208NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800209 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800210{
211}
212
Glenn Kasten535e1612016-12-05 12:19:36 -0800213NBLog::Writer::Writer(void *shared, size_t size)
214 : mShared((Shared *) shared),
215 mFifo(mShared != NULL ?
216 new audio_utils_fifo(size, sizeof(uint8_t),
217 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
218 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
219 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800220{
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800221 // caching pid and process name
222 pid_t id = ::getpid();
223 char procName[16];
224 int status = prctl(PR_GET_NAME, procName);
225 if (status) { // error getting process name
226 procName[0] = '\0';
227 }
228 size_t length = strlen(procName);
229 mPidTagSize = length + sizeof(pid_t);
230 mPidTag = new char[mPidTagSize];
231 memcpy(mPidTag, &id, sizeof(pid_t));
232 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800233}
234
Glenn Kasten535e1612016-12-05 12:19:36 -0800235NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
236 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800237{
Glenn Kasten535e1612016-12-05 12:19:36 -0800238 mIMemory = iMemory;
239}
240
241NBLog::Writer::~Writer()
242{
243 delete mFifoWriter;
244 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800245 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800246}
247
248void NBLog::Writer::log(const char *string)
249{
250 if (!mEnabled) {
251 return;
252 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800253 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800254 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800255 if (length > Entry::kMaxLength) {
256 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800257 }
258 log(EVENT_STRING, string, length);
259}
260
261void NBLog::Writer::logf(const char *fmt, ...)
262{
263 if (!mEnabled) {
264 return;
265 }
266 va_list ap;
267 va_start(ap, fmt);
268 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
269 va_end(ap);
270}
271
272void NBLog::Writer::logvf(const char *fmt, va_list ap)
273{
274 if (!mEnabled) {
275 return;
276 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800277 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800278 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
279 if (length >= (int) sizeof(buffer)) {
280 length = sizeof(buffer) - 1;
281 // NUL termination is not required
282 // buffer[length] = '\0';
283 }
284 if (length >= 0) {
285 log(EVENT_STRING, buffer, length);
286 }
287}
288
289void NBLog::Writer::logTimestamp()
290{
291 if (!mEnabled) {
292 return;
293 }
294 struct timespec ts;
295 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800296 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800297 }
298}
299
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800300void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800301{
302 if (!mEnabled) {
303 return;
304 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800305 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
306}
307
308void NBLog::Writer::logInteger(const int x)
309{
310 if (!mEnabled) {
311 return;
312 }
313 log(EVENT_INTEGER, &x, sizeof(x));
314}
315
316void NBLog::Writer::logFloat(const float x)
317{
318 if (!mEnabled) {
319 return;
320 }
321 log(EVENT_FLOAT, &x, sizeof(x));
322}
323
324void NBLog::Writer::logPID()
325{
326 if (!mEnabled) {
327 return;
328 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800329 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800330}
331
332void NBLog::Writer::logStart(const char *fmt)
333{
334 if (!mEnabled) {
335 return;
336 }
337 size_t length = strlen(fmt);
338 if (length > Entry::kMaxLength) {
339 length = Entry::kMaxLength;
340 }
341 log(EVENT_START_FMT, fmt, length);
342}
343
344void NBLog::Writer::logEnd()
345{
346 if (!mEnabled) {
347 return;
348 }
349 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
350 log(&entry, true);
351}
352
353void NBLog::Writer::logFormat(const char *fmt, ...)
354{
355 if (!mEnabled) {
356 return;
357 }
358
359 va_list ap;
360 va_start(ap, fmt);
361 Writer::logVFormat(fmt, ap);
362 va_end(ap);
363}
364
365void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
366{
367 if (!mEnabled) {
368 return;
369 }
370 Writer::logStart(fmt);
371 int i;
372 double f;
373 char* s;
374 struct timespec t;
375 Writer::logTimestamp();
376 for (const char *p = fmt; *p != '\0'; p++) {
377 // TODO: implement more complex formatting such as %.3f
378 if (*p != '%') {
379 continue;
380 }
381 switch(*++p) {
382 case 's': // string
383 s = va_arg(argp, char *);
384 Writer::log(s);
385 break;
386
387 case 't': // timestamp
388 t = va_arg(argp, struct timespec);
389 Writer::logTimestamp(t);
390 break;
391
392 case 'd': // integer
393 i = va_arg(argp, int);
394 Writer::logInteger(i);
395 break;
396
397 case 'f': // float
398 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
399 Writer::logFloat((float)f);
400 break;
401
402 case 'p': // pid
403 Writer::logPID();
404 break;
405
406 // the "%\0" case finishes parsing
407 case '\0':
408 --p;
409 break;
410
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800411 case '%':
412 break;
413
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800414 default:
415 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
416 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800417 }
418 }
419 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800420}
421
422void NBLog::Writer::log(Event event, const void *data, size_t length)
423{
424 if (!mEnabled) {
425 return;
426 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800427 if (data == NULL || length > Entry::kMaxLength) {
428 // TODO Perhaps it makes sense to display truncated data or at least a
429 // message that the data is too long? The current behavior can create
430 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800431 return;
432 }
433 switch (event) {
434 case EVENT_STRING:
435 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800436 case EVENT_INTEGER:
437 case EVENT_FLOAT:
438 case EVENT_PID:
439 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800440 break;
441 case EVENT_RESERVED:
442 default:
443 return;
444 }
445 Entry entry(event, data, length);
446 log(&entry, true /*trusted*/);
447}
448
449void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
450{
451 if (!mEnabled) {
452 return;
453 }
454 if (!trusted) {
455 log(entry->mEvent, entry->mData, entry->mLength);
456 return;
457 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800458 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
459 // need = number of bytes remaining to write
460
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800461 // FIXME optimize this using memcpy for the data part of the Entry.
462 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800463 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
464 for (size_t i = 0; i < need; i++) {
465 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800466 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800467 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800468}
469
470bool NBLog::Writer::isEnabled() const
471{
472 return mEnabled;
473}
474
475bool NBLog::Writer::setEnabled(bool enabled)
476{
477 bool old = mEnabled;
478 mEnabled = enabled && mShared != NULL;
479 return old;
480}
481
482// ---------------------------------------------------------------------------
483
484NBLog::LockedWriter::LockedWriter()
485 : Writer()
486{
487}
488
Glenn Kasten535e1612016-12-05 12:19:36 -0800489NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
490 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800491{
492}
493
494void NBLog::LockedWriter::log(const char *string)
495{
496 Mutex::Autolock _l(mLock);
497 Writer::log(string);
498}
499
500void NBLog::LockedWriter::logf(const char *fmt, ...)
501{
502 // FIXME should not take the lock until after formatting is done
503 Mutex::Autolock _l(mLock);
504 va_list ap;
505 va_start(ap, fmt);
506 Writer::logvf(fmt, ap);
507 va_end(ap);
508}
509
510void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
511{
512 // FIXME should not take the lock until after formatting is done
513 Mutex::Autolock _l(mLock);
514 Writer::logvf(fmt, ap);
515}
516
517void NBLog::LockedWriter::logTimestamp()
518{
519 // FIXME should not take the lock until after the clock_gettime() syscall
520 Mutex::Autolock _l(mLock);
521 Writer::logTimestamp();
522}
523
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800524void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800525{
526 Mutex::Autolock _l(mLock);
527 Writer::logTimestamp(ts);
528}
529
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800530void NBLog::LockedWriter::logInteger(const int x)
531{
532 Mutex::Autolock _l(mLock);
533 Writer::logInteger(x);
534}
535
536void NBLog::LockedWriter::logFloat(const float x)
537{
538 Mutex::Autolock _l(mLock);
539 Writer::logFloat(x);
540}
541
542void NBLog::LockedWriter::logPID()
543{
544 Mutex::Autolock _l(mLock);
545 Writer::logPID();
546}
547
548void NBLog::LockedWriter::logStart(const char *fmt)
549{
550 Mutex::Autolock _l(mLock);
551 Writer::logStart(fmt);
552}
553
554
555void NBLog::LockedWriter::logEnd()
556{
557 Mutex::Autolock _l(mLock);
558 Writer::logEnd();
559}
560
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800561bool NBLog::LockedWriter::isEnabled() const
562{
563 Mutex::Autolock _l(mLock);
564 return Writer::isEnabled();
565}
566
567bool NBLog::LockedWriter::setEnabled(bool enabled)
568{
569 Mutex::Autolock _l(mLock);
570 return Writer::setEnabled(enabled);
571}
572
573// ---------------------------------------------------------------------------
574
Glenn Kasten535e1612016-12-05 12:19:36 -0800575NBLog::Reader::Reader(const void *shared, size_t size)
576 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
577 mFd(-1), mIndent(0),
578 mFifo(mShared != NULL ?
579 new audio_utils_fifo(size, sizeof(uint8_t),
580 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
581 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800582{
583}
584
Glenn Kasten535e1612016-12-05 12:19:36 -0800585NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
586 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800587{
Glenn Kasten535e1612016-12-05 12:19:36 -0800588 mIMemory = iMemory;
589}
590
591NBLog::Reader::~Reader()
592{
593 delete mFifoReader;
594 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800595}
596
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800597uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) {
598 while (back + Entry::kPreviousLengthOffset >= front) {
599 uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
600 if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] +
601 Entry::kOverhead != back) {
602
603 // prev points to an out of limits or inconsistent entry
604 return nullptr;
605 }
606 if (prev[offsetof(FormatEntry::entry, type)] == type) {
607 return prev;
608 }
609 back = prev;
610 }
611 return nullptr; // no entry found
612}
613
Nicolas Roulet40a44982017-02-03 13:39:57 -0800614std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800615{
Glenn Kasten535e1612016-12-05 12:19:36 -0800616 if (mFifoReader == NULL) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800617 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800618 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800619 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800620 size_t capacity = mFifo->capacity();
621
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800622 // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
623 // reader index. The index is incremented after handling corruption, to after the last complete
624 // entry of the buffer
625 size_t lost;
626 audio_utils_iovec iovec[2];
627 ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
628 if (availToRead <= 0) {
629 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
630 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800631
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800632 std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
633 memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
634 if (iovec[1].mLength > 0) {
635 memcpy(snapshot->mData + (iovec[0].mLength),
636 (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
637 }
638
639 // Handle corrupted buffer
640 // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
641 // (due to incomplete format entry). But even if the end format entry is incomplete,
642 // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
643 // TODO: handle client corruption (in the middle of a buffer)
644
645 uint8_t *back = snapshot->mData + availToRead;
646 uint8_t *front = snapshot->mData;
647
648 // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
649 // We go backwards until we find an EVENT_END_FMT.
650 uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT);
651 if (lastEnd == nullptr) {
652 snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front);
653 } else {
654 // end of snapshot points to after last END_FMT entry
655 snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead);
656 // find first START_FMT
657 uint8_t *firstStart = nullptr;
658 uint8_t *firstStartTmp = lastEnd;
659 while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT))
660 != nullptr) {
661 firstStart = firstStartTmp;
662 }
663 // firstStart is null if no START_FMT entry was found before lastEnd
664 if (firstStart == nullptr) {
665 snapshot->mBegin = snapshot->mEnd;
666 } else {
667 snapshot->mBegin = FormatEntry::iterator(firstStart);
668 }
669 }
670
671 // advance fifo reader index to after last entry read.
672 mFifoReader->release(snapshot->mEnd - front);
673
674 snapshot->mLost = lost;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800675 return snapshot;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800676
Nicolas Roulet40a44982017-02-03 13:39:57 -0800677}
678
679void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
680{
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800681#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800682 struct timespec ts;
683 time_t maxSec = -1;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800684 while (entry - start >= (int) Entry::kOverhead) {
685 if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800686 break;
687 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800688 if (prevEntry->type == EVENT_TIMESTAMP) {
689 if (prevEntry->length != sizeof(struct timespec)) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800690 // corrupt
691 break;
692 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800693 prevEntry.copyData((uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800694 if (ts.tv_sec > maxSec) {
695 maxSec = ts.tv_sec;
696 }
697 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800698 --entry;
699 --prevEntry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800700 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800701#endif
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700702 mFd = fd;
703 mIndent = indent;
704 String8 timestamp, body;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800705 size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data()));
Glenn Kastenc02c9612013-10-15 09:25:11 -0700706 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700707 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700708 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
709 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
710 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800711 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800712#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800713 size_t width = 1;
714 while (maxSec >= 10) {
715 ++width;
716 maxSec /= 10;
717 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800718 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700719 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800720 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700721 bool deferredTimestamp = false;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800722#endif
723 for (auto entry = snapshot.begin(); entry != snapshot.end();) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800724 switch (entry->type) {
725#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800726 case EVENT_STRING:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800727 body.appendFormat("%.*s", (int) entry.length(), entry.data());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700728 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800729 case EVENT_TIMESTAMP: {
730 // already checked that length == sizeof(struct timespec);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800731 entry.copyData((const uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800732 long prevNsec = ts.tv_nsec;
733 long deltaMin = LONG_MAX;
734 long deltaMax = -1;
735 long deltaTotal = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800736 auto aux(entry);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800737 for (;;) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800738 ++aux;
739 if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800740 break;
741 }
742 struct timespec tsNext;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800743 aux.copyData((const uint8_t*) &tsNext);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800744 if (tsNext.tv_sec != ts.tv_sec) {
745 break;
746 }
747 long delta = tsNext.tv_nsec - prevNsec;
748 if (delta < 0) {
749 break;
750 }
751 if (delta < deltaMin) {
752 deltaMin = delta;
753 }
754 if (delta > deltaMax) {
755 deltaMax = delta;
756 }
757 deltaTotal += delta;
758 prevNsec = tsNext.tv_nsec;
759 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800760 size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700761 if (deferredTimestamp) {
762 dumpLine(timestamp, body);
763 deferredTimestamp = false;
764 }
765 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800766 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700767 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
768 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
769 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
770 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800771 entry = aux;
772 // advance = 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800773 break;
774 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700775 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
776 (int) (ts.tv_nsec / 1000000));
777 deferredTimestamp = true;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800778 }
779 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800780 case EVENT_INTEGER:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800781 appendInt(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800782 break;
783 case EVENT_FLOAT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800784 appendFloat(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800785 break;
786 case EVENT_PID:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800787 appendPID(&body, entry.data(), entry.length());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800788 break;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800789#endif
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800790 case EVENT_START_FMT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800791 // right now, this is the only supported case
792 entry = handleFormat(FormatEntry(entry), &timestamp, &body);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800793 break;
794 case EVENT_END_FMT:
795 body.appendFormat("warning: got to end format event");
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800796 ++entry;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800797 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800798 case EVENT_RESERVED:
799 default:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800800 body.appendFormat("warning: unexpected event %d", entry->type);
801 ++entry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800802 break;
803 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700804
805 if (!body.isEmpty()) {
806 dumpLine(timestamp, body);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800807 // deferredTimestamp = false;
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700808 }
809 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800810 // if (deferredTimestamp) {
811 // dumpLine(timestamp, body);
812 // }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800813}
814
Nicolas Roulet40a44982017-02-03 13:39:57 -0800815void NBLog::Reader::dump(int fd, size_t indent)
816{
817 // get a snapshot, dump it
818 std::unique_ptr<Snapshot> snap = getSnapshot();
819 dump(fd, indent, *snap);
820}
821
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800822void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700823{
824 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700825 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700826 } else {
827 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
828 }
829 body.clear();
830}
831
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800832bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
833{
Glenn Kasten481fb672013-09-30 14:39:28 -0700834 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800835}
836
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800837void NBLog::appendTimestamp(String8 *body, const void *data) {
838 struct timespec ts;
839 memcpy(&ts, data, sizeof(struct timespec));
840 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
841 (int) (ts.tv_nsec / 1000000));
842}
843
844void NBLog::appendInt(String8 *body, const void *data) {
845 int x = *((int*) data);
846 body->appendFormat("<%d>", x);
847}
848
849void NBLog::appendFloat(String8 *body, const void *data) {
850 float f;
851 memcpy(&f, data, sizeof(float));
852 body->appendFormat("<%f>", f);
853}
854
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800855void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800856 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800857 char * name = &((char*) data)[sizeof(pid_t)];
858 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800859}
860
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800861NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
862 String8 *timestamp,
863 String8 *body) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800864 // log timestamp
865 struct timespec ts = fmtEntry.timestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800866 timestamp->clear();
867 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
868 (int) (ts.tv_nsec / 1000000));
Nicolas Roulet40a44982017-02-03 13:39:57 -0800869
870 // log author (if present)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800871 handleAuthor(fmtEntry, body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800872
873 // log string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800874 NBLog::FormatEntry::iterator arg = fmtEntry.args();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800875
876 const char* fmt = fmtEntry.formatString();
877 size_t fmt_length = fmtEntry.formatStringLength();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800878
879 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
880 if (fmt[fmt_offset] != '%') {
881 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
882 continue;
883 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800884 // case "%%""
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800885 if (fmt[++fmt_offset] == '%') {
886 body->append("%");
887 continue;
888 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800889 // case "%\0"
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800890 if (fmt_offset == fmt_length) {
891 continue;
892 }
893
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800894 NBLog::Event event = (NBLog::Event) arg->type;
895 size_t length = arg->length;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800896
897 // TODO check length for event type is correct
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800898
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800899 if (event == EVENT_END_FMT) {
900 break;
901 }
902
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800903 // TODO: implement more complex formatting such as %.3f
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800904 const uint8_t *datum = arg->data; // pointer to the current event args
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800905 switch(fmt[fmt_offset])
906 {
907 case 's': // string
Nicolas Roulet4da78202017-02-03 12:53:39 -0800908 ALOGW_IF(event != EVENT_STRING,
909 "NBLog Reader incompatible event for string specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800910 body->append((const char*) datum, length);
911 break;
912
913 case 't': // timestamp
Nicolas Roulet4da78202017-02-03 12:53:39 -0800914 ALOGW_IF(event != EVENT_TIMESTAMP,
915 "NBLog Reader incompatible event for timestamp specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800916 appendTimestamp(body, datum);
917 break;
918
919 case 'd': // integer
Nicolas Roulet4da78202017-02-03 12:53:39 -0800920 ALOGW_IF(event != EVENT_INTEGER,
921 "NBLog Reader incompatible event for integer specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800922 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800923 break;
924
925 case 'f': // float
Nicolas Roulet4da78202017-02-03 12:53:39 -0800926 ALOGW_IF(event != EVENT_FLOAT,
927 "NBLog Reader incompatible event for float specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800928 appendFloat(body, datum);
929 break;
930
931 case 'p': // pid
Nicolas Roulet4da78202017-02-03 12:53:39 -0800932 ALOGW_IF(event != EVENT_PID,
933 "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800934 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800935 break;
936
937 default:
938 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
939 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800940 ++arg;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800941 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800942 ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
943 ++arg;
944 return arg;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800945}
946
947// ---------------------------------------------------------------------------
948
949NBLog::Merger::Merger(const void *shared, size_t size):
950 mBuffer(NULL),
951 mShared((Shared *) shared),
952 mFifo(mShared != NULL ?
953 new audio_utils_fifo(size, sizeof(uint8_t),
954 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
955 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
956 {}
957
958void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
959 mNamedReaders.push_back(reader);
960}
961
962// items placed in priority queue during merge
963// composed by a timestamp and the index of the snapshot where the timestamp came from
964struct MergeItem
965{
966 struct timespec ts;
967 int index;
968 MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
969};
970
971// operators needed for priority queue in merge
972bool operator>(const struct timespec &t1, const struct timespec &t2) {
973 return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
974}
975
976bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
977 return i1.ts > i2.ts ||
978 (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
979}
980
981// Merge registered readers, sorted by timestamp
982void NBLog::Merger::merge() {
983 int nLogs = mNamedReaders.size();
984 std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800985 std::vector<NBLog::FormatEntry::iterator> offsets(nLogs);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800986 for (int i = 0; i < nLogs; ++i) {
987 snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800988 offsets[i] = snapshots[i]->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800989 }
990 // initialize offsets
Nicolas Roulet40a44982017-02-03 13:39:57 -0800991 // TODO custom heap implementation could allow to update top, improving performance
992 // for bursty buffers
993 std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
994 for (int i = 0; i < nLogs; ++i)
995 {
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800996 if (offsets[i] != snapshots[i]->end()) {
997 timespec ts = FormatEntry(offsets[i]).timestamp();
998 timestamps.emplace(ts, i);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800999 }
1000 }
1001
1002 while (!timestamps.empty()) {
1003 // find minimum timestamp
1004 int index = timestamps.top().index;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001005 // copy it to the log, increasing offset
1006 offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001007 // update data structures
Nicolas Roulet40a44982017-02-03 13:39:57 -08001008 timestamps.pop();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001009 if (offsets[index] != snapshots[index]->end()) {
1010 timespec ts = FormatEntry(offsets[index]).timestamp();
1011 timestamps.emplace(ts, index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001012 }
1013 }
1014}
1015
1016const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
1017 return &mNamedReaders;
1018}
1019
1020NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
1021 : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
1022
1023size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
1024 int author = fmtEntry.author();
1025 const char* name = (*mNamedReaders)[author].name();
1026 body->appendFormat("%s: ", name);
1027 return NBLog::Entry::kOverhead + sizeof(author);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001028}
1029
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -08001030NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
1031 : mMerger(merger),
1032 mTimeoutUs(0) {}
1033
1034NBLog::MergeThread::~MergeThread() {
1035 // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
1036 requestExit();
1037 setTimeoutUs(0);
1038 join();
1039}
1040
1041bool NBLog::MergeThread::threadLoop() {
1042 bool doMerge;
1043 {
1044 AutoMutex _l(mMutex);
1045 // If mTimeoutUs is negative, wait on the condition variable until it's positive.
1046 // If it's positive, wait kThreadSleepPeriodUs and then merge
1047 nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
1048 mCond.waitRelative(mMutex, waitTime);
1049 doMerge = mTimeoutUs > 0;
1050 mTimeoutUs -= kThreadSleepPeriodUs;
1051 }
1052 if (doMerge) {
1053 mMerger.merge();
1054 }
1055 return true;
1056}
1057
1058void NBLog::MergeThread::wakeup() {
1059 setTimeoutUs(kThreadWakeupPeriodUs);
1060}
1061
1062void NBLog::MergeThread::setTimeoutUs(int time) {
1063 AutoMutex _l(mMutex);
1064 mTimeoutUs = time;
1065 mCond.signal();
1066}
1067
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001068} // namespace android