blob: b65ac99b0719ebba678fe5be0ff6929956261522 [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
94size_t NBLog::FormatEntry::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080095 auto it = this->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -080096 // copy fmt start entry
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080097 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -080098 // insert author entry
99 size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
100 uint8_t authorEntry[authorEntrySize];
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800101 authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
102 authorEntry[offsetof(entry, length)] =
103 authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
104 sizeof(author);
105 *(int*) (&authorEntry[offsetof(entry, data)]) = author;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800106 dst->write(authorEntry, authorEntrySize);
107 // copy rest of entries
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800108 while ((++it)->type != EVENT_END_FMT) {
109 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800110 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800111 it.copyTo(dst);
112 ++it;
113 return it - this->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800114}
115
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800116void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
117 size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
118 dst->write(ptr, length);
119}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800120
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800121void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
122 memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
123}
124
125NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
126 return iterator(mEntry);
127}
128
129NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
130 : ptr(entry) {}
131
132NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
133 : ptr(other.ptr) {}
134
135const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
136 return *(entry*) ptr;
137}
138
139const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
140 return (entry*) ptr;
141}
142
143NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
144 ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
145 return *this;
146}
147
148NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
149 ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
150 return *this;
151}
152
153int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
154 return ptr - other.ptr;
155}
156
157bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
158 return ptr != other.ptr;
159}
160
161bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
162 return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
163 NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
Nicolas Roulet40a44982017-02-03 13:39:57 -0800164}
165
166// ---------------------------------------------------------------------------
167
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800168#if 0 // FIXME see note in NBLog.h
169NBLog::Timeline::Timeline(size_t size, void *shared)
170 : mSize(roundup(size)), mOwn(shared == NULL),
171 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
172{
173 new (mShared) Shared;
174}
175
176NBLog::Timeline::~Timeline()
177{
178 mShared->~Shared();
179 if (mOwn) {
180 delete[] (char *) mShared;
181 }
182}
183#endif
184
185/*static*/
186size_t NBLog::Timeline::sharedSize(size_t size)
187{
Glenn Kastened99c2b2016-12-12 08:31:24 -0800188 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800189 return sizeof(Shared) + roundup(size);
190}
191
192// ---------------------------------------------------------------------------
193
194NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800195 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800196{
197}
198
Glenn Kasten535e1612016-12-05 12:19:36 -0800199NBLog::Writer::Writer(void *shared, size_t size)
200 : mShared((Shared *) shared),
201 mFifo(mShared != NULL ?
202 new audio_utils_fifo(size, sizeof(uint8_t),
203 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
204 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
205 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800206{
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800207 // caching pid and process name
208 pid_t id = ::getpid();
209 char procName[16];
210 int status = prctl(PR_GET_NAME, procName);
211 if (status) { // error getting process name
212 procName[0] = '\0';
213 }
214 size_t length = strlen(procName);
215 mPidTagSize = length + sizeof(pid_t);
216 mPidTag = new char[mPidTagSize];
217 memcpy(mPidTag, &id, sizeof(pid_t));
218 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800219}
220
Glenn Kasten535e1612016-12-05 12:19:36 -0800221NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
222 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800223{
Glenn Kasten535e1612016-12-05 12:19:36 -0800224 mIMemory = iMemory;
225}
226
227NBLog::Writer::~Writer()
228{
229 delete mFifoWriter;
230 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800231 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800232}
233
234void NBLog::Writer::log(const char *string)
235{
236 if (!mEnabled) {
237 return;
238 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800239 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800240 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800241 if (length > Entry::kMaxLength) {
242 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800243 }
244 log(EVENT_STRING, string, length);
245}
246
247void NBLog::Writer::logf(const char *fmt, ...)
248{
249 if (!mEnabled) {
250 return;
251 }
252 va_list ap;
253 va_start(ap, fmt);
254 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
255 va_end(ap);
256}
257
258void NBLog::Writer::logvf(const char *fmt, va_list ap)
259{
260 if (!mEnabled) {
261 return;
262 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800263 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800264 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
265 if (length >= (int) sizeof(buffer)) {
266 length = sizeof(buffer) - 1;
267 // NUL termination is not required
268 // buffer[length] = '\0';
269 }
270 if (length >= 0) {
271 log(EVENT_STRING, buffer, length);
272 }
273}
274
275void NBLog::Writer::logTimestamp()
276{
277 if (!mEnabled) {
278 return;
279 }
280 struct timespec ts;
281 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800282 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800283 }
284}
285
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800286void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800287{
288 if (!mEnabled) {
289 return;
290 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800291 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
292}
293
294void NBLog::Writer::logInteger(const int x)
295{
296 if (!mEnabled) {
297 return;
298 }
299 log(EVENT_INTEGER, &x, sizeof(x));
300}
301
302void NBLog::Writer::logFloat(const float x)
303{
304 if (!mEnabled) {
305 return;
306 }
307 log(EVENT_FLOAT, &x, sizeof(x));
308}
309
310void NBLog::Writer::logPID()
311{
312 if (!mEnabled) {
313 return;
314 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800315 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800316}
317
318void NBLog::Writer::logStart(const char *fmt)
319{
320 if (!mEnabled) {
321 return;
322 }
323 size_t length = strlen(fmt);
324 if (length > Entry::kMaxLength) {
325 length = Entry::kMaxLength;
326 }
327 log(EVENT_START_FMT, fmt, length);
328}
329
330void NBLog::Writer::logEnd()
331{
332 if (!mEnabled) {
333 return;
334 }
335 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
336 log(&entry, true);
337}
338
339void NBLog::Writer::logFormat(const char *fmt, ...)
340{
341 if (!mEnabled) {
342 return;
343 }
344
345 va_list ap;
346 va_start(ap, fmt);
347 Writer::logVFormat(fmt, ap);
348 va_end(ap);
349}
350
351void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
352{
353 if (!mEnabled) {
354 return;
355 }
356 Writer::logStart(fmt);
357 int i;
358 double f;
359 char* s;
360 struct timespec t;
361 Writer::logTimestamp();
362 for (const char *p = fmt; *p != '\0'; p++) {
363 // TODO: implement more complex formatting such as %.3f
364 if (*p != '%') {
365 continue;
366 }
367 switch(*++p) {
368 case 's': // string
369 s = va_arg(argp, char *);
370 Writer::log(s);
371 break;
372
373 case 't': // timestamp
374 t = va_arg(argp, struct timespec);
375 Writer::logTimestamp(t);
376 break;
377
378 case 'd': // integer
379 i = va_arg(argp, int);
380 Writer::logInteger(i);
381 break;
382
383 case 'f': // float
384 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
385 Writer::logFloat((float)f);
386 break;
387
388 case 'p': // pid
389 Writer::logPID();
390 break;
391
392 // the "%\0" case finishes parsing
393 case '\0':
394 --p;
395 break;
396
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800397 case '%':
398 break;
399
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800400 default:
401 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
402 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800403 }
404 }
405 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800406}
407
408void NBLog::Writer::log(Event event, const void *data, size_t length)
409{
410 if (!mEnabled) {
411 return;
412 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800413 if (data == NULL || length > Entry::kMaxLength) {
414 // TODO Perhaps it makes sense to display truncated data or at least a
415 // message that the data is too long? The current behavior can create
416 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800417 return;
418 }
419 switch (event) {
420 case EVENT_STRING:
421 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800422 case EVENT_INTEGER:
423 case EVENT_FLOAT:
424 case EVENT_PID:
425 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800426 break;
427 case EVENT_RESERVED:
428 default:
429 return;
430 }
431 Entry entry(event, data, length);
432 log(&entry, true /*trusted*/);
433}
434
435void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
436{
437 if (!mEnabled) {
438 return;
439 }
440 if (!trusted) {
441 log(entry->mEvent, entry->mData, entry->mLength);
442 return;
443 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800444 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
445 // need = number of bytes remaining to write
446
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800447 // FIXME optimize this using memcpy for the data part of the Entry.
448 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800449 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
450 for (size_t i = 0; i < need; i++) {
451 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800452 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800453 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800454}
455
456bool NBLog::Writer::isEnabled() const
457{
458 return mEnabled;
459}
460
461bool NBLog::Writer::setEnabled(bool enabled)
462{
463 bool old = mEnabled;
464 mEnabled = enabled && mShared != NULL;
465 return old;
466}
467
468// ---------------------------------------------------------------------------
469
470NBLog::LockedWriter::LockedWriter()
471 : Writer()
472{
473}
474
Glenn Kasten535e1612016-12-05 12:19:36 -0800475NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
476 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800477{
478}
479
480void NBLog::LockedWriter::log(const char *string)
481{
482 Mutex::Autolock _l(mLock);
483 Writer::log(string);
484}
485
486void NBLog::LockedWriter::logf(const char *fmt, ...)
487{
488 // FIXME should not take the lock until after formatting is done
489 Mutex::Autolock _l(mLock);
490 va_list ap;
491 va_start(ap, fmt);
492 Writer::logvf(fmt, ap);
493 va_end(ap);
494}
495
496void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
497{
498 // FIXME should not take the lock until after formatting is done
499 Mutex::Autolock _l(mLock);
500 Writer::logvf(fmt, ap);
501}
502
503void NBLog::LockedWriter::logTimestamp()
504{
505 // FIXME should not take the lock until after the clock_gettime() syscall
506 Mutex::Autolock _l(mLock);
507 Writer::logTimestamp();
508}
509
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800510void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800511{
512 Mutex::Autolock _l(mLock);
513 Writer::logTimestamp(ts);
514}
515
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800516void NBLog::LockedWriter::logInteger(const int x)
517{
518 Mutex::Autolock _l(mLock);
519 Writer::logInteger(x);
520}
521
522void NBLog::LockedWriter::logFloat(const float x)
523{
524 Mutex::Autolock _l(mLock);
525 Writer::logFloat(x);
526}
527
528void NBLog::LockedWriter::logPID()
529{
530 Mutex::Autolock _l(mLock);
531 Writer::logPID();
532}
533
534void NBLog::LockedWriter::logStart(const char *fmt)
535{
536 Mutex::Autolock _l(mLock);
537 Writer::logStart(fmt);
538}
539
540
541void NBLog::LockedWriter::logEnd()
542{
543 Mutex::Autolock _l(mLock);
544 Writer::logEnd();
545}
546
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800547bool NBLog::LockedWriter::isEnabled() const
548{
549 Mutex::Autolock _l(mLock);
550 return Writer::isEnabled();
551}
552
553bool NBLog::LockedWriter::setEnabled(bool enabled)
554{
555 Mutex::Autolock _l(mLock);
556 return Writer::setEnabled(enabled);
557}
558
559// ---------------------------------------------------------------------------
560
Glenn Kasten535e1612016-12-05 12:19:36 -0800561NBLog::Reader::Reader(const void *shared, size_t size)
562 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
563 mFd(-1), mIndent(0),
564 mFifo(mShared != NULL ?
565 new audio_utils_fifo(size, sizeof(uint8_t),
566 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
567 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800568{
569}
570
Glenn Kasten535e1612016-12-05 12:19:36 -0800571NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
572 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800573{
Glenn Kasten535e1612016-12-05 12:19:36 -0800574 mIMemory = iMemory;
575}
576
577NBLog::Reader::~Reader()
578{
579 delete mFifoReader;
580 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800581}
582
Nicolas Roulet40a44982017-02-03 13:39:57 -0800583std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800584{
Glenn Kasten535e1612016-12-05 12:19:36 -0800585 if (mFifoReader == NULL) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800586 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800587 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800588 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800589 size_t capacity = mFifo->capacity();
590
Nicolas Roulet40a44982017-02-03 13:39:57 -0800591 std::unique_ptr<Snapshot> snapshot(new Snapshot(capacity));
Glenn Kasten535e1612016-12-05 12:19:36 -0800592
Nicolas Roulet40a44982017-02-03 13:39:57 -0800593 ssize_t actual = mFifoReader->read((void*) snapshot->mData, capacity, NULL /*timeout*/,
594 &(snapshot->mLost));
Glenn Kasten535e1612016-12-05 12:19:36 -0800595 ALOG_ASSERT(actual <= capacity);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800596 snapshot->mAvail = actual > 0 ? (size_t) actual : 0;
597 return snapshot;
598}
599
600void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
601{
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800602 NBLog::FormatEntry::iterator entry(snapshot.data() + snapshot.available());
603 NBLog::FormatEntry::iterator prevEntry = entry;
604 --prevEntry;
605 NBLog::FormatEntry::iterator start(snapshot.data());
606
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800607 struct timespec ts;
608 time_t maxSec = -1;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800609 while (entry - start >= (int) Entry::kOverhead) {
610 if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800611 break;
612 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800613 if (prevEntry->type == EVENT_TIMESTAMP) {
614 if (prevEntry->length != sizeof(struct timespec)) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800615 // corrupt
616 break;
617 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800618 prevEntry.copyData((uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800619 if (ts.tv_sec > maxSec) {
620 maxSec = ts.tv_sec;
621 }
622 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800623 --entry;
624 --prevEntry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800625 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700626 mFd = fd;
627 mIndent = indent;
628 String8 timestamp, body;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800629 size_t lost = snapshot.lost() + (entry - start);
Glenn Kastenc02c9612013-10-15 09:25:11 -0700630 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700631 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700632 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
633 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
634 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800635 }
636 size_t width = 1;
637 while (maxSec >= 10) {
638 ++width;
639 maxSec /= 10;
640 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800641 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700642 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800643 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700644 bool deferredTimestamp = false;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800645 NBLog::FormatEntry::iterator end(snapshot.data() + snapshot.available());
646
647 while (entry != end) {
648 switch (entry->type) {
649#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800650 case EVENT_STRING:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800651 body.appendFormat("%.*s", (int) entry.length(), entry.data());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700652 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800653 case EVENT_TIMESTAMP: {
654 // already checked that length == sizeof(struct timespec);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800655 entry.copyData((const uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800656 long prevNsec = ts.tv_nsec;
657 long deltaMin = LONG_MAX;
658 long deltaMax = -1;
659 long deltaTotal = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800660 auto aux(entry);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800661 for (;;) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800662 ++aux;
663 if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800664 break;
665 }
666 struct timespec tsNext;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800667 aux.copyData((const uint8_t*) &tsNext);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800668 if (tsNext.tv_sec != ts.tv_sec) {
669 break;
670 }
671 long delta = tsNext.tv_nsec - prevNsec;
672 if (delta < 0) {
673 break;
674 }
675 if (delta < deltaMin) {
676 deltaMin = delta;
677 }
678 if (delta > deltaMax) {
679 deltaMax = delta;
680 }
681 deltaTotal += delta;
682 prevNsec = tsNext.tv_nsec;
683 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800684 size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700685 if (deferredTimestamp) {
686 dumpLine(timestamp, body);
687 deferredTimestamp = false;
688 }
689 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800690 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700691 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
692 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
693 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
694 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800695 entry = aux;
696 // advance = 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800697 break;
698 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700699 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
700 (int) (ts.tv_nsec / 1000000));
701 deferredTimestamp = true;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800702 }
703 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800704 case EVENT_INTEGER:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800705 appendInt(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800706 break;
707 case EVENT_FLOAT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800708 appendFloat(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800709 break;
710 case EVENT_PID:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800711 appendPID(&body, entry.data(), entry.length());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800712 break;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800713#endif
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800714 case EVENT_START_FMT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800715 // right now, this is the only supported case
716 entry = handleFormat(FormatEntry(entry), &timestamp, &body);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800717 break;
718 case EVENT_END_FMT:
719 body.appendFormat("warning: got to end format event");
720 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800721 case EVENT_RESERVED:
722 default:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800723 body.appendFormat("warning: unknown event %d", entry->type);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800724 break;
725 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700726
727 if (!body.isEmpty()) {
728 dumpLine(timestamp, body);
729 deferredTimestamp = false;
730 }
731 }
732 if (deferredTimestamp) {
733 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800734 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800735}
736
Nicolas Roulet40a44982017-02-03 13:39:57 -0800737void NBLog::Reader::dump(int fd, size_t indent)
738{
739 // get a snapshot, dump it
740 std::unique_ptr<Snapshot> snap = getSnapshot();
741 dump(fd, indent, *snap);
742}
743
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800744void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700745{
746 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700747 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700748 } else {
749 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
750 }
751 body.clear();
752}
753
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800754bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
755{
Glenn Kasten481fb672013-09-30 14:39:28 -0700756 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800757}
758
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800759void NBLog::appendTimestamp(String8 *body, const void *data) {
760 struct timespec ts;
761 memcpy(&ts, data, sizeof(struct timespec));
762 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
763 (int) (ts.tv_nsec / 1000000));
764}
765
766void NBLog::appendInt(String8 *body, const void *data) {
767 int x = *((int*) data);
768 body->appendFormat("<%d>", x);
769}
770
771void NBLog::appendFloat(String8 *body, const void *data) {
772 float f;
773 memcpy(&f, data, sizeof(float));
774 body->appendFormat("<%f>", f);
775}
776
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800777void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800778 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800779 char * name = &((char*) data)[sizeof(pid_t)];
780 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800781}
782
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800783NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
784 String8 *timestamp,
785 String8 *body) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800786 // log timestamp
787 struct timespec ts = fmtEntry.timestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800788 timestamp->clear();
789 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
790 (int) (ts.tv_nsec / 1000000));
Nicolas Roulet40a44982017-02-03 13:39:57 -0800791
792 // log author (if present)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800793 handleAuthor(fmtEntry, body);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800794
795 // log string
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800796 NBLog::FormatEntry::iterator arg = fmtEntry.args();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800797
798 const char* fmt = fmtEntry.formatString();
799 size_t fmt_length = fmtEntry.formatStringLength();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800800
801 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
802 if (fmt[fmt_offset] != '%') {
803 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
804 continue;
805 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800806 // case "%%""
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800807 if (fmt[++fmt_offset] == '%') {
808 body->append("%");
809 continue;
810 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800811 // case "%\0"
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800812 if (fmt_offset == fmt_length) {
813 continue;
814 }
815
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800816 NBLog::Event event = (NBLog::Event) arg->type;
817 size_t length = arg->length;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800818
819 // TODO check length for event type is correct
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800820 if (!arg.hasConsistentLength()) {
821 // TODO: corrupt, resync buffer
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800822 body->append("<invalid entry>");
823 ++fmt_offset;
824 continue;
825 }
826
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800827 if (event == EVENT_END_FMT) {
828 break;
829 }
830
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800831 // TODO: implement more complex formatting such as %.3f
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800832 const uint8_t *datum = arg->data; // pointer to the current event args
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800833 switch(fmt[fmt_offset])
834 {
835 case 's': // string
Nicolas Roulet4da78202017-02-03 12:53:39 -0800836 ALOGW_IF(event != EVENT_STRING,
837 "NBLog Reader incompatible event for string specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800838 body->append((const char*) datum, length);
839 break;
840
841 case 't': // timestamp
Nicolas Roulet4da78202017-02-03 12:53:39 -0800842 ALOGW_IF(event != EVENT_TIMESTAMP,
843 "NBLog Reader incompatible event for timestamp specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800844 appendTimestamp(body, datum);
845 break;
846
847 case 'd': // integer
Nicolas Roulet4da78202017-02-03 12:53:39 -0800848 ALOGW_IF(event != EVENT_INTEGER,
849 "NBLog Reader incompatible event for integer specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800850 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800851 break;
852
853 case 'f': // float
Nicolas Roulet4da78202017-02-03 12:53:39 -0800854 ALOGW_IF(event != EVENT_FLOAT,
855 "NBLog Reader incompatible event for float specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800856 appendFloat(body, datum);
857 break;
858
859 case 'p': // pid
Nicolas Roulet4da78202017-02-03 12:53:39 -0800860 ALOGW_IF(event != EVENT_PID,
861 "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800862 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800863 break;
864
865 default:
866 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
867 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800868 ++arg;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800869 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800870 ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
871 ++arg;
872 return arg;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800873}
874
875// ---------------------------------------------------------------------------
876
877NBLog::Merger::Merger(const void *shared, size_t size):
878 mBuffer(NULL),
879 mShared((Shared *) shared),
880 mFifo(mShared != NULL ?
881 new audio_utils_fifo(size, sizeof(uint8_t),
882 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
883 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
884 {}
885
886void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
887 mNamedReaders.push_back(reader);
888}
889
890// items placed in priority queue during merge
891// composed by a timestamp and the index of the snapshot where the timestamp came from
892struct MergeItem
893{
894 struct timespec ts;
895 int index;
896 MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
897};
898
899// operators needed for priority queue in merge
900bool operator>(const struct timespec &t1, const struct timespec &t2) {
901 return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
902}
903
904bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
905 return i1.ts > i2.ts ||
906 (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
907}
908
909// Merge registered readers, sorted by timestamp
910void NBLog::Merger::merge() {
911 int nLogs = mNamedReaders.size();
912 std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
913 for (int i = 0; i < nLogs; ++i) {
914 snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
915 }
916 // initialize offsets
917 std::vector<size_t> offsets(nLogs, 0);
918 // TODO custom heap implementation could allow to update top, improving performance
919 // for bursty buffers
920 std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
921 for (int i = 0; i < nLogs; ++i)
922 {
923 if (snapshots[i]->available() > 0) {
924 timespec ts = FormatEntry(snapshots[i]->data()).timestamp();
925 MergeItem item(ts, i);
926 timestamps.push(item);
927 }
928 }
929
930 while (!timestamps.empty()) {
931 // find minimum timestamp
932 int index = timestamps.top().index;
933 // copy it to the log
934 size_t length = FormatEntry(snapshots[index]->data() + offsets[index]).copyTo(
935 mFifoWriter, index);
936 // update data structures
937 offsets[index] += length;
938 ALOGW_IF(offsets[index] > snapshots[index]->available(), "Overflown snapshot capacity");
939 timestamps.pop();
940 if (offsets[index] != snapshots[index]->available()) {
941 timespec ts = FormatEntry(snapshots[index]->data() + offsets[index]).timestamp();
942 MergeItem item(ts, index);
943 timestamps.emplace(item);
944 }
945 }
946}
947
948const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
949 return &mNamedReaders;
950}
951
952NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
953 : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
954
955size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
956 int author = fmtEntry.author();
957 const char* name = (*mNamedReaders)[author].name();
958 body->appendFormat("%s: ", name);
959 return NBLog::Entry::kOverhead + sizeof(author);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800960}
961
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -0800962NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
963 : mMerger(merger),
964 mTimeoutUs(0) {}
965
966NBLog::MergeThread::~MergeThread() {
967 // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
968 requestExit();
969 setTimeoutUs(0);
970 join();
971}
972
973bool NBLog::MergeThread::threadLoop() {
974 bool doMerge;
975 {
976 AutoMutex _l(mMutex);
977 // If mTimeoutUs is negative, wait on the condition variable until it's positive.
978 // If it's positive, wait kThreadSleepPeriodUs and then merge
979 nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
980 mCond.waitRelative(mMutex, waitTime);
981 doMerge = mTimeoutUs > 0;
982 mTimeoutUs -= kThreadSleepPeriodUs;
983 }
984 if (doMerge) {
985 mMerger.merge();
986 }
987 return true;
988}
989
990void NBLog::MergeThread::wakeup() {
991 setTimeoutUs(kThreadWakeupPeriodUs);
992}
993
994void NBLog::MergeThread::setTimeoutUs(int time) {
995 AutoMutex _l(mMutex);
996 mTimeoutUs = time;
997 mCond.signal();
998}
999
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001000} // namespace android