blob: 7c2523d0f9b9c8311a80f55397a4ab0a8d8ec435 [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>
24#include <time.h>
25#include <new>
Glenn Kasten535e1612016-12-05 12:19:36 -080026#include <audio_utils/roundup.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080027#include <media/nbaio/NBLog.h>
28#include <utils/Log.h>
Glenn Kasten4e01ef62013-07-11 14:29:59 -070029#include <utils/String8.h>
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080030
31namespace android {
32
33int NBLog::Entry::readAt(size_t offset) const
34{
35 // FIXME This is too slow, despite the name it is used during writing
36 if (offset == 0)
37 return mEvent;
38 else if (offset == 1)
39 return mLength;
40 else if (offset < (size_t) (mLength + 2))
41 return ((char *) mData)[offset - 2];
42 else if (offset == (size_t) (mLength + 2))
43 return mLength;
44 else
45 return 0;
46}
47
48// ---------------------------------------------------------------------------
49
50#if 0 // FIXME see note in NBLog.h
51NBLog::Timeline::Timeline(size_t size, void *shared)
52 : mSize(roundup(size)), mOwn(shared == NULL),
53 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
54{
55 new (mShared) Shared;
56}
57
58NBLog::Timeline::~Timeline()
59{
60 mShared->~Shared();
61 if (mOwn) {
62 delete[] (char *) mShared;
63 }
64}
65#endif
66
67/*static*/
68size_t NBLog::Timeline::sharedSize(size_t size)
69{
Glenn Kastened99c2b2016-12-12 08:31:24 -080070 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080071 return sizeof(Shared) + roundup(size);
72}
73
74// ---------------------------------------------------------------------------
75
76NBLog::Writer::Writer()
Glenn Kasten535e1612016-12-05 12:19:36 -080077 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080078{
79}
80
Glenn Kasten535e1612016-12-05 12:19:36 -080081NBLog::Writer::Writer(void *shared, size_t size)
82 : mShared((Shared *) shared),
83 mFifo(mShared != NULL ?
84 new audio_utils_fifo(size, sizeof(uint8_t),
85 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
86 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
87 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080088{
89}
90
Glenn Kasten535e1612016-12-05 12:19:36 -080091NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
92 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080093{
Glenn Kasten535e1612016-12-05 12:19:36 -080094 mIMemory = iMemory;
95}
96
97NBLog::Writer::~Writer()
98{
99 delete mFifoWriter;
100 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800101}
102
103void NBLog::Writer::log(const char *string)
104{
105 if (!mEnabled) {
106 return;
107 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800108 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800109 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800110 if (length > Entry::kMaxLength) {
111 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800112 }
113 log(EVENT_STRING, string, length);
114}
115
116void NBLog::Writer::logf(const char *fmt, ...)
117{
118 if (!mEnabled) {
119 return;
120 }
121 va_list ap;
122 va_start(ap, fmt);
123 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
124 va_end(ap);
125}
126
127void NBLog::Writer::logvf(const char *fmt, va_list ap)
128{
129 if (!mEnabled) {
130 return;
131 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800132 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800133 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
134 if (length >= (int) sizeof(buffer)) {
135 length = sizeof(buffer) - 1;
136 // NUL termination is not required
137 // buffer[length] = '\0';
138 }
139 if (length >= 0) {
140 log(EVENT_STRING, buffer, length);
141 }
142}
143
144void NBLog::Writer::logTimestamp()
145{
146 if (!mEnabled) {
147 return;
148 }
149 struct timespec ts;
150 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800151 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800152 }
153}
154
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800155void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800156{
157 if (!mEnabled) {
158 return;
159 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800160 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
161}
162
163void NBLog::Writer::logInteger(const int x)
164{
165 if (!mEnabled) {
166 return;
167 }
168 log(EVENT_INTEGER, &x, sizeof(x));
169}
170
171void NBLog::Writer::logFloat(const float x)
172{
173 if (!mEnabled) {
174 return;
175 }
176 log(EVENT_FLOAT, &x, sizeof(x));
177}
178
179void NBLog::Writer::logPID()
180{
181 if (!mEnabled) {
182 return;
183 }
184 pid_t id = ::getpid();
185 // TODO: append process name to pid
186 // const char* path = sprintf("/proc/%d/status", id);
187 // FILE* f = fopen(path);
188 // size_t length = 30
189 // char buffer[length];
190 // getline(&buffer, &length, f);
191 // char* pidTag = sprintf("")
192 log(EVENT_PID, &id, sizeof(pid_t));
193}
194
195void NBLog::Writer::logStart(const char *fmt)
196{
197 if (!mEnabled) {
198 return;
199 }
200 size_t length = strlen(fmt);
201 if (length > Entry::kMaxLength) {
202 length = Entry::kMaxLength;
203 }
204 log(EVENT_START_FMT, fmt, length);
205}
206
207void NBLog::Writer::logEnd()
208{
209 if (!mEnabled) {
210 return;
211 }
212 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
213 log(&entry, true);
214}
215
216void NBLog::Writer::logFormat(const char *fmt, ...)
217{
218 if (!mEnabled) {
219 return;
220 }
221
222 va_list ap;
223 va_start(ap, fmt);
224 Writer::logVFormat(fmt, ap);
225 va_end(ap);
226}
227
228void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
229{
230 if (!mEnabled) {
231 return;
232 }
233 Writer::logStart(fmt);
234 int i;
235 double f;
236 char* s;
237 struct timespec t;
238 Writer::logTimestamp();
239 for (const char *p = fmt; *p != '\0'; p++) {
240 // TODO: implement more complex formatting such as %.3f
241 if (*p != '%') {
242 continue;
243 }
244 switch(*++p) {
245 case 's': // string
246 s = va_arg(argp, char *);
247 Writer::log(s);
248 break;
249
250 case 't': // timestamp
251 t = va_arg(argp, struct timespec);
252 Writer::logTimestamp(t);
253 break;
254
255 case 'd': // integer
256 i = va_arg(argp, int);
257 Writer::logInteger(i);
258 break;
259
260 case 'f': // float
261 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
262 Writer::logFloat((float)f);
263 break;
264
265 case 'p': // pid
266 Writer::logPID();
267 break;
268
269 // the "%\0" case finishes parsing
270 case '\0':
271 --p;
272 break;
273
274 default:
275 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
276 break;
277 // the '%' case is handled using the formatted string in the reader
278 }
279 }
280 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800281}
282
283void NBLog::Writer::log(Event event, const void *data, size_t length)
284{
285 if (!mEnabled) {
286 return;
287 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800288 if (data == NULL || length > Entry::kMaxLength) {
289 // TODO Perhaps it makes sense to display truncated data or at least a
290 // message that the data is too long? The current behavior can create
291 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800292 return;
293 }
294 switch (event) {
295 case EVENT_STRING:
296 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800297 case EVENT_INTEGER:
298 case EVENT_FLOAT:
299 case EVENT_PID:
300 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800301 break;
302 case EVENT_RESERVED:
303 default:
304 return;
305 }
306 Entry entry(event, data, length);
307 log(&entry, true /*trusted*/);
308}
309
310void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
311{
312 if (!mEnabled) {
313 return;
314 }
315 if (!trusted) {
316 log(entry->mEvent, entry->mData, entry->mLength);
317 return;
318 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800319 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
320 // need = number of bytes remaining to write
321
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800322 // FIXME optimize this using memcpy for the data part of the Entry.
323 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800324 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
325 for (size_t i = 0; i < need; i++) {
326 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800327 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800328 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800329}
330
331bool NBLog::Writer::isEnabled() const
332{
333 return mEnabled;
334}
335
336bool NBLog::Writer::setEnabled(bool enabled)
337{
338 bool old = mEnabled;
339 mEnabled = enabled && mShared != NULL;
340 return old;
341}
342
343// ---------------------------------------------------------------------------
344
345NBLog::LockedWriter::LockedWriter()
346 : Writer()
347{
348}
349
Glenn Kasten535e1612016-12-05 12:19:36 -0800350NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
351 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800352{
353}
354
355void NBLog::LockedWriter::log(const char *string)
356{
357 Mutex::Autolock _l(mLock);
358 Writer::log(string);
359}
360
361void NBLog::LockedWriter::logf(const char *fmt, ...)
362{
363 // FIXME should not take the lock until after formatting is done
364 Mutex::Autolock _l(mLock);
365 va_list ap;
366 va_start(ap, fmt);
367 Writer::logvf(fmt, ap);
368 va_end(ap);
369}
370
371void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
372{
373 // FIXME should not take the lock until after formatting is done
374 Mutex::Autolock _l(mLock);
375 Writer::logvf(fmt, ap);
376}
377
378void NBLog::LockedWriter::logTimestamp()
379{
380 // FIXME should not take the lock until after the clock_gettime() syscall
381 Mutex::Autolock _l(mLock);
382 Writer::logTimestamp();
383}
384
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800385void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800386{
387 Mutex::Autolock _l(mLock);
388 Writer::logTimestamp(ts);
389}
390
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800391void NBLog::LockedWriter::logInteger(const int x)
392{
393 Mutex::Autolock _l(mLock);
394 Writer::logInteger(x);
395}
396
397void NBLog::LockedWriter::logFloat(const float x)
398{
399 Mutex::Autolock _l(mLock);
400 Writer::logFloat(x);
401}
402
403void NBLog::LockedWriter::logPID()
404{
405 Mutex::Autolock _l(mLock);
406 Writer::logPID();
407}
408
409void NBLog::LockedWriter::logStart(const char *fmt)
410{
411 Mutex::Autolock _l(mLock);
412 Writer::logStart(fmt);
413}
414
415
416void NBLog::LockedWriter::logEnd()
417{
418 Mutex::Autolock _l(mLock);
419 Writer::logEnd();
420}
421
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800422bool NBLog::LockedWriter::isEnabled() const
423{
424 Mutex::Autolock _l(mLock);
425 return Writer::isEnabled();
426}
427
428bool NBLog::LockedWriter::setEnabled(bool enabled)
429{
430 Mutex::Autolock _l(mLock);
431 return Writer::setEnabled(enabled);
432}
433
434// ---------------------------------------------------------------------------
435
Glenn Kasten535e1612016-12-05 12:19:36 -0800436NBLog::Reader::Reader(const void *shared, size_t size)
437 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
438 mFd(-1), mIndent(0),
439 mFifo(mShared != NULL ?
440 new audio_utils_fifo(size, sizeof(uint8_t),
441 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
442 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800443{
444}
445
Glenn Kasten535e1612016-12-05 12:19:36 -0800446NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
447 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800448{
Glenn Kasten535e1612016-12-05 12:19:36 -0800449 mIMemory = iMemory;
450}
451
452NBLog::Reader::~Reader()
453{
454 delete mFifoReader;
455 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800456}
457
458void NBLog::Reader::dump(int fd, size_t indent)
459{
Glenn Kasten535e1612016-12-05 12:19:36 -0800460 if (mFifoReader == NULL) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800461 return;
462 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800463 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800464 size_t capacity = mFifo->capacity();
465
466 // TODO Stack-based allocation of large objects may fail.
467 // Currently the log buffers are a page or two, which should be safe.
468 // But if the log buffers ever get a lot larger,
469 // then change this to allocate from heap when necessary.
470 static size_t kReasonableStackObjectSize = 32768;
471 ALOGW_IF(capacity > kReasonableStackObjectSize, "Stack-based allocation of object may fail");
472 uint8_t copy[capacity];
473
474 size_t lost;
475 ssize_t actual = mFifoReader->read(copy, capacity, NULL /*timeout*/, &lost);
476 ALOG_ASSERT(actual <= capacity);
477 size_t avail = actual > 0 ? (size_t) actual : 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800478 size_t i = avail;
479 Event event;
480 size_t length;
481 struct timespec ts;
482 time_t maxSec = -1;
Glenn Kasten535e1612016-12-05 12:19:36 -0800483 while (i >= Entry::kOverhead) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800484 length = copy[i - 1];
Glenn Kasten535e1612016-12-05 12:19:36 -0800485 if (length + Entry::kOverhead > i || copy[i - length - 2] != length) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800486 break;
487 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800488 event = (Event) copy[i - length - Entry::kOverhead];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800489 if (event == EVENT_TIMESTAMP) {
490 if (length != sizeof(struct timespec)) {
491 // corrupt
492 break;
493 }
494 memcpy(&ts, &copy[i - length - 1], sizeof(struct timespec));
495 if (ts.tv_sec > maxSec) {
496 maxSec = ts.tv_sec;
497 }
498 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800499 i -= length + Entry::kOverhead;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800500 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700501 mFd = fd;
502 mIndent = indent;
503 String8 timestamp, body;
Glenn Kastenc02c9612013-10-15 09:25:11 -0700504 lost += i;
505 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700506 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700507 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
508 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
509 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800510 }
511 size_t width = 1;
512 while (maxSec >= 10) {
513 ++width;
514 maxSec /= 10;
515 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800516 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700517 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800518 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700519 bool deferredTimestamp = false;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800520 while (i < avail) {
521 event = (Event) copy[i];
522 length = copy[i + 1];
523 const void *data = &copy[i + 2];
Glenn Kasten535e1612016-12-05 12:19:36 -0800524 size_t advance = length + Entry::kOverhead;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800525 switch (event) {
526 case EVENT_STRING:
Glenn Kasten95d287d2014-04-28 14:11:45 -0700527 body.appendFormat("%.*s", (int) length, (const char *) data);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700528 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800529 case EVENT_TIMESTAMP: {
530 // already checked that length == sizeof(struct timespec);
531 memcpy(&ts, data, sizeof(struct timespec));
532 long prevNsec = ts.tv_nsec;
533 long deltaMin = LONG_MAX;
534 long deltaMax = -1;
535 long deltaTotal = 0;
536 size_t j = i;
537 for (;;) {
Glenn Kasten535e1612016-12-05 12:19:36 -0800538 j += sizeof(struct timespec) + 3 /*Entry::kOverhead?*/;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800539 if (j >= avail || (Event) copy[j] != EVENT_TIMESTAMP) {
540 break;
541 }
542 struct timespec tsNext;
543 memcpy(&tsNext, &copy[j + 2], sizeof(struct timespec));
544 if (tsNext.tv_sec != ts.tv_sec) {
545 break;
546 }
547 long delta = tsNext.tv_nsec - prevNsec;
548 if (delta < 0) {
549 break;
550 }
551 if (delta < deltaMin) {
552 deltaMin = delta;
553 }
554 if (delta > deltaMax) {
555 deltaMax = delta;
556 }
557 deltaTotal += delta;
558 prevNsec = tsNext.tv_nsec;
559 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800560 size_t n = (j - i) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700561 if (deferredTimestamp) {
562 dumpLine(timestamp, body);
563 deferredTimestamp = false;
564 }
565 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800566 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700567 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
568 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
569 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
570 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800571 i = j;
572 advance = 0;
573 break;
574 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700575 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
576 (int) (ts.tv_nsec / 1000000));
577 deferredTimestamp = true;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800578 } break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800579 case EVENT_INTEGER:
580 appendInt(&body, data);
581 break;
582 case EVENT_FLOAT:
583 appendFloat(&body, data);
584 break;
585 case EVENT_PID:
586 appendPID(&body, data);
587 break;
588 case EVENT_START_FMT:
589 advance += handleFormat((const char*) &copy[i + 2], length,
590 &copy[i + Entry::kOverhead + length], &timestamp, &body);
591 break;
592 case EVENT_END_FMT:
593 body.appendFormat("warning: got to end format event");
594 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800595 case EVENT_RESERVED:
596 default:
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700597 body.appendFormat("warning: unknown event %d", event);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800598 break;
599 }
600 i += advance;
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700601
602 if (!body.isEmpty()) {
603 dumpLine(timestamp, body);
604 deferredTimestamp = false;
605 }
606 }
607 if (deferredTimestamp) {
608 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800609 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800610}
611
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800612void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700613{
614 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700615 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700616 } else {
617 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
618 }
619 body.clear();
620}
621
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800622bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
623{
Glenn Kasten481fb672013-09-30 14:39:28 -0700624 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800625}
626
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800627void NBLog::appendTimestamp(String8 *body, const void *data) {
628 struct timespec ts;
629 memcpy(&ts, data, sizeof(struct timespec));
630 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
631 (int) (ts.tv_nsec / 1000000));
632}
633
634void NBLog::appendInt(String8 *body, const void *data) {
635 int x = *((int*) data);
636 body->appendFormat("<%d>", x);
637}
638
639void NBLog::appendFloat(String8 *body, const void *data) {
640 float f;
641 memcpy(&f, data, sizeof(float));
642 body->appendFormat("<%f>", f);
643}
644
645void NBLog::appendPID(String8 *body, const void* data) {
646 pid_t id = *((pid_t*) data);
647 body->appendFormat("<PID: %d>", id);
648}
649
650int NBLog::handleFormat(const char *fmt, size_t fmt_length, const uint8_t *data,
651 String8 *timestamp, String8 *body) {
652 if (data[0] != EVENT_TIMESTAMP) {
653 ALOGW("NBLog Reader Expected timestamp event %d, got %d", EVENT_TIMESTAMP, data[0]);
654 }
655 struct timespec ts;
656 memcpy(&ts, &data[2], sizeof(ts));
657 timestamp->clear();
658 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
659 (int) (ts.tv_nsec / 1000000));
660 size_t data_offset = Entry::kOverhead + sizeof ts;
661
662 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
663 if (fmt[fmt_offset] != '%') {
664 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
665 continue;
666 }
667 if (fmt[++fmt_offset] == '%') {
668 body->append("%");
669 continue;
670 }
671 if (fmt_offset == fmt_length) {
672 continue;
673 }
674
675 NBLog::Event event = (NBLog::Event) data[data_offset];
676 size_t length = data[data_offset + 1];
677
678 // TODO check length for event type is correct
679 if(length != data[data_offset + length + 2]) {
680 ALOGW("NBLog Reader recieved different lengths %zu and %d for event %d", length,
681 data[data_offset + length + 2], event);
682 body->append("<invalid entry>");
683 ++fmt_offset;
684 continue;
685 }
686
687 // TODO: implement more complex formatting such as %.3f
688 void * datum = (void*) &data[data_offset + 2]; // pointer to the current event data
689 switch(fmt[fmt_offset])
690 {
691 case 's': // string
692 ALOGW_IF(event != EVENT_STRING, "NBLog Reader incompatible event for string specifier: %d", event);
693 body->append((const char*) datum, length);
694 break;
695
696 case 't': // timestamp
697 ALOGW_IF(event != EVENT_TIMESTAMP, "NBLog Reader incompatible event for timestamp specifier: %d", event);
698 appendTimestamp(body, datum);
699 break;
700
701 case 'd': // integer
702 ALOGW_IF(event != EVENT_INTEGER, "NBLog Reader incompatible event for integer specifier: %d", event);
703 appendInt(body, datum);
704
705 break;
706
707 case 'f': // float
708 ALOGW_IF(event != EVENT_FLOAT, "NBLog Reader incompatible event for float specifier: %d", event);
709 appendFloat(body, datum);
710 break;
711
712 case 'p': // pid
713 ALOGW_IF(event != EVENT_PID, "NBLog Reader incompatible event for pid specifier: %d", event);
714 appendPID(body, datum);
715 break;
716
717 default:
718 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
719 }
720
721 data_offset += length + Entry::kOverhead;
722
723 }
724 return data_offset + Entry::kOverhead; // data offset + size of END_FMT event
725}
726
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800727} // namespace android