blob: f1c3f10f41bd8864c417f0214331520d86eee724 [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
32namespace android {
33
34int NBLog::Entry::readAt(size_t offset) const
35{
36 // FIXME This is too slow, despite the name it is used during writing
37 if (offset == 0)
38 return mEvent;
39 else if (offset == 1)
40 return mLength;
41 else if (offset < (size_t) (mLength + 2))
42 return ((char *) mData)[offset - 2];
43 else if (offset == (size_t) (mLength + 2))
44 return mLength;
45 else
46 return 0;
47}
48
49// ---------------------------------------------------------------------------
50
51#if 0 // FIXME see note in NBLog.h
52NBLog::Timeline::Timeline(size_t size, void *shared)
53 : mSize(roundup(size)), mOwn(shared == NULL),
54 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
55{
56 new (mShared) Shared;
57}
58
59NBLog::Timeline::~Timeline()
60{
61 mShared->~Shared();
62 if (mOwn) {
63 delete[] (char *) mShared;
64 }
65}
66#endif
67
68/*static*/
69size_t NBLog::Timeline::sharedSize(size_t size)
70{
Glenn Kastened99c2b2016-12-12 08:31:24 -080071 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080072 return sizeof(Shared) + roundup(size);
73}
74
75// ---------------------------------------------------------------------------
76
77NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -080078 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080079{
80}
81
Glenn Kasten535e1612016-12-05 12:19:36 -080082NBLog::Writer::Writer(void *shared, size_t size)
83 : mShared((Shared *) shared),
84 mFifo(mShared != NULL ?
85 new audio_utils_fifo(size, sizeof(uint8_t),
86 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
87 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
88 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080089{
Nicolas Rouletc20cb502017-02-01 12:35:24 -080090 // caching pid and process name
91 pid_t id = ::getpid();
92 char procName[16];
93 int status = prctl(PR_GET_NAME, procName);
94 if (status) { // error getting process name
95 procName[0] = '\0';
96 }
97 size_t length = strlen(procName);
98 mPidTagSize = length + sizeof(pid_t);
99 mPidTag = new char[mPidTagSize];
100 memcpy(mPidTag, &id, sizeof(pid_t));
101 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800102}
103
Glenn Kasten535e1612016-12-05 12:19:36 -0800104NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
105 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800106{
Glenn Kasten535e1612016-12-05 12:19:36 -0800107 mIMemory = iMemory;
108}
109
110NBLog::Writer::~Writer()
111{
112 delete mFifoWriter;
113 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800114 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800115}
116
117void NBLog::Writer::log(const char *string)
118{
119 if (!mEnabled) {
120 return;
121 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800122 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800123 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800124 if (length > Entry::kMaxLength) {
125 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800126 }
127 log(EVENT_STRING, string, length);
128}
129
130void NBLog::Writer::logf(const char *fmt, ...)
131{
132 if (!mEnabled) {
133 return;
134 }
135 va_list ap;
136 va_start(ap, fmt);
137 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
138 va_end(ap);
139}
140
141void NBLog::Writer::logvf(const char *fmt, va_list ap)
142{
143 if (!mEnabled) {
144 return;
145 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800146 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800147 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
148 if (length >= (int) sizeof(buffer)) {
149 length = sizeof(buffer) - 1;
150 // NUL termination is not required
151 // buffer[length] = '\0';
152 }
153 if (length >= 0) {
154 log(EVENT_STRING, buffer, length);
155 }
156}
157
158void NBLog::Writer::logTimestamp()
159{
160 if (!mEnabled) {
161 return;
162 }
163 struct timespec ts;
164 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800165 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800166 }
167}
168
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800169void NBLog::Writer::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800170{
171 if (!mEnabled) {
172 return;
173 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800174 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
175}
176
177void NBLog::Writer::logInteger(const int x)
178{
179 if (!mEnabled) {
180 return;
181 }
182 log(EVENT_INTEGER, &x, sizeof(x));
183}
184
185void NBLog::Writer::logFloat(const float x)
186{
187 if (!mEnabled) {
188 return;
189 }
190 log(EVENT_FLOAT, &x, sizeof(x));
191}
192
193void NBLog::Writer::logPID()
194{
195 if (!mEnabled) {
196 return;
197 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800198 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800199}
200
201void NBLog::Writer::logStart(const char *fmt)
202{
203 if (!mEnabled) {
204 return;
205 }
206 size_t length = strlen(fmt);
207 if (length > Entry::kMaxLength) {
208 length = Entry::kMaxLength;
209 }
210 log(EVENT_START_FMT, fmt, length);
211}
212
213void NBLog::Writer::logEnd()
214{
215 if (!mEnabled) {
216 return;
217 }
218 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
219 log(&entry, true);
220}
221
222void NBLog::Writer::logFormat(const char *fmt, ...)
223{
224 if (!mEnabled) {
225 return;
226 }
227
228 va_list ap;
229 va_start(ap, fmt);
230 Writer::logVFormat(fmt, ap);
231 va_end(ap);
232}
233
234void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
235{
236 if (!mEnabled) {
237 return;
238 }
239 Writer::logStart(fmt);
240 int i;
241 double f;
242 char* s;
243 struct timespec t;
244 Writer::logTimestamp();
245 for (const char *p = fmt; *p != '\0'; p++) {
246 // TODO: implement more complex formatting such as %.3f
247 if (*p != '%') {
248 continue;
249 }
250 switch(*++p) {
251 case 's': // string
252 s = va_arg(argp, char *);
253 Writer::log(s);
254 break;
255
256 case 't': // timestamp
257 t = va_arg(argp, struct timespec);
258 Writer::logTimestamp(t);
259 break;
260
261 case 'd': // integer
262 i = va_arg(argp, int);
263 Writer::logInteger(i);
264 break;
265
266 case 'f': // float
267 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
268 Writer::logFloat((float)f);
269 break;
270
271 case 'p': // pid
272 Writer::logPID();
273 break;
274
275 // the "%\0" case finishes parsing
276 case '\0':
277 --p;
278 break;
279
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800280 case '%':
281 break;
282
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800283 default:
284 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
285 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800286 }
287 }
288 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800289}
290
291void NBLog::Writer::log(Event event, const void *data, size_t length)
292{
293 if (!mEnabled) {
294 return;
295 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800296 if (data == NULL || length > Entry::kMaxLength) {
297 // TODO Perhaps it makes sense to display truncated data or at least a
298 // message that the data is too long? The current behavior can create
299 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800300 return;
301 }
302 switch (event) {
303 case EVENT_STRING:
304 case EVENT_TIMESTAMP:
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800305 case EVENT_INTEGER:
306 case EVENT_FLOAT:
307 case EVENT_PID:
308 case EVENT_START_FMT:
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800309 break;
310 case EVENT_RESERVED:
311 default:
312 return;
313 }
314 Entry entry(event, data, length);
315 log(&entry, true /*trusted*/);
316}
317
318void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
319{
320 if (!mEnabled) {
321 return;
322 }
323 if (!trusted) {
324 log(entry->mEvent, entry->mData, entry->mLength);
325 return;
326 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800327 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
328 // need = number of bytes remaining to write
329
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800330 // FIXME optimize this using memcpy for the data part of the Entry.
331 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800332 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
333 for (size_t i = 0; i < need; i++) {
334 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800335 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800336 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800337}
338
339bool NBLog::Writer::isEnabled() const
340{
341 return mEnabled;
342}
343
344bool NBLog::Writer::setEnabled(bool enabled)
345{
346 bool old = mEnabled;
347 mEnabled = enabled && mShared != NULL;
348 return old;
349}
350
351// ---------------------------------------------------------------------------
352
353NBLog::LockedWriter::LockedWriter()
354 : Writer()
355{
356}
357
Glenn Kasten535e1612016-12-05 12:19:36 -0800358NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
359 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800360{
361}
362
363void NBLog::LockedWriter::log(const char *string)
364{
365 Mutex::Autolock _l(mLock);
366 Writer::log(string);
367}
368
369void NBLog::LockedWriter::logf(const char *fmt, ...)
370{
371 // FIXME should not take the lock until after formatting is done
372 Mutex::Autolock _l(mLock);
373 va_list ap;
374 va_start(ap, fmt);
375 Writer::logvf(fmt, ap);
376 va_end(ap);
377}
378
379void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
380{
381 // FIXME should not take the lock until after formatting is done
382 Mutex::Autolock _l(mLock);
383 Writer::logvf(fmt, ap);
384}
385
386void NBLog::LockedWriter::logTimestamp()
387{
388 // FIXME should not take the lock until after the clock_gettime() syscall
389 Mutex::Autolock _l(mLock);
390 Writer::logTimestamp();
391}
392
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800393void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800394{
395 Mutex::Autolock _l(mLock);
396 Writer::logTimestamp(ts);
397}
398
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800399void NBLog::LockedWriter::logInteger(const int x)
400{
401 Mutex::Autolock _l(mLock);
402 Writer::logInteger(x);
403}
404
405void NBLog::LockedWriter::logFloat(const float x)
406{
407 Mutex::Autolock _l(mLock);
408 Writer::logFloat(x);
409}
410
411void NBLog::LockedWriter::logPID()
412{
413 Mutex::Autolock _l(mLock);
414 Writer::logPID();
415}
416
417void NBLog::LockedWriter::logStart(const char *fmt)
418{
419 Mutex::Autolock _l(mLock);
420 Writer::logStart(fmt);
421}
422
423
424void NBLog::LockedWriter::logEnd()
425{
426 Mutex::Autolock _l(mLock);
427 Writer::logEnd();
428}
429
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800430bool NBLog::LockedWriter::isEnabled() const
431{
432 Mutex::Autolock _l(mLock);
433 return Writer::isEnabled();
434}
435
436bool NBLog::LockedWriter::setEnabled(bool enabled)
437{
438 Mutex::Autolock _l(mLock);
439 return Writer::setEnabled(enabled);
440}
441
442// ---------------------------------------------------------------------------
443
Glenn Kasten535e1612016-12-05 12:19:36 -0800444NBLog::Reader::Reader(const void *shared, size_t size)
445 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
446 mFd(-1), mIndent(0),
447 mFifo(mShared != NULL ?
448 new audio_utils_fifo(size, sizeof(uint8_t),
449 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
450 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800451{
452}
453
Glenn Kasten535e1612016-12-05 12:19:36 -0800454NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
455 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800456{
Glenn Kasten535e1612016-12-05 12:19:36 -0800457 mIMemory = iMemory;
458}
459
460NBLog::Reader::~Reader()
461{
462 delete mFifoReader;
463 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800464}
465
466void NBLog::Reader::dump(int fd, size_t indent)
467{
Glenn Kasten535e1612016-12-05 12:19:36 -0800468 if (mFifoReader == NULL) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800469 return;
470 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800471 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800472 size_t capacity = mFifo->capacity();
473
474 // TODO Stack-based allocation of large objects may fail.
475 // Currently the log buffers are a page or two, which should be safe.
476 // But if the log buffers ever get a lot larger,
477 // then change this to allocate from heap when necessary.
478 static size_t kReasonableStackObjectSize = 32768;
479 ALOGW_IF(capacity > kReasonableStackObjectSize, "Stack-based allocation of object may fail");
480 uint8_t copy[capacity];
481
482 size_t lost;
483 ssize_t actual = mFifoReader->read(copy, capacity, NULL /*timeout*/, &lost);
484 ALOG_ASSERT(actual <= capacity);
485 size_t avail = actual > 0 ? (size_t) actual : 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800486 size_t i = avail;
487 Event event;
488 size_t length;
489 struct timespec ts;
490 time_t maxSec = -1;
Glenn Kasten535e1612016-12-05 12:19:36 -0800491 while (i >= Entry::kOverhead) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800492 length = copy[i - 1];
Glenn Kasten535e1612016-12-05 12:19:36 -0800493 if (length + Entry::kOverhead > i || copy[i - length - 2] != length) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800494 break;
495 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800496 event = (Event) copy[i - length - Entry::kOverhead];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800497 if (event == EVENT_TIMESTAMP) {
498 if (length != sizeof(struct timespec)) {
499 // corrupt
500 break;
501 }
502 memcpy(&ts, &copy[i - length - 1], sizeof(struct timespec));
503 if (ts.tv_sec > maxSec) {
504 maxSec = ts.tv_sec;
505 }
506 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800507 i -= length + Entry::kOverhead;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800508 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700509 mFd = fd;
510 mIndent = indent;
511 String8 timestamp, body;
Glenn Kastenc02c9612013-10-15 09:25:11 -0700512 lost += i;
513 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700514 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700515 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
516 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
517 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800518 }
519 size_t width = 1;
520 while (maxSec >= 10) {
521 ++width;
522 maxSec /= 10;
523 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800524 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700525 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800526 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700527 bool deferredTimestamp = false;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800528 while (i < avail) {
529 event = (Event) copy[i];
530 length = copy[i + 1];
531 const void *data = &copy[i + 2];
Glenn Kasten535e1612016-12-05 12:19:36 -0800532 size_t advance = length + Entry::kOverhead;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800533 switch (event) {
534 case EVENT_STRING:
Glenn Kasten95d287d2014-04-28 14:11:45 -0700535 body.appendFormat("%.*s", (int) length, (const char *) data);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700536 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800537 case EVENT_TIMESTAMP: {
538 // already checked that length == sizeof(struct timespec);
539 memcpy(&ts, data, sizeof(struct timespec));
540 long prevNsec = ts.tv_nsec;
541 long deltaMin = LONG_MAX;
542 long deltaMax = -1;
543 long deltaTotal = 0;
544 size_t j = i;
545 for (;;) {
Glenn Kasten535e1612016-12-05 12:19:36 -0800546 j += sizeof(struct timespec) + 3 /*Entry::kOverhead?*/;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800547 if (j >= avail || (Event) copy[j] != EVENT_TIMESTAMP) {
548 break;
549 }
550 struct timespec tsNext;
551 memcpy(&tsNext, &copy[j + 2], sizeof(struct timespec));
552 if (tsNext.tv_sec != ts.tv_sec) {
553 break;
554 }
555 long delta = tsNext.tv_nsec - prevNsec;
556 if (delta < 0) {
557 break;
558 }
559 if (delta < deltaMin) {
560 deltaMin = delta;
561 }
562 if (delta > deltaMax) {
563 deltaMax = delta;
564 }
565 deltaTotal += delta;
566 prevNsec = tsNext.tv_nsec;
567 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800568 size_t n = (j - i) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700569 if (deferredTimestamp) {
570 dumpLine(timestamp, body);
571 deferredTimestamp = false;
572 }
573 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800574 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700575 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
576 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
577 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
578 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800579 i = j;
580 advance = 0;
581 break;
582 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700583 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
584 (int) (ts.tv_nsec / 1000000));
585 deferredTimestamp = true;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800586 } break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800587 case EVENT_INTEGER:
588 appendInt(&body, data);
589 break;
590 case EVENT_FLOAT:
591 appendFloat(&body, data);
592 break;
593 case EVENT_PID:
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800594 appendPID(&body, data, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800595 break;
596 case EVENT_START_FMT:
597 advance += handleFormat((const char*) &copy[i + 2], length,
598 &copy[i + Entry::kOverhead + length], &timestamp, &body);
599 break;
600 case EVENT_END_FMT:
601 body.appendFormat("warning: got to end format event");
602 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800603 case EVENT_RESERVED:
604 default:
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700605 body.appendFormat("warning: unknown event %d", event);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800606 break;
607 }
608 i += advance;
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700609
610 if (!body.isEmpty()) {
611 dumpLine(timestamp, body);
612 deferredTimestamp = false;
613 }
614 }
615 if (deferredTimestamp) {
616 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800617 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800618}
619
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800620void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700621{
622 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700623 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700624 } else {
625 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
626 }
627 body.clear();
628}
629
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800630bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
631{
Glenn Kasten481fb672013-09-30 14:39:28 -0700632 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800633}
634
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800635void NBLog::appendTimestamp(String8 *body, const void *data) {
636 struct timespec ts;
637 memcpy(&ts, data, sizeof(struct timespec));
638 body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
639 (int) (ts.tv_nsec / 1000000));
640}
641
642void NBLog::appendInt(String8 *body, const void *data) {
643 int x = *((int*) data);
644 body->appendFormat("<%d>", x);
645}
646
647void NBLog::appendFloat(String8 *body, const void *data) {
648 float f;
649 memcpy(&f, data, sizeof(float));
650 body->appendFormat("<%f>", f);
651}
652
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800653void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800654 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800655 char * name = &((char*) data)[sizeof(pid_t)];
656 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800657}
658
659int NBLog::handleFormat(const char *fmt, size_t fmt_length, const uint8_t *data,
660 String8 *timestamp, String8 *body) {
661 if (data[0] != EVENT_TIMESTAMP) {
662 ALOGW("NBLog Reader Expected timestamp event %d, got %d", EVENT_TIMESTAMP, data[0]);
663 }
664 struct timespec ts;
665 memcpy(&ts, &data[2], sizeof(ts));
666 timestamp->clear();
667 timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
668 (int) (ts.tv_nsec / 1000000));
669 size_t data_offset = Entry::kOverhead + sizeof ts;
670
671 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
672 if (fmt[fmt_offset] != '%') {
673 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
674 continue;
675 }
676 if (fmt[++fmt_offset] == '%') {
677 body->append("%");
678 continue;
679 }
680 if (fmt_offset == fmt_length) {
681 continue;
682 }
683
684 NBLog::Event event = (NBLog::Event) data[data_offset];
685 size_t length = data[data_offset + 1];
686
687 // TODO check length for event type is correct
688 if(length != data[data_offset + length + 2]) {
689 ALOGW("NBLog Reader recieved different lengths %zu and %d for event %d", length,
690 data[data_offset + length + 2], event);
691 body->append("<invalid entry>");
692 ++fmt_offset;
693 continue;
694 }
695
696 // TODO: implement more complex formatting such as %.3f
697 void * datum = (void*) &data[data_offset + 2]; // pointer to the current event data
698 switch(fmt[fmt_offset])
699 {
700 case 's': // string
701 ALOGW_IF(event != EVENT_STRING, "NBLog Reader incompatible event for string specifier: %d", event);
702 body->append((const char*) datum, length);
703 break;
704
705 case 't': // timestamp
706 ALOGW_IF(event != EVENT_TIMESTAMP, "NBLog Reader incompatible event for timestamp specifier: %d", event);
707 appendTimestamp(body, datum);
708 break;
709
710 case 'd': // integer
711 ALOGW_IF(event != EVENT_INTEGER, "NBLog Reader incompatible event for integer specifier: %d", event);
712 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800713 break;
714
715 case 'f': // float
716 ALOGW_IF(event != EVENT_FLOAT, "NBLog Reader incompatible event for float specifier: %d", event);
717 appendFloat(body, datum);
718 break;
719
720 case 'p': // pid
721 ALOGW_IF(event != EVENT_PID, "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800722 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800723 break;
724
725 default:
726 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
727 }
728
729 data_offset += length + Entry::kOverhead;
730
731 }
732 return data_offset + Entry::kOverhead; // data offset + size of END_FMT event
733}
734
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800735} // namespace android