blob: f480c16a68d40b85633c759e2c8d97f67ccc495e [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
20#include <stdarg.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <string.h>
Nicolas Rouletc20cb502017-02-01 12:35:24 -080024#include <sys/prctl.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080025#include <time.h>
26#include <new>
Glenn Kasten535e1612016-12-05 12:19:36 -080027#include <audio_utils/roundup.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080028#include <media/nbaio/NBLog.h>
29#include <utils/Log.h>
Glenn Kasten4e01ef62013-07-11 14:29:59 -070030#include <utils/String8.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080031
Nicolas Roulet40a44982017-02-03 13:39:57 -080032#include <queue>
33
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080034namespace android {
35
36int NBLog::Entry::readAt(size_t offset) const
37{
38 // FIXME This is too slow, despite the name it is used during writing
39 if (offset == 0)
40 return mEvent;
41 else if (offset == 1)
42 return mLength;
43 else if (offset < (size_t) (mLength + 2))
44 return ((char *) mData)[offset - 2];
45 else if (offset == (size_t) (mLength + 2))
46 return mLength;
47 else
48 return 0;
49}
50
51// ---------------------------------------------------------------------------
52
Nicolas Roulet40a44982017-02-03 13:39:57 -080053NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080054 ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
55 "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
Nicolas Roulet40a44982017-02-03 13:39:57 -080056}
57
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080058NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}
59
Nicolas Roulet40a44982017-02-03 13:39:57 -080060const char *NBLog::FormatEntry::formatString() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080061 return (const char*) mEntry + offsetof(entry, data);
Nicolas Roulet40a44982017-02-03 13:39:57 -080062}
63
64size_t NBLog::FormatEntry::formatStringLength() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080065 return mEntry[offsetof(entry, length)];
Nicolas Roulet40a44982017-02-03 13:39:57 -080066}
67
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080068NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
69 auto it = begin();
70 // Second entry can be author or timestamp. Skip author if present
71 if ((++it)->type == EVENT_AUTHOR) {
72 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080073 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080074 return ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080075}
76
77timespec NBLog::FormatEntry::timestamp() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080078 auto it = begin();
79 if ((++it)->type != EVENT_TIMESTAMP) {
80 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080081 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080082 return it.payload<timespec>();
Nicolas Roulet40a44982017-02-03 13:39:57 -080083}
84
85pid_t NBLog::FormatEntry::author() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080086 auto it = begin();
87 if ((++it)->type == EVENT_AUTHOR) {
88 return it.payload<int>();
Nicolas Roulet40a44982017-02-03 13:39:57 -080089 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080090 return -1;
Nicolas Roulet40a44982017-02-03 13:39:57 -080091}
92
93size_t NBLog::FormatEntry::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080094 auto it = this->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -080095 // copy fmt start entry
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080096 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -080097 // insert author entry
98 size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
99 uint8_t authorEntry[authorEntrySize];
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800100 authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
101 authorEntry[offsetof(entry, length)] =
102 authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
103 sizeof(author);
104 *(int*) (&authorEntry[offsetof(entry, data)]) = author;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800105 dst->write(authorEntry, authorEntrySize);
106 // copy rest of entries
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800107 while ((++it)->type != EVENT_END_FMT) {
108 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800109 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800110 it.copyTo(dst);
111 ++it;
112 return it - this->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800113}
114
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800115void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
116 size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
117 dst->write(ptr, length);
118}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800119
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800120void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
121 memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
122}
123
124NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
125 return iterator(mEntry);
126}
127
128NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
129 : ptr(entry) {}
130
131NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
132 : ptr(other.ptr) {}
133
134const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
135 return *(entry*) ptr;
136}
137
138const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
139 return (entry*) ptr;
140}
141
142NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
143 ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
144 return *this;
145}
146
147NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
148 ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
149 return *this;
150}
151
152int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
153 return ptr - other.ptr;
154}
155
156bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
157 return ptr != other.ptr;
158}
159
160bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
161 return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
162 NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
Nicolas Roulet40a44982017-02-03 13:39:57 -0800163}
164
165// ---------------------------------------------------------------------------
166
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800167#if 0 // FIXME see note in NBLog.h
168NBLog::Timeline::Timeline(size_t size, void *shared)
169 : mSize(roundup(size)), mOwn(shared == NULL),
170 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
171{
172 new (mShared) Shared;
173}
174
175NBLog::Timeline::~Timeline()
176{
177 mShared->~Shared();
178 if (mOwn) {
179 delete[] (char *) mShared;
180 }
181}
182#endif
183
184/*static*/
185size_t NBLog::Timeline::sharedSize(size_t size)
186{
Glenn Kastened99c2b2016-12-12 08:31:24 -0800187 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800188 return sizeof(Shared) + roundup(size);
189}
190
191// ---------------------------------------------------------------------------
192
193NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800194 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800195{
196}
197
Glenn Kasten535e1612016-12-05 12:19:36 -0800198NBLog::Writer::Writer(void *shared, size_t size)
199 : mShared((Shared *) shared),
200 mFifo(mShared != NULL ?
201 new audio_utils_fifo(size, sizeof(uint8_t),
202 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
203 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
204 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800205{
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800206 // caching pid and process name
207 pid_t id = ::getpid();
208 char procName[16];
209 int status = prctl(PR_GET_NAME, procName);
210 if (status) { // error getting process name
211 procName[0] = '\0';
212 }
213 size_t length = strlen(procName);
214 mPidTagSize = length + sizeof(pid_t);
215 mPidTag = new char[mPidTagSize];
216 memcpy(mPidTag, &id, sizeof(pid_t));
217 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800218}
219
Glenn Kasten535e1612016-12-05 12:19:36 -0800220NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
221 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800222{
Glenn Kasten535e1612016-12-05 12:19:36 -0800223 mIMemory = iMemory;
224}
225
226NBLog::Writer::~Writer()
227{
228 delete mFifoWriter;
229 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800230 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800231}
232
233void NBLog::Writer::log(const char *string)
234{
235 if (!mEnabled) {
236 return;
237 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800238 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800239 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800240 if (length > Entry::kMaxLength) {
241 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800242 }
243 log(EVENT_STRING, string, length);
244}
245
246void NBLog::Writer::logf(const char *fmt, ...)
247{
248 if (!mEnabled) {
249 return;
250 }
251 va_list ap;
252 va_start(ap, fmt);
253 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
254 va_end(ap);
255}
256
257void NBLog::Writer::logvf(const char *fmt, va_list ap)
258{
259 if (!mEnabled) {
260 return;
261 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800262 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800263 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
264 if (length >= (int) sizeof(buffer)) {
265 length = sizeof(buffer) - 1;
266 // NUL termination is not required
267 // buffer[length] = '\0';
268 }
269 if (length >= 0) {
270 log(EVENT_STRING, buffer, length);
271 }
272}
273
274void NBLog::Writer::logTimestamp()
275{
276 if (!mEnabled) {
277 return;
278 }
279 struct timespec ts;
280 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800281 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800282 }
283}
284
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800285void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800286{
287 if (!mEnabled) {
288 return;
289 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800290 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
291}
292
293void NBLog::Writer::logInteger(const int x)
294{
295 if (!mEnabled) {
296 return;
297 }
298 log(EVENT_INTEGER, &x, sizeof(x));
299}
300
301void NBLog::Writer::logFloat(const float x)
302{
303 if (!mEnabled) {
304 return;
305 }
306 log(EVENT_FLOAT, &x, sizeof(x));
307}
308
309void NBLog::Writer::logPID()
310{
311 if (!mEnabled) {
312 return;
313 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800314 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800315}
316
317void NBLog::Writer::logStart(const char *fmt)
318{
319 if (!mEnabled) {
320 return;
321 }
322 size_t length = strlen(fmt);
323 if (length > Entry::kMaxLength) {
324 length = Entry::kMaxLength;
325 }
326 log(EVENT_START_FMT, fmt, length);
327}
328
329void NBLog::Writer::logEnd()
330{
331 if (!mEnabled) {
332 return;
333 }
334 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
335 log(&entry, true);
336}
337
338void NBLog::Writer::logFormat(const char *fmt, ...)
339{
340 if (!mEnabled) {
341 return;
342 }
343
344 va_list ap;
345 va_start(ap, fmt);
346 Writer::logVFormat(fmt, ap);
347 va_end(ap);
348}
349
350void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
351{
352 if (!mEnabled) {
353 return;
354 }
355 Writer::logStart(fmt);
356 int i;
357 double f;
358 char* s;
359 struct timespec t;
360 Writer::logTimestamp();
361 for (const char *p = fmt; *p != '\0'; p++) {
362 // TODO: implement more complex formatting such as %.3f
363 if (*p != '%') {
364 continue;
365 }
366 switch(*++p) {
367 case 's': // string
368 s = va_arg(argp, char *);
369 Writer::log(s);
370 break;
371
372 case 't': // timestamp
373 t = va_arg(argp, struct timespec);
374 Writer::logTimestamp(t);
375 break;
376
377 case 'd': // integer
378 i = va_arg(argp, int);
379 Writer::logInteger(i);
380 break;
381
382 case 'f': // float
383 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
384 Writer::logFloat((float)f);
385 break;
386
387 case 'p': // pid
388 Writer::logPID();
389 break;
390
391 // the "%\0" case finishes parsing
392 case '\0':
393 --p;
394 break;
395
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800396 case '%':
397 break;
398
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800399 default:
400 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
401 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800402 }
403 }
404 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800405}
406
407void NBLog::Writer::log(Event event, const void *data, size_t length)
408{
409 if (!mEnabled) {
410 return;
411 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800412 if (data == NULL || length > Entry::kMaxLength) {
413 // TODO Perhaps it makes sense to display truncated data or at least a
414 // message that the data is too long? The current behavior can create
415 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800416 return;
417 }
418 switch (event) {
419 case EVENT_STRING:
420 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800421 case EVENT_INTEGER:
422 case EVENT_FLOAT:
423 case EVENT_PID:
424 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800425 break;
426 case EVENT_RESERVED:
427 default:
428 return;
429 }
430 Entry entry(event, data, length);
431 log(&entry, true /*trusted*/);
432}
433
434void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
435{
436 if (!mEnabled) {
437 return;
438 }
439 if (!trusted) {
440 log(entry->mEvent, entry->mData, entry->mLength);
441 return;
442 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800443 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
444 // need = number of bytes remaining to write
445
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800446 // FIXME optimize this using memcpy for the data part of the Entry.
447 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800448 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
449 for (size_t i = 0; i < need; i++) {
450 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800451 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800452 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800453}
454
455bool NBLog::Writer::isEnabled() const
456{
457 return mEnabled;
458}
459
460bool NBLog::Writer::setEnabled(bool enabled)
461{
462 bool old = mEnabled;
463 mEnabled = enabled && mShared != NULL;
464 return old;
465}
466
467// ---------------------------------------------------------------------------
468
469NBLog::LockedWriter::LockedWriter()
470 : Writer()
471{
472}
473
Glenn Kasten535e1612016-12-05 12:19:36 -0800474NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
475 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800476{
477}
478
479void NBLog::LockedWriter::log(const char *string)
480{
481 Mutex::Autolock _l(mLock);
482 Writer::log(string);
483}
484
485void NBLog::LockedWriter::logf(const char *fmt, ...)
486{
487 // FIXME should not take the lock until after formatting is done
488 Mutex::Autolock _l(mLock);
489 va_list ap;
490 va_start(ap, fmt);
491 Writer::logvf(fmt, ap);
492 va_end(ap);
493}
494
495void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
496{
497 // FIXME should not take the lock until after formatting is done
498 Mutex::Autolock _l(mLock);
499 Writer::logvf(fmt, ap);
500}
501
502void NBLog::LockedWriter::logTimestamp()
503{
504 // FIXME should not take the lock until after the clock_gettime() syscall
505 Mutex::Autolock _l(mLock);
506 Writer::logTimestamp();
507}
508
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800509void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800510{
511 Mutex::Autolock _l(mLock);
512 Writer::logTimestamp(ts);
513}
514
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800515void NBLog::LockedWriter::logInteger(const int x)
516{
517 Mutex::Autolock _l(mLock);
518 Writer::logInteger(x);
519}
520
521void NBLog::LockedWriter::logFloat(const float x)
522{
523 Mutex::Autolock _l(mLock);
524 Writer::logFloat(x);
525}
526
527void NBLog::LockedWriter::logPID()
528{
529 Mutex::Autolock _l(mLock);
530 Writer::logPID();
531}
532
533void NBLog::LockedWriter::logStart(const char *fmt)
534{
535 Mutex::Autolock _l(mLock);
536 Writer::logStart(fmt);
537}
538
539
540void NBLog::LockedWriter::logEnd()
541{
542 Mutex::Autolock _l(mLock);
543 Writer::logEnd();
544}
545
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800546bool NBLog::LockedWriter::isEnabled() const
547{
548 Mutex::Autolock _l(mLock);
549 return Writer::isEnabled();
550}
551
552bool NBLog::LockedWriter::setEnabled(bool enabled)
553{
554 Mutex::Autolock _l(mLock);
555 return Writer::setEnabled(enabled);
556}
557
558// ---------------------------------------------------------------------------
559
Glenn Kasten535e1612016-12-05 12:19:36 -0800560NBLog::Reader::Reader(const void *shared, size_t size)
561 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
562 mFd(-1), mIndent(0),
563 mFifo(mShared != NULL ?
564 new audio_utils_fifo(size, sizeof(uint8_t),
565 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
566 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800567{
568}
569
Glenn Kasten535e1612016-12-05 12:19:36 -0800570NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
571 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800572{
Glenn Kasten535e1612016-12-05 12:19:36 -0800573 mIMemory = iMemory;
574}
575
576NBLog::Reader::~Reader()
577{
578 delete mFifoReader;
579 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800580}
581
Nicolas Roulet40a44982017-02-03 13:39:57 -0800582std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800583{
Glenn Kasten535e1612016-12-05 12:19:36 -0800584 if (mFifoReader == NULL) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800585 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800586 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800587 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800588 size_t capacity = mFifo->capacity();
589
Nicolas Roulet40a44982017-02-03 13:39:57 -0800590 std::unique_ptr<Snapshot> snapshot(new Snapshot(capacity));
Glenn Kasten535e1612016-12-05 12:19:36 -0800591
Nicolas Roulet40a44982017-02-03 13:39:57 -0800592 ssize_t actual = mFifoReader->read((void*) snapshot->mData, capacity, NULL /*timeout*/,
593 &(snapshot->mLost));
Glenn Kasten535e1612016-12-05 12:19:36 -0800594 ALOG_ASSERT(actual <= capacity);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800595 snapshot->mAvail = actual > 0 ? (size_t) actual : 0;
596 return snapshot;
597}
598
599void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
600{
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800601 NBLog::FormatEntry::iterator entry(snapshot.data() + snapshot.available());
602 NBLog::FormatEntry::iterator prevEntry = entry;
603 --prevEntry;
604 NBLog::FormatEntry::iterator start(snapshot.data());
605
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800606 struct timespec ts;
607 time_t maxSec = -1;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800608 while (entry - start >= (int) Entry::kOverhead) {
609 if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800610 break;
611 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800612 if (prevEntry->type == EVENT_TIMESTAMP) {
613 if (prevEntry->length != sizeof(struct timespec)) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800614 // corrupt
615 break;
616 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800617 prevEntry.copyData((uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800618 if (ts.tv_sec > maxSec) {
619 maxSec = ts.tv_sec;
620 }
621 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800622 --entry;
623 --prevEntry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800624 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700625 mFd = fd;
626 mIndent = indent;
627 String8 timestamp, body;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800628 size_t lost = snapshot.lost() + (entry - start);
Glenn Kastenc02c9612013-10-15 09:25:11 -0700629 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700630 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700631 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
632 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
633 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800634 }
635 size_t width = 1;
636 while (maxSec >= 10) {
637 ++width;
638 maxSec /= 10;
639 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800640 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700641 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800642 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700643 bool deferredTimestamp = false;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800644 NBLog::FormatEntry::iterator end(snapshot.data() + snapshot.available());
645
646 while (entry != end) {
647 switch (entry->type) {
648#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800649 case EVENT_STRING:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800650 body.appendFormat("%.*s", (int) entry.length(), entry.data());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700651 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800652 case EVENT_TIMESTAMP: {
653 // already checked that length == sizeof(struct timespec);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800654 entry.copyData((const uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800655 long prevNsec = ts.tv_nsec;
656 long deltaMin = LONG_MAX;
657 long deltaMax = -1;
658 long deltaTotal = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800659 auto aux(entry);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800660 for (;;) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800661 ++aux;
662 if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800663 break;
664 }
665 struct timespec tsNext;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800666 aux.copyData((const uint8_t*) &tsNext);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800667 if (tsNext.tv_sec != ts.tv_sec) {
668 break;
669 }
670 long delta = tsNext.tv_nsec - prevNsec;
671 if (delta < 0) {
672 break;
673 }
674 if (delta < deltaMin) {
675 deltaMin = delta;
676 }
677 if (delta > deltaMax) {
678 deltaMax = delta;
679 }
680 deltaTotal += delta;
681 prevNsec = tsNext.tv_nsec;
682 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800683 size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700684 if (deferredTimestamp) {
685 dumpLine(timestamp, body);
686 deferredTimestamp = false;
687 }
688 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800689 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700690 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
691 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
692 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
693 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800694 entry = aux;
695 // advance = 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800696 break;
697 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700698 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
699 (int) (ts.tv_nsec / 1000000));
700 deferredTimestamp = true;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800701 }
702 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800703 case EVENT_INTEGER:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800704 appendInt(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800705 break;
706 case EVENT_FLOAT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800707 appendFloat(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800708 break;
709 case EVENT_PID:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800710 appendPID(&body, entry.data(), entry.length());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800711 break;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800712#endif
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800713 case EVENT_START_FMT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800714 // right now, this is the only supported case
715 entry = handleFormat(FormatEntry(entry), &timestamp, &body);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800716 break;
717 case EVENT_END_FMT:
718 body.appendFormat("warning: got to end format event");
719 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800720 case EVENT_RESERVED:
721 default:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800722 body.appendFormat("warning: unknown event %d", entry->type);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800723 break;
724 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700725
726 if (!body.isEmpty()) {
727 dumpLine(timestamp, body);
728 deferredTimestamp = false;
729 }
730 }
731 if (deferredTimestamp) {
732 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800733 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800734}
735
Nicolas Roulet40a44982017-02-03 13:39:57 -0800736void NBLog::Reader::dump(int fd, size_t indent)
737{
738 // get a snapshot, dump it
739 std::unique_ptr<Snapshot> snap = getSnapshot();
740 dump(fd, indent, *snap);
741}
742
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800743void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700744{
745 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700746 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700747 } else {
748 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
749 }
750 body.clear();
751}
752
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800753bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
754{
Glenn Kasten481fb672013-09-30 14:39:28 -0700755 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800756}
757
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800758void NBLog::appendTimestamp(String8 *body, const void *data) {
759 struct timespec ts;
760 memcpy(&ts, data, sizeof(struct timespec));
761 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
762 (int) (ts.tv_nsec / 1000000));
763}
764
765void NBLog::appendInt(String8 *body, const void *data) {
766 int x = *((int*) data);
767 body->appendFormat("<%d>", x);
768}
769
770void NBLog::appendFloat(String8 *body, const void *data) {
771 float f;
772 memcpy(&f, data, sizeof(float));
773 body->appendFormat("<%f>", f);
774}
775
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800776void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800777 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800778 char * name = &((char*) data)[sizeof(pid_t)];
779 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800780}
781
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800782NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
783 String8 *timestamp,
784 String8 *body) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800785 // log timestamp
786 struct timespec ts = fmtEntry.timestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800787 timestamp->clear();
788 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
789 (int) (ts.tv_nsec / 1000000));
Nicolas Roulet40a44982017-02-03 13:39:57 -0800790
791 // log author (if present)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800792 handleAuthor(fmtEntry, body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800793
794 // log string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800795 NBLog::FormatEntry::iterator arg = fmtEntry.args();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800796
797 const char* fmt = fmtEntry.formatString();
798 size_t fmt_length = fmtEntry.formatStringLength();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800799
800 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
801 if (fmt[fmt_offset] != '%') {
802 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
803 continue;
804 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800805 // case "%%""
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800806 if (fmt[++fmt_offset] == '%') {
807 body->append("%");
808 continue;
809 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800810 // case "%\0"
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800811 if (fmt_offset == fmt_length) {
812 continue;
813 }
814
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800815 NBLog::Event event = (NBLog::Event) arg->type;
816 size_t length = arg->length;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800817
818 // TODO check length for event type is correct
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800819 if (!arg.hasConsistentLength()) {
820 // TODO: corrupt, resync buffer
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800821 body->append("<invalid entry>");
822 ++fmt_offset;
823 continue;
824 }
825
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800826 if (event == EVENT_END_FMT) {
827 break;
828 }
829
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800830 // TODO: implement more complex formatting such as %.3f
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800831 const uint8_t *datum = arg->data; // pointer to the current event args
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800832 switch(fmt[fmt_offset])
833 {
834 case 's': // string
Nicolas Roulet4da78202017-02-03 12:53:39 -0800835 ALOGW_IF(event != EVENT_STRING,
836 "NBLog Reader incompatible event for string specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800837 body->append((const char*) datum, length);
838 break;
839
840 case 't': // timestamp
Nicolas Roulet4da78202017-02-03 12:53:39 -0800841 ALOGW_IF(event != EVENT_TIMESTAMP,
842 "NBLog Reader incompatible event for timestamp specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800843 appendTimestamp(body, datum);
844 break;
845
846 case 'd': // integer
Nicolas Roulet4da78202017-02-03 12:53:39 -0800847 ALOGW_IF(event != EVENT_INTEGER,
848 "NBLog Reader incompatible event for integer specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800849 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800850 break;
851
852 case 'f': // float
Nicolas Roulet4da78202017-02-03 12:53:39 -0800853 ALOGW_IF(event != EVENT_FLOAT,
854 "NBLog Reader incompatible event for float specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800855 appendFloat(body, datum);
856 break;
857
858 case 'p': // pid
Nicolas Roulet4da78202017-02-03 12:53:39 -0800859 ALOGW_IF(event != EVENT_PID,
860 "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800861 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800862 break;
863
864 default:
865 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
866 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800867 ++arg;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800868 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800869 ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
870 ++arg;
871 return arg;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800872}
873
874// ---------------------------------------------------------------------------
875
876NBLog::Merger::Merger(const void *shared, size_t size):
877 mBuffer(NULL),
878 mShared((Shared *) shared),
879 mFifo(mShared != NULL ?
880 new audio_utils_fifo(size, sizeof(uint8_t),
881 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
882 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
883 {}
884
885void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
886 mNamedReaders.push_back(reader);
887}
888
889// items placed in priority queue during merge
890// composed by a timestamp and the index of the snapshot where the timestamp came from
891struct MergeItem
892{
893 struct timespec ts;
894 int index;
895 MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
896};
897
898// operators needed for priority queue in merge
899bool operator>(const struct timespec &t1, const struct timespec &t2) {
900 return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
901}
902
903bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
904 return i1.ts > i2.ts ||
905 (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
906}
907
908// Merge registered readers, sorted by timestamp
909void NBLog::Merger::merge() {
910 int nLogs = mNamedReaders.size();
911 std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
912 for (int i = 0; i < nLogs; ++i) {
913 snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
914 }
915 // initialize offsets
916 std::vector<size_t> offsets(nLogs, 0);
917 // TODO custom heap implementation could allow to update top, improving performance
918 // for bursty buffers
919 std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
920 for (int i = 0; i < nLogs; ++i)
921 {
922 if (snapshots[i]->available() > 0) {
923 timespec ts = FormatEntry(snapshots[i]->data()).timestamp();
924 MergeItem item(ts, i);
925 timestamps.push(item);
926 }
927 }
928
929 while (!timestamps.empty()) {
930 // find minimum timestamp
931 int index = timestamps.top().index;
932 // copy it to the log
933 size_t length = FormatEntry(snapshots[index]->data() + offsets[index]).copyTo(
934 mFifoWriter, index);
935 // update data structures
936 offsets[index] += length;
937 ALOGW_IF(offsets[index] > snapshots[index]->available(), "Overflown snapshot capacity");
938 timestamps.pop();
939 if (offsets[index] != snapshots[index]->available()) {
940 timespec ts = FormatEntry(snapshots[index]->data() + offsets[index]).timestamp();
941 MergeItem item(ts, index);
942 timestamps.emplace(item);
943 }
944 }
945}
946
947const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
948 return &mNamedReaders;
949}
950
951NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
952 : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
953
954size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
955 int author = fmtEntry.author();
956 const char* name = (*mNamedReaders)[author].name();
957 body->appendFormat("%s: ", name);
958 return NBLog::Entry::kOverhead + sizeof(author);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800959}
960
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800961} // namespace android