blob: 94ae11ef802f6b26664c3f0f90cafb0916d16b79 [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();
Nicolas Roulet1ca75122017-03-16 14:19:59 -070071 // skip start fmt
72 ++it;
73 // skip timestamp
74 ++it;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070075 // skip hash
76 ++it;
Nicolas Roulet1ca75122017-03-16 14:19:59 -070077 // Skip author if present
78 if (it->type == EVENT_AUTHOR) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080079 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080080 }
Nicolas Roulet1ca75122017-03-16 14:19:59 -070081 return it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080082}
83
84timespec NBLog::FormatEntry::timestamp() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080085 auto it = begin();
Nicolas Roulet1ca75122017-03-16 14:19:59 -070086 // skip start fmt
87 ++it;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080088 return it.payload<timespec>();
Nicolas Roulet40a44982017-02-03 13:39:57 -080089}
90
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070091NBLog::log_hash_t NBLog::FormatEntry::hash() const {
92 auto it = begin();
93 // skip start fmt
94 ++it;
95 // skip timestamp
96 ++it;
97 // unaligned 64-bit read not supported
98 log_hash_t hash;
99 memcpy(&hash, it->data, sizeof(hash));
100 return hash;
101}
102
Nicolas Roulet40a44982017-02-03 13:39:57 -0800103pid_t NBLog::FormatEntry::author() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800104 auto it = begin();
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700105 // skip start fmt
106 ++it;
107 // skip timestamp
108 ++it;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700109 // skip hash
110 ++it;
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700111 // if there is an author entry, return it, return -1 otherwise
112 if (it->type == EVENT_AUTHOR) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800113 return it.payload<int>();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800114 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800115 return -1;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800116}
117
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800118NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor(
119 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
120 auto it = begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800121 // copy fmt start entry
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800122 it.copyTo(dst);
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700123 // copy timestamp
124 (++it).copyTo(dst);
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700125 // copy hash
126 (++it).copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800127 // insert author entry
128 size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
129 uint8_t authorEntry[authorEntrySize];
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800130 authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
131 authorEntry[offsetof(entry, length)] =
132 authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
133 sizeof(author);
134 *(int*) (&authorEntry[offsetof(entry, data)]) = author;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800135 dst->write(authorEntry, authorEntrySize);
136 // copy rest of entries
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800137 while ((++it)->type != EVENT_END_FMT) {
138 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800139 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800140 it.copyTo(dst);
141 ++it;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800142 return it;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800143}
144
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800145void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
146 size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
147 dst->write(ptr, length);
148}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800149
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800150void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
151 memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
152}
153
154NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
155 return iterator(mEntry);
156}
157
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800158NBLog::FormatEntry::iterator::iterator()
159 : ptr(nullptr) {}
160
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800161NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
162 : ptr(entry) {}
163
164NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
165 : ptr(other.ptr) {}
166
167const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
168 return *(entry*) ptr;
169}
170
171const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
172 return (entry*) ptr;
173}
174
175NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
176 ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
177 return *this;
178}
179
180NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
181 ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
182 return *this;
183}
184
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800185NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const {
186 iterator aux(*this);
187 return ++aux;
188}
189
190NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const {
191 iterator aux(*this);
192 return --aux;
193}
194
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800195int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
196 return ptr - other.ptr;
197}
198
199bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
200 return ptr != other.ptr;
201}
202
203bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
204 return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
205 NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
Nicolas Roulet40a44982017-02-03 13:39:57 -0800206}
207
208// ---------------------------------------------------------------------------
209
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800210#if 0 // FIXME see note in NBLog.h
211NBLog::Timeline::Timeline(size_t size, void *shared)
212 : mSize(roundup(size)), mOwn(shared == NULL),
213 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
214{
215 new (mShared) Shared;
216}
217
218NBLog::Timeline::~Timeline()
219{
220 mShared->~Shared();
221 if (mOwn) {
222 delete[] (char *) mShared;
223 }
224}
225#endif
226
227/*static*/
228size_t NBLog::Timeline::sharedSize(size_t size)
229{
Glenn Kastened99c2b2016-12-12 08:31:24 -0800230 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800231 return sizeof(Shared) + roundup(size);
232}
233
234// ---------------------------------------------------------------------------
235
236NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800237 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800238{
239}
240
Glenn Kasten535e1612016-12-05 12:19:36 -0800241NBLog::Writer::Writer(void *shared, size_t size)
242 : mShared((Shared *) shared),
243 mFifo(mShared != NULL ?
244 new audio_utils_fifo(size, sizeof(uint8_t),
245 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
246 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
247 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800248{
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800249 // caching pid and process name
250 pid_t id = ::getpid();
251 char procName[16];
252 int status = prctl(PR_GET_NAME, procName);
253 if (status) { // error getting process name
254 procName[0] = '\0';
255 }
256 size_t length = strlen(procName);
257 mPidTagSize = length + sizeof(pid_t);
258 mPidTag = new char[mPidTagSize];
259 memcpy(mPidTag, &id, sizeof(pid_t));
260 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800261}
262
Glenn Kasten535e1612016-12-05 12:19:36 -0800263NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
264 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800265{
Glenn Kasten535e1612016-12-05 12:19:36 -0800266 mIMemory = iMemory;
267}
268
269NBLog::Writer::~Writer()
270{
271 delete mFifoWriter;
272 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800273 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800274}
275
276void NBLog::Writer::log(const char *string)
277{
278 if (!mEnabled) {
279 return;
280 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800281 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800282 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800283 if (length > Entry::kMaxLength) {
284 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800285 }
286 log(EVENT_STRING, string, length);
287}
288
289void NBLog::Writer::logf(const char *fmt, ...)
290{
291 if (!mEnabled) {
292 return;
293 }
294 va_list ap;
295 va_start(ap, fmt);
296 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
297 va_end(ap);
298}
299
300void NBLog::Writer::logvf(const char *fmt, va_list ap)
301{
302 if (!mEnabled) {
303 return;
304 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800305 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800306 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
307 if (length >= (int) sizeof(buffer)) {
308 length = sizeof(buffer) - 1;
309 // NUL termination is not required
310 // buffer[length] = '\0';
311 }
312 if (length >= 0) {
313 log(EVENT_STRING, buffer, length);
314 }
315}
316
317void NBLog::Writer::logTimestamp()
318{
319 if (!mEnabled) {
320 return;
321 }
322 struct timespec ts;
323 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800324 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800325 }
326}
327
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800328void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800329{
330 if (!mEnabled) {
331 return;
332 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800333 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
334}
335
336void NBLog::Writer::logInteger(const int x)
337{
338 if (!mEnabled) {
339 return;
340 }
341 log(EVENT_INTEGER, &x, sizeof(x));
342}
343
344void NBLog::Writer::logFloat(const float x)
345{
346 if (!mEnabled) {
347 return;
348 }
349 log(EVENT_FLOAT, &x, sizeof(x));
350}
351
352void NBLog::Writer::logPID()
353{
354 if (!mEnabled) {
355 return;
356 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800357 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800358}
359
360void NBLog::Writer::logStart(const char *fmt)
361{
362 if (!mEnabled) {
363 return;
364 }
365 size_t length = strlen(fmt);
366 if (length > Entry::kMaxLength) {
367 length = Entry::kMaxLength;
368 }
369 log(EVENT_START_FMT, fmt, length);
370}
371
372void NBLog::Writer::logEnd()
373{
374 if (!mEnabled) {
375 return;
376 }
377 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
378 log(&entry, true);
379}
380
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700381void NBLog::Writer::logHash(log_hash_t hash)
382{
383 if (!mEnabled) {
384 return;
385 }
386 log(EVENT_HASH, &hash, sizeof(hash));
387}
388
389void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800390{
391 if (!mEnabled) {
392 return;
393 }
394
395 va_list ap;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700396 va_start(ap, hash);
397 Writer::logVFormat(fmt, hash, ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800398 va_end(ap);
399}
400
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700401void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800402{
403 if (!mEnabled) {
404 return;
405 }
406 Writer::logStart(fmt);
407 int i;
408 double f;
409 char* s;
410 struct timespec t;
411 Writer::logTimestamp();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700412 Writer::logHash(hash);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800413 for (const char *p = fmt; *p != '\0'; p++) {
414 // TODO: implement more complex formatting such as %.3f
415 if (*p != '%') {
416 continue;
417 }
418 switch(*++p) {
419 case 's': // string
420 s = va_arg(argp, char *);
421 Writer::log(s);
422 break;
423
424 case 't': // timestamp
425 t = va_arg(argp, struct timespec);
426 Writer::logTimestamp(t);
427 break;
428
429 case 'd': // integer
430 i = va_arg(argp, int);
431 Writer::logInteger(i);
432 break;
433
434 case 'f': // float
435 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
436 Writer::logFloat((float)f);
437 break;
438
439 case 'p': // pid
440 Writer::logPID();
441 break;
442
443 // the "%\0" case finishes parsing
444 case '\0':
445 --p;
446 break;
447
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800448 case '%':
449 break;
450
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800451 default:
452 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
453 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800454 }
455 }
456 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800457}
458
459void NBLog::Writer::log(Event event, const void *data, size_t length)
460{
461 if (!mEnabled) {
462 return;
463 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800464 if (data == NULL || length > Entry::kMaxLength) {
465 // TODO Perhaps it makes sense to display truncated data or at least a
466 // message that the data is too long? The current behavior can create
467 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800468 return;
469 }
470 switch (event) {
471 case EVENT_STRING:
472 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800473 case EVENT_INTEGER:
474 case EVENT_FLOAT:
475 case EVENT_PID:
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700476 case EVENT_HASH:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800477 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800478 break;
479 case EVENT_RESERVED:
480 default:
481 return;
482 }
483 Entry entry(event, data, length);
484 log(&entry, true /*trusted*/);
485}
486
487void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
488{
489 if (!mEnabled) {
490 return;
491 }
492 if (!trusted) {
493 log(entry->mEvent, entry->mData, entry->mLength);
494 return;
495 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800496 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
497 // need = number of bytes remaining to write
498
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800499 // FIXME optimize this using memcpy for the data part of the Entry.
500 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800501 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
502 for (size_t i = 0; i < need; i++) {
503 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800504 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800505 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800506}
507
508bool NBLog::Writer::isEnabled() const
509{
510 return mEnabled;
511}
512
513bool NBLog::Writer::setEnabled(bool enabled)
514{
515 bool old = mEnabled;
516 mEnabled = enabled && mShared != NULL;
517 return old;
518}
519
520// ---------------------------------------------------------------------------
521
522NBLog::LockedWriter::LockedWriter()
523 : Writer()
524{
525}
526
Glenn Kasten535e1612016-12-05 12:19:36 -0800527NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
528 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800529{
530}
531
532void NBLog::LockedWriter::log(const char *string)
533{
534 Mutex::Autolock _l(mLock);
535 Writer::log(string);
536}
537
538void NBLog::LockedWriter::logf(const char *fmt, ...)
539{
540 // FIXME should not take the lock until after formatting is done
541 Mutex::Autolock _l(mLock);
542 va_list ap;
543 va_start(ap, fmt);
544 Writer::logvf(fmt, ap);
545 va_end(ap);
546}
547
548void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
549{
550 // FIXME should not take the lock until after formatting is done
551 Mutex::Autolock _l(mLock);
552 Writer::logvf(fmt, ap);
553}
554
555void NBLog::LockedWriter::logTimestamp()
556{
557 // FIXME should not take the lock until after the clock_gettime() syscall
558 Mutex::Autolock _l(mLock);
559 Writer::logTimestamp();
560}
561
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800562void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800563{
564 Mutex::Autolock _l(mLock);
565 Writer::logTimestamp(ts);
566}
567
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800568void NBLog::LockedWriter::logInteger(const int x)
569{
570 Mutex::Autolock _l(mLock);
571 Writer::logInteger(x);
572}
573
574void NBLog::LockedWriter::logFloat(const float x)
575{
576 Mutex::Autolock _l(mLock);
577 Writer::logFloat(x);
578}
579
580void NBLog::LockedWriter::logPID()
581{
582 Mutex::Autolock _l(mLock);
583 Writer::logPID();
584}
585
586void NBLog::LockedWriter::logStart(const char *fmt)
587{
588 Mutex::Autolock _l(mLock);
589 Writer::logStart(fmt);
590}
591
592
593void NBLog::LockedWriter::logEnd()
594{
595 Mutex::Autolock _l(mLock);
596 Writer::logEnd();
597}
598
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700599void NBLog::LockedWriter::logHash(log_hash_t hash)
600{
601 Mutex::Autolock _l(mLock);
602 Writer::logHash(hash);
603}
604
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800605bool NBLog::LockedWriter::isEnabled() const
606{
607 Mutex::Autolock _l(mLock);
608 return Writer::isEnabled();
609}
610
611bool NBLog::LockedWriter::setEnabled(bool enabled)
612{
613 Mutex::Autolock _l(mLock);
614 return Writer::setEnabled(enabled);
615}
616
617// ---------------------------------------------------------------------------
618
Glenn Kasten535e1612016-12-05 12:19:36 -0800619NBLog::Reader::Reader(const void *shared, size_t size)
620 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
621 mFd(-1), mIndent(0),
622 mFifo(mShared != NULL ?
623 new audio_utils_fifo(size, sizeof(uint8_t),
624 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
625 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800626{
627}
628
Glenn Kasten535e1612016-12-05 12:19:36 -0800629NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
630 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800631{
Glenn Kasten535e1612016-12-05 12:19:36 -0800632 mIMemory = iMemory;
633}
634
635NBLog::Reader::~Reader()
636{
637 delete mFifoReader;
638 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800639}
640
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800641uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) {
642 while (back + Entry::kPreviousLengthOffset >= front) {
643 uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
644 if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] +
645 Entry::kOverhead != back) {
646
647 // prev points to an out of limits or inconsistent entry
648 return nullptr;
649 }
650 if (prev[offsetof(FormatEntry::entry, type)] == type) {
651 return prev;
652 }
653 back = prev;
654 }
655 return nullptr; // no entry found
656}
657
Nicolas Roulet40a44982017-02-03 13:39:57 -0800658std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800659{
Glenn Kasten535e1612016-12-05 12:19:36 -0800660 if (mFifoReader == NULL) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800661 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800662 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800663 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800664 size_t capacity = mFifo->capacity();
665
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800666 // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
667 // reader index. The index is incremented after handling corruption, to after the last complete
668 // entry of the buffer
669 size_t lost;
670 audio_utils_iovec iovec[2];
671 ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
672 if (availToRead <= 0) {
673 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
674 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800675
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800676 std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
677 memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
678 if (iovec[1].mLength > 0) {
679 memcpy(snapshot->mData + (iovec[0].mLength),
680 (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
681 }
682
683 // Handle corrupted buffer
684 // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
685 // (due to incomplete format entry). But even if the end format entry is incomplete,
686 // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
687 // TODO: handle client corruption (in the middle of a buffer)
688
689 uint8_t *back = snapshot->mData + availToRead;
690 uint8_t *front = snapshot->mData;
691
692 // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
693 // We go backwards until we find an EVENT_END_FMT.
694 uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT);
695 if (lastEnd == nullptr) {
696 snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front);
697 } else {
698 // end of snapshot points to after last END_FMT entry
699 snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead);
700 // find first START_FMT
701 uint8_t *firstStart = nullptr;
702 uint8_t *firstStartTmp = lastEnd;
703 while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT))
704 != nullptr) {
705 firstStart = firstStartTmp;
706 }
707 // firstStart is null if no START_FMT entry was found before lastEnd
708 if (firstStart == nullptr) {
709 snapshot->mBegin = snapshot->mEnd;
710 } else {
711 snapshot->mBegin = FormatEntry::iterator(firstStart);
712 }
713 }
714
715 // advance fifo reader index to after last entry read.
716 mFifoReader->release(snapshot->mEnd - front);
717
718 snapshot->mLost = lost;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800719 return snapshot;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800720
Nicolas Roulet40a44982017-02-03 13:39:57 -0800721}
722
723void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
724{
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800725#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800726 struct timespec ts;
727 time_t maxSec = -1;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800728 while (entry - start >= (int) Entry::kOverhead) {
729 if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800730 break;
731 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800732 if (prevEntry->type == EVENT_TIMESTAMP) {
733 if (prevEntry->length != sizeof(struct timespec)) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800734 // corrupt
735 break;
736 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800737 prevEntry.copyData((uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800738 if (ts.tv_sec > maxSec) {
739 maxSec = ts.tv_sec;
740 }
741 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800742 --entry;
743 --prevEntry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800744 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800745#endif
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700746 mFd = fd;
747 mIndent = indent;
748 String8 timestamp, body;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800749 size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data()));
Glenn Kastenc02c9612013-10-15 09:25:11 -0700750 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700751 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700752 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
753 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
754 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800755 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800756#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800757 size_t width = 1;
758 while (maxSec >= 10) {
759 ++width;
760 maxSec /= 10;
761 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800762 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700763 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800764 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700765 bool deferredTimestamp = false;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800766#endif
767 for (auto entry = snapshot.begin(); entry != snapshot.end();) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800768 switch (entry->type) {
769#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800770 case EVENT_STRING:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800771 body.appendFormat("%.*s", (int) entry.length(), entry.data());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700772 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800773 case EVENT_TIMESTAMP: {
774 // already checked that length == sizeof(struct timespec);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800775 entry.copyData((const uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800776 long prevNsec = ts.tv_nsec;
777 long deltaMin = LONG_MAX;
778 long deltaMax = -1;
779 long deltaTotal = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800780 auto aux(entry);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800781 for (;;) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800782 ++aux;
783 if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800784 break;
785 }
786 struct timespec tsNext;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800787 aux.copyData((const uint8_t*) &tsNext);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800788 if (tsNext.tv_sec != ts.tv_sec) {
789 break;
790 }
791 long delta = tsNext.tv_nsec - prevNsec;
792 if (delta < 0) {
793 break;
794 }
795 if (delta < deltaMin) {
796 deltaMin = delta;
797 }
798 if (delta > deltaMax) {
799 deltaMax = delta;
800 }
801 deltaTotal += delta;
802 prevNsec = tsNext.tv_nsec;
803 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800804 size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700805 if (deferredTimestamp) {
806 dumpLine(timestamp, body);
807 deferredTimestamp = false;
808 }
809 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800810 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700811 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
812 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
813 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
814 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800815 entry = aux;
816 // advance = 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800817 break;
818 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700819 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
820 (int) (ts.tv_nsec / 1000000));
821 deferredTimestamp = true;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800822 }
823 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800824 case EVENT_INTEGER:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800825 appendInt(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800826 break;
827 case EVENT_FLOAT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800828 appendFloat(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800829 break;
830 case EVENT_PID:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800831 appendPID(&body, entry.data(), entry.length());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800832 break;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800833#endif
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800834 case EVENT_START_FMT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800835 // right now, this is the only supported case
836 entry = handleFormat(FormatEntry(entry), &timestamp, &body);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800837 break;
838 case EVENT_END_FMT:
839 body.appendFormat("warning: got to end format event");
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800840 ++entry;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800841 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800842 case EVENT_RESERVED:
843 default:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800844 body.appendFormat("warning: unexpected event %d", entry->type);
845 ++entry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800846 break;
847 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700848
849 if (!body.isEmpty()) {
850 dumpLine(timestamp, body);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800851 // deferredTimestamp = false;
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700852 }
853 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800854 // if (deferredTimestamp) {
855 // dumpLine(timestamp, body);
856 // }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800857}
858
Nicolas Roulet40a44982017-02-03 13:39:57 -0800859void NBLog::Reader::dump(int fd, size_t indent)
860{
861 // get a snapshot, dump it
862 std::unique_ptr<Snapshot> snap = getSnapshot();
863 dump(fd, indent, *snap);
864}
865
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800866void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700867{
868 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700869 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700870 } else {
871 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
872 }
873 body.clear();
874}
875
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800876bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
877{
Glenn Kasten481fb672013-09-30 14:39:28 -0700878 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800879}
880
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800881void NBLog::appendTimestamp(String8 *body, const void *data) {
882 struct timespec ts;
883 memcpy(&ts, data, sizeof(struct timespec));
884 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
885 (int) (ts.tv_nsec / 1000000));
886}
887
888void NBLog::appendInt(String8 *body, const void *data) {
889 int x = *((int*) data);
890 body->appendFormat("<%d>", x);
891}
892
893void NBLog::appendFloat(String8 *body, const void *data) {
894 float f;
895 memcpy(&f, data, sizeof(float));
896 body->appendFormat("<%f>", f);
897}
898
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800899void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800900 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800901 char * name = &((char*) data)[sizeof(pid_t)];
902 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800903}
904
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800905NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
906 String8 *timestamp,
907 String8 *body) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800908 // log timestamp
909 struct timespec ts = fmtEntry.timestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800910 timestamp->clear();
911 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
912 (int) (ts.tv_nsec / 1000000));
Nicolas Roulet40a44982017-02-03 13:39:57 -0800913
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700914 // log unique hash
915 log_hash_t hash = fmtEntry.hash();
916 // print only lower 16bit of hash as hex and line as int to reduce spam in the log
917 body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
918
Nicolas Roulet40a44982017-02-03 13:39:57 -0800919 // log author (if present)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800920 handleAuthor(fmtEntry, body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800921
922 // log string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800923 NBLog::FormatEntry::iterator arg = fmtEntry.args();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800924
925 const char* fmt = fmtEntry.formatString();
926 size_t fmt_length = fmtEntry.formatStringLength();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800927
928 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
929 if (fmt[fmt_offset] != '%') {
930 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
931 continue;
932 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800933 // case "%%""
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800934 if (fmt[++fmt_offset] == '%') {
935 body->append("%");
936 continue;
937 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800938 // case "%\0"
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800939 if (fmt_offset == fmt_length) {
940 continue;
941 }
942
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800943 NBLog::Event event = (NBLog::Event) arg->type;
944 size_t length = arg->length;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800945
946 // TODO check length for event type is correct
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800947
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800948 if (event == EVENT_END_FMT) {
949 break;
950 }
951
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800952 // TODO: implement more complex formatting such as %.3f
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800953 const uint8_t *datum = arg->data; // pointer to the current event args
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800954 switch(fmt[fmt_offset])
955 {
956 case 's': // string
Nicolas Roulet4da78202017-02-03 12:53:39 -0800957 ALOGW_IF(event != EVENT_STRING,
958 "NBLog Reader incompatible event for string specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800959 body->append((const char*) datum, length);
960 break;
961
962 case 't': // timestamp
Nicolas Roulet4da78202017-02-03 12:53:39 -0800963 ALOGW_IF(event != EVENT_TIMESTAMP,
964 "NBLog Reader incompatible event for timestamp specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800965 appendTimestamp(body, datum);
966 break;
967
968 case 'd': // integer
Nicolas Roulet4da78202017-02-03 12:53:39 -0800969 ALOGW_IF(event != EVENT_INTEGER,
970 "NBLog Reader incompatible event for integer specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800971 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800972 break;
973
974 case 'f': // float
Nicolas Roulet4da78202017-02-03 12:53:39 -0800975 ALOGW_IF(event != EVENT_FLOAT,
976 "NBLog Reader incompatible event for float specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800977 appendFloat(body, datum);
978 break;
979
980 case 'p': // pid
Nicolas Roulet4da78202017-02-03 12:53:39 -0800981 ALOGW_IF(event != EVENT_PID,
982 "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800983 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800984 break;
985
986 default:
987 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
988 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800989 ++arg;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800990 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800991 ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
992 ++arg;
993 return arg;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800994}
995
996// ---------------------------------------------------------------------------
997
998NBLog::Merger::Merger(const void *shared, size_t size):
999 mBuffer(NULL),
1000 mShared((Shared *) shared),
1001 mFifo(mShared != NULL ?
1002 new audio_utils_fifo(size, sizeof(uint8_t),
1003 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
1004 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
1005 {}
1006
1007void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
1008 mNamedReaders.push_back(reader);
1009}
1010
1011// items placed in priority queue during merge
1012// composed by a timestamp and the index of the snapshot where the timestamp came from
1013struct MergeItem
1014{
1015 struct timespec ts;
1016 int index;
1017 MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
1018};
1019
1020// operators needed for priority queue in merge
1021bool operator>(const struct timespec &t1, const struct timespec &t2) {
1022 return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
1023}
1024
1025bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
1026 return i1.ts > i2.ts ||
1027 (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
1028}
1029
1030// Merge registered readers, sorted by timestamp
1031void NBLog::Merger::merge() {
1032 int nLogs = mNamedReaders.size();
1033 std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001034 std::vector<NBLog::FormatEntry::iterator> offsets(nLogs);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001035 for (int i = 0; i < nLogs; ++i) {
1036 snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001037 offsets[i] = snapshots[i]->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -08001038 }
1039 // initialize offsets
Nicolas Roulet40a44982017-02-03 13:39:57 -08001040 // TODO custom heap implementation could allow to update top, improving performance
1041 // for bursty buffers
1042 std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
1043 for (int i = 0; i < nLogs; ++i)
1044 {
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001045 if (offsets[i] != snapshots[i]->end()) {
1046 timespec ts = FormatEntry(offsets[i]).timestamp();
1047 timestamps.emplace(ts, i);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001048 }
1049 }
1050
1051 while (!timestamps.empty()) {
1052 // find minimum timestamp
1053 int index = timestamps.top().index;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001054 // copy it to the log, increasing offset
1055 offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001056 // update data structures
Nicolas Roulet40a44982017-02-03 13:39:57 -08001057 timestamps.pop();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001058 if (offsets[index] != snapshots[index]->end()) {
1059 timespec ts = FormatEntry(offsets[index]).timestamp();
1060 timestamps.emplace(ts, index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001061 }
1062 }
1063}
1064
1065const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
1066 return &mNamedReaders;
1067}
1068
1069NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
1070 : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
1071
1072size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
1073 int author = fmtEntry.author();
1074 const char* name = (*mNamedReaders)[author].name();
1075 body->appendFormat("%s: ", name);
1076 return NBLog::Entry::kOverhead + sizeof(author);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001077}
1078
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -08001079NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
1080 : mMerger(merger),
1081 mTimeoutUs(0) {}
1082
1083NBLog::MergeThread::~MergeThread() {
1084 // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
1085 requestExit();
1086 setTimeoutUs(0);
1087 join();
1088}
1089
1090bool NBLog::MergeThread::threadLoop() {
1091 bool doMerge;
1092 {
1093 AutoMutex _l(mMutex);
1094 // If mTimeoutUs is negative, wait on the condition variable until it's positive.
1095 // If it's positive, wait kThreadSleepPeriodUs and then merge
1096 nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
1097 mCond.waitRelative(mMutex, waitTime);
1098 doMerge = mTimeoutUs > 0;
1099 mTimeoutUs -= kThreadSleepPeriodUs;
1100 }
1101 if (doMerge) {
1102 mMerger.merge();
1103 }
1104 return true;
1105}
1106
1107void NBLog::MergeThread::wakeup() {
1108 setTimeoutUs(kThreadWakeupPeriodUs);
1109}
1110
1111void NBLog::MergeThread::setTimeoutUs(int time) {
1112 AutoMutex _l(mMutex);
1113 mTimeoutUs = time;
1114 mCond.signal();
1115}
1116
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001117} // namespace android