blob: 88bd9814b4fddd900699d928d651104b03dd4d14 [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>
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070034#include <utility>
Nicolas Roulet40a44982017-02-03 13:39:57 -080035
Glenn Kasten11d8dfc2013-01-14 14:53:13 -080036namespace android {
37
38int NBLog::Entry::readAt(size_t offset) const
39{
40 // FIXME This is too slow, despite the name it is used during writing
41 if (offset == 0)
42 return mEvent;
43 else if (offset == 1)
44 return mLength;
45 else if (offset < (size_t) (mLength + 2))
46 return ((char *) mData)[offset - 2];
47 else if (offset == (size_t) (mLength + 2))
48 return mLength;
49 else
50 return 0;
51}
52
53// ---------------------------------------------------------------------------
54
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070055/*static*/
56std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
57 uint8_t type = EntryIterator(ptr)->type;
58 switch (type) {
59 case EVENT_START_FMT:
60 return std::make_unique<FormatEntry>(FormatEntry(ptr));
61 case EVENT_HISTOGRAM_FLUSH:
62 case EVENT_HISTOGRAM_ENTRY_TS:
63 return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
64 default:
65 ALOGW("Tried to create AbstractEntry of type %d", type);
66 return nullptr;
67 }
Nicolas Roulet40a44982017-02-03 13:39:57 -080068}
69
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070070NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
71}
72
73// ---------------------------------------------------------------------------
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080074
Nicolas Roulet40a44982017-02-03 13:39:57 -080075const char *NBLog::FormatEntry::formatString() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080076 return (const char*) mEntry + offsetof(entry, data);
Nicolas Roulet40a44982017-02-03 13:39:57 -080077}
78
79size_t NBLog::FormatEntry::formatStringLength() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080080 return mEntry[offsetof(entry, length)];
Nicolas Roulet40a44982017-02-03 13:39:57 -080081}
82
Nicolas Roulet537ad7d2017-03-21 16:24:30 -070083NBLog::EntryIterator NBLog::FormatEntry::args() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080084 auto it = begin();
Nicolas Roulet1ca75122017-03-16 14:19:59 -070085 // skip start fmt
86 ++it;
87 // skip timestamp
88 ++it;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -070089 // skip hash
90 ++it;
Nicolas Roulet1ca75122017-03-16 14:19:59 -070091 // Skip author if present
92 if (it->type == EVENT_AUTHOR) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080093 ++it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080094 }
Nicolas Roulet1ca75122017-03-16 14:19:59 -070095 return it;
Nicolas Roulet40a44982017-02-03 13:39:57 -080096}
97
Nicolas Rouletf42f1562017-03-30 19:16:22 -070098int64_t NBLog::FormatEntry::timestamp() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -080099 auto it = begin();
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700100 // skip start fmt
101 ++it;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700102 return it.payload<int64_t>();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800103}
104
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700105NBLog::log_hash_t NBLog::FormatEntry::hash() const {
106 auto it = begin();
107 // skip start fmt
108 ++it;
109 // skip timestamp
110 ++it;
111 // unaligned 64-bit read not supported
112 log_hash_t hash;
113 memcpy(&hash, it->data, sizeof(hash));
114 return hash;
115}
116
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700117int NBLog::FormatEntry::author() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800118 auto it = begin();
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700119 // skip start fmt
120 ++it;
121 // skip timestamp
122 ++it;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700123 // skip hash
124 ++it;
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700125 // if there is an author entry, return it, return -1 otherwise
126 if (it->type == EVENT_AUTHOR) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800127 return it.payload<int>();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800128 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800129 return -1;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800130}
131
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700132NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800133 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
134 auto it = begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -0800135 // copy fmt start entry
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800136 it.copyTo(dst);
Nicolas Roulet1ca75122017-03-16 14:19:59 -0700137 // copy timestamp
138 (++it).copyTo(dst);
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700139 // copy hash
140 (++it).copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800141 // insert author entry
142 size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
143 uint8_t authorEntry[authorEntrySize];
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800144 authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
145 authorEntry[offsetof(entry, length)] =
146 authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
147 sizeof(author);
148 *(int*) (&authorEntry[offsetof(entry, data)]) = author;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800149 dst->write(authorEntry, authorEntrySize);
150 // copy rest of entries
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800151 while ((++it)->type != EVENT_END_FMT) {
152 it.copyTo(dst);
Nicolas Roulet40a44982017-02-03 13:39:57 -0800153 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800154 it.copyTo(dst);
155 ++it;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800156 return it;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800157}
158
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700159void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800160 size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
161 dst->write(ptr, length);
162}
Nicolas Roulet40a44982017-02-03 13:39:57 -0800163
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700164void NBLog::EntryIterator::copyData(uint8_t *dst) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800165 memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
166}
167
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700168NBLog::EntryIterator NBLog::FormatEntry::begin() const {
169 return EntryIterator(mEntry);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800170}
171
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700172NBLog::EntryIterator::EntryIterator()
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800173 : ptr(nullptr) {}
174
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700175NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800176 : ptr(entry) {}
177
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700178NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800179 : ptr(other.ptr) {}
180
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700181const NBLog::entry& NBLog::EntryIterator::operator*() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800182 return *(entry*) ptr;
183}
184
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700185const NBLog::entry* NBLog::EntryIterator::operator->() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800186 return (entry*) ptr;
187}
188
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700189NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800190 ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
191 return *this;
192}
193
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700194NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800195 ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
196 return *this;
197}
198
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700199NBLog::EntryIterator NBLog::EntryIterator::next() const {
200 EntryIterator aux(*this);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800201 return ++aux;
202}
203
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700204NBLog::EntryIterator NBLog::EntryIterator::prev() const {
205 EntryIterator aux(*this);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800206 return --aux;
207}
208
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700209int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800210 return ptr - other.ptr;
211}
212
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700213bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800214 return ptr != other.ptr;
215}
216
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700217bool NBLog::EntryIterator::hasConsistentLength() const {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800218 return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
219 NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
Nicolas Roulet40a44982017-02-03 13:39:57 -0800220}
221
222// ---------------------------------------------------------------------------
223
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700224int64_t NBLog::HistogramEntry::timestamp() const {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700225 return EntryIterator(mEntry).payload<HistTsEntry>().ts;
226}
227
228NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
229 return EntryIterator(mEntry).payload<HistTsEntry>().hash;
230}
231
232int NBLog::HistogramEntry::author() const {
233 EntryIterator it(mEntry);
234 if (it->length == sizeof(HistTsEntryWithAuthor)) {
235 return it.payload<HistTsEntryWithAuthor>().author;
236 } else {
237 return -1;
238 }
239}
240
241NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
242 std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
243 // Current histogram entry has {type, length, struct HistTsEntry, length}.
244 // We now want {type, length, struct HistTsEntryWithAuthor, length}
245 uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
246 // Copy content until the point we want to add the author
247 memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
248 // Copy the author
249 *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
250 // Update lengths
251 buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
252 buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor);
253 // Write new buffer into FIFO
254 dst->write(buffer, sizeof(buffer));
255 return EntryIterator(mEntry).next();
256}
257
258// ---------------------------------------------------------------------------
259
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800260#if 0 // FIXME see note in NBLog.h
261NBLog::Timeline::Timeline(size_t size, void *shared)
262 : mSize(roundup(size)), mOwn(shared == NULL),
263 mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
264{
265 new (mShared) Shared;
266}
267
268NBLog::Timeline::~Timeline()
269{
270 mShared->~Shared();
271 if (mOwn) {
272 delete[] (char *) mShared;
273 }
274}
275#endif
276
277/*static*/
278size_t NBLog::Timeline::sharedSize(size_t size)
279{
Glenn Kastened99c2b2016-12-12 08:31:24 -0800280 // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800281 return sizeof(Shared) + roundup(size);
282}
283
284// ---------------------------------------------------------------------------
285
286NBLog::Writer::Writer()
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800287 : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800288{
289}
290
Glenn Kasten535e1612016-12-05 12:19:36 -0800291NBLog::Writer::Writer(void *shared, size_t size)
292 : mShared((Shared *) shared),
293 mFifo(mShared != NULL ?
294 new audio_utils_fifo(size, sizeof(uint8_t),
295 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
296 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
297 mEnabled(mFifoWriter != NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800298{
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800299 // caching pid and process name
300 pid_t id = ::getpid();
301 char procName[16];
302 int status = prctl(PR_GET_NAME, procName);
303 if (status) { // error getting process name
304 procName[0] = '\0';
305 }
306 size_t length = strlen(procName);
307 mPidTagSize = length + sizeof(pid_t);
308 mPidTag = new char[mPidTagSize];
309 memcpy(mPidTag, &id, sizeof(pid_t));
310 memcpy(mPidTag + sizeof(pid_t), procName, length);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800311}
312
Glenn Kasten535e1612016-12-05 12:19:36 -0800313NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
314 : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800315{
Glenn Kasten535e1612016-12-05 12:19:36 -0800316 mIMemory = iMemory;
317}
318
319NBLog::Writer::~Writer()
320{
321 delete mFifoWriter;
322 delete mFifo;
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800323 delete[] mPidTag;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800324}
325
326void NBLog::Writer::log(const char *string)
327{
328 if (!mEnabled) {
329 return;
330 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800331 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800332 size_t length = strlen(string);
Glenn Kasten535e1612016-12-05 12:19:36 -0800333 if (length > Entry::kMaxLength) {
334 length = Entry::kMaxLength;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800335 }
336 log(EVENT_STRING, string, length);
337}
338
339void NBLog::Writer::logf(const char *fmt, ...)
340{
341 if (!mEnabled) {
342 return;
343 }
344 va_list ap;
345 va_start(ap, fmt);
346 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
347 va_end(ap);
348}
349
350void NBLog::Writer::logvf(const char *fmt, va_list ap)
351{
352 if (!mEnabled) {
353 return;
354 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800355 char buffer[Entry::kMaxLength + 1 /*NUL*/];
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800356 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
357 if (length >= (int) sizeof(buffer)) {
358 length = sizeof(buffer) - 1;
359 // NUL termination is not required
360 // buffer[length] = '\0';
361 }
362 if (length >= 0) {
363 log(EVENT_STRING, buffer, length);
364 }
365}
366
367void NBLog::Writer::logTimestamp()
368{
369 if (!mEnabled) {
370 return;
371 }
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700372 int64_t ts = get_monotonic_ns();
373 if (ts > 0) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800374 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700375 } else {
376 ALOGE("Failed to get timestamp");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800377 }
378}
379
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700380void NBLog::Writer::logTimestamp(const int64_t ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800381{
382 if (!mEnabled) {
383 return;
384 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800385 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
386}
387
388void NBLog::Writer::logInteger(const int x)
389{
390 if (!mEnabled) {
391 return;
392 }
393 log(EVENT_INTEGER, &x, sizeof(x));
394}
395
396void NBLog::Writer::logFloat(const float x)
397{
398 if (!mEnabled) {
399 return;
400 }
401 log(EVENT_FLOAT, &x, sizeof(x));
402}
403
404void NBLog::Writer::logPID()
405{
406 if (!mEnabled) {
407 return;
408 }
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800409 log(EVENT_PID, mPidTag, mPidTagSize);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800410}
411
412void NBLog::Writer::logStart(const char *fmt)
413{
414 if (!mEnabled) {
415 return;
416 }
417 size_t length = strlen(fmt);
418 if (length > Entry::kMaxLength) {
419 length = Entry::kMaxLength;
420 }
421 log(EVENT_START_FMT, fmt, length);
422}
423
424void NBLog::Writer::logEnd()
425{
426 if (!mEnabled) {
427 return;
428 }
429 Entry entry = Entry(EVENT_END_FMT, NULL, 0);
430 log(&entry, true);
431}
432
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700433void NBLog::Writer::logHash(log_hash_t hash)
434{
435 if (!mEnabled) {
436 return;
437 }
438 log(EVENT_HASH, &hash, sizeof(hash));
439}
440
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700441void NBLog::Writer::logHistTS(log_hash_t hash)
442{
443 if (!mEnabled) {
444 return;
445 }
446 HistTsEntry data;
447 data.hash = hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700448 data.ts = get_monotonic_ns();
449 if (data.ts > 0) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700450 log(EVENT_HISTOGRAM_ENTRY_TS, &data, sizeof(data));
451 } else {
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700452 ALOGE("Failed to get timestamp");
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700453 }
454}
455
456void NBLog::Writer::logHistFlush(log_hash_t hash)
457{
458 if (!mEnabled) {
459 return;
460 }
461 HistTsEntry data;
462 data.hash = hash;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700463 data.ts = get_monotonic_ns();
464 if (data.ts > 0) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700465 log(EVENT_HISTOGRAM_FLUSH, &data, sizeof(data));
466 } else {
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700467 ALOGE("Failed to get timestamp");
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700468 }
469}
470
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700471void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800472{
473 if (!mEnabled) {
474 return;
475 }
476
477 va_list ap;
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700478 va_start(ap, hash);
479 Writer::logVFormat(fmt, hash, ap);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800480 va_end(ap);
481}
482
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700483void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800484{
485 if (!mEnabled) {
486 return;
487 }
488 Writer::logStart(fmt);
489 int i;
490 double f;
491 char* s;
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700492 int64_t t;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800493 Writer::logTimestamp();
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700494 Writer::logHash(hash);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800495 for (const char *p = fmt; *p != '\0'; p++) {
496 // TODO: implement more complex formatting such as %.3f
497 if (*p != '%') {
498 continue;
499 }
500 switch(*++p) {
501 case 's': // string
502 s = va_arg(argp, char *);
503 Writer::log(s);
504 break;
505
506 case 't': // timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700507 t = va_arg(argp, int64_t);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800508 Writer::logTimestamp(t);
509 break;
510
511 case 'd': // integer
512 i = va_arg(argp, int);
513 Writer::logInteger(i);
514 break;
515
516 case 'f': // float
517 f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
518 Writer::logFloat((float)f);
519 break;
520
521 case 'p': // pid
522 Writer::logPID();
523 break;
524
525 // the "%\0" case finishes parsing
526 case '\0':
527 --p;
528 break;
529
Nicolas Rouletc20cb502017-02-01 12:35:24 -0800530 case '%':
531 break;
532
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800533 default:
534 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
535 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800536 }
537 }
538 Writer::logEnd();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800539}
540
541void NBLog::Writer::log(Event event, const void *data, size_t length)
542{
543 if (!mEnabled) {
544 return;
545 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800546 if (data == NULL || length > Entry::kMaxLength) {
547 // TODO Perhaps it makes sense to display truncated data or at least a
548 // message that the data is too long? The current behavior can create
549 // a confusion for a programmer debugging their code.
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800550 return;
551 }
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700552 // Ignore if invalid event
553 if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800554 return;
555 }
556 Entry entry(event, data, length);
557 log(&entry, true /*trusted*/);
558}
559
560void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
561{
562 if (!mEnabled) {
563 return;
564 }
565 if (!trusted) {
566 log(entry->mEvent, entry->mData, entry->mLength);
567 return;
568 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800569 size_t need = entry->mLength + Entry::kOverhead; // mEvent, mLength, data[length], mLength
570 // need = number of bytes remaining to write
571
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800572 // FIXME optimize this using memcpy for the data part of the Entry.
573 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
Glenn Kasten535e1612016-12-05 12:19:36 -0800574 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
575 for (size_t i = 0; i < need; i++) {
576 temp[i] = entry->readAt(i);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800577 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800578 mFifoWriter->write(temp, need);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800579}
580
581bool NBLog::Writer::isEnabled() const
582{
583 return mEnabled;
584}
585
586bool NBLog::Writer::setEnabled(bool enabled)
587{
588 bool old = mEnabled;
589 mEnabled = enabled && mShared != NULL;
590 return old;
591}
592
593// ---------------------------------------------------------------------------
594
595NBLog::LockedWriter::LockedWriter()
596 : Writer()
597{
598}
599
Glenn Kasten535e1612016-12-05 12:19:36 -0800600NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
601 : Writer(shared, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800602{
603}
604
605void NBLog::LockedWriter::log(const char *string)
606{
607 Mutex::Autolock _l(mLock);
608 Writer::log(string);
609}
610
611void NBLog::LockedWriter::logf(const char *fmt, ...)
612{
613 // FIXME should not take the lock until after formatting is done
614 Mutex::Autolock _l(mLock);
615 va_list ap;
616 va_start(ap, fmt);
617 Writer::logvf(fmt, ap);
618 va_end(ap);
619}
620
621void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
622{
623 // FIXME should not take the lock until after formatting is done
624 Mutex::Autolock _l(mLock);
625 Writer::logvf(fmt, ap);
626}
627
628void NBLog::LockedWriter::logTimestamp()
629{
630 // FIXME should not take the lock until after the clock_gettime() syscall
631 Mutex::Autolock _l(mLock);
632 Writer::logTimestamp();
633}
634
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700635void NBLog::LockedWriter::logTimestamp(const int64_t ts)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800636{
637 Mutex::Autolock _l(mLock);
638 Writer::logTimestamp(ts);
639}
640
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800641void NBLog::LockedWriter::logInteger(const int x)
642{
643 Mutex::Autolock _l(mLock);
644 Writer::logInteger(x);
645}
646
647void NBLog::LockedWriter::logFloat(const float x)
648{
649 Mutex::Autolock _l(mLock);
650 Writer::logFloat(x);
651}
652
653void NBLog::LockedWriter::logPID()
654{
655 Mutex::Autolock _l(mLock);
656 Writer::logPID();
657}
658
659void NBLog::LockedWriter::logStart(const char *fmt)
660{
661 Mutex::Autolock _l(mLock);
662 Writer::logStart(fmt);
663}
664
665
666void NBLog::LockedWriter::logEnd()
667{
668 Mutex::Autolock _l(mLock);
669 Writer::logEnd();
670}
671
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -0700672void NBLog::LockedWriter::logHash(log_hash_t hash)
673{
674 Mutex::Autolock _l(mLock);
675 Writer::logHash(hash);
676}
677
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800678bool NBLog::LockedWriter::isEnabled() const
679{
680 Mutex::Autolock _l(mLock);
681 return Writer::isEnabled();
682}
683
684bool NBLog::LockedWriter::setEnabled(bool enabled)
685{
686 Mutex::Autolock _l(mLock);
687 return Writer::setEnabled(enabled);
688}
689
690// ---------------------------------------------------------------------------
691
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700692const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
693 NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS};
694const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT,
695 NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
696 NBLog::Event::EVENT_HISTOGRAM_FLUSH};
Glenn Kasten535e1612016-12-05 12:19:36 -0800697NBLog::Reader::Reader(const void *shared, size_t size)
698 : mShared((/*const*/ Shared *) shared), /*mIMemory*/
699 mFd(-1), mIndent(0),
700 mFifo(mShared != NULL ?
701 new audio_utils_fifo(size, sizeof(uint8_t),
702 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
703 mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800704{
705}
706
Glenn Kasten535e1612016-12-05 12:19:36 -0800707NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
708 : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800709{
Glenn Kasten535e1612016-12-05 12:19:36 -0800710 mIMemory = iMemory;
711}
712
713NBLog::Reader::~Reader()
714{
715 delete mFifoReader;
716 delete mFifo;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800717}
718
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700719const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
720 const std::set<Event> &types) {
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800721 while (back + Entry::kPreviousLengthOffset >= front) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700722 const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
723 if (prev < front || prev + prev[offsetof(entry, length)] +
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800724 Entry::kOverhead != back) {
725
726 // prev points to an out of limits or inconsistent entry
727 return nullptr;
728 }
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700729 if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800730 return prev;
731 }
732 back = prev;
733 }
734 return nullptr; // no entry found
735}
736
Nicolas Roulet40a44982017-02-03 13:39:57 -0800737std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800738{
Glenn Kasten535e1612016-12-05 12:19:36 -0800739 if (mFifoReader == NULL) {
Nicolas Roulet40a44982017-02-03 13:39:57 -0800740 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800741 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800742 // make a copy to avoid race condition with writer
Glenn Kasten535e1612016-12-05 12:19:36 -0800743 size_t capacity = mFifo->capacity();
744
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800745 // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
746 // reader index. The index is incremented after handling corruption, to after the last complete
747 // entry of the buffer
748 size_t lost;
749 audio_utils_iovec iovec[2];
750 ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
751 if (availToRead <= 0) {
752 return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
753 }
Glenn Kasten535e1612016-12-05 12:19:36 -0800754
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800755 std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
756 memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
757 if (iovec[1].mLength > 0) {
758 memcpy(snapshot->mData + (iovec[0].mLength),
759 (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
760 }
761
762 // Handle corrupted buffer
763 // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
764 // (due to incomplete format entry). But even if the end format entry is incomplete,
765 // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
766 // TODO: handle client corruption (in the middle of a buffer)
767
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700768 const uint8_t *back = snapshot->mData + availToRead;
769 const uint8_t *front = snapshot->mData;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800770
771 // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
772 // We go backwards until we find an EVENT_END_FMT.
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700773 const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800774 if (lastEnd == nullptr) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700775 snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800776 } else {
777 // end of snapshot points to after last END_FMT entry
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700778 snapshot->mEnd = EntryIterator(lastEnd).next();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800779 // find first START_FMT
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700780 const uint8_t *firstStart = nullptr;
781 const uint8_t *firstStartTmp = snapshot->mEnd;
782 while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800783 != nullptr) {
784 firstStart = firstStartTmp;
785 }
786 // firstStart is null if no START_FMT entry was found before lastEnd
787 if (firstStart == nullptr) {
788 snapshot->mBegin = snapshot->mEnd;
789 } else {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700790 snapshot->mBegin = EntryIterator(firstStart);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800791 }
792 }
793
794 // advance fifo reader index to after last entry read.
795 mFifoReader->release(snapshot->mEnd - front);
796
797 snapshot->mLost = lost;
Nicolas Roulet40a44982017-02-03 13:39:57 -0800798 return snapshot;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800799
Nicolas Roulet40a44982017-02-03 13:39:57 -0800800}
801
Nicolas Rouletf42f1562017-03-30 19:16:22 -0700802inline static int deltaMs(int64_t t1, int64_t t2) {
803 return (t2 - t1) / (1000 * 1000);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700804}
805
Nicolas Roulet40a44982017-02-03 13:39:57 -0800806void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
807{
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800808#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800809 struct timespec ts;
810 time_t maxSec = -1;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800811 while (entry - start >= (int) Entry::kOverhead) {
812 if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800813 break;
814 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800815 if (prevEntry->type == EVENT_TIMESTAMP) {
816 if (prevEntry->length != sizeof(struct timespec)) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800817 // corrupt
818 break;
819 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800820 prevEntry.copyData((uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800821 if (ts.tv_sec > maxSec) {
822 maxSec = ts.tv_sec;
823 }
824 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800825 --entry;
826 --prevEntry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800827 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800828#endif
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700829 mFd = fd;
830 mIndent = indent;
831 String8 timestamp, body;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700832 size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
Glenn Kastenc02c9612013-10-15 09:25:11 -0700833 if (lost > 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700834 body.appendFormat("warning: lost %zu bytes worth of events", lost);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700835 // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
836 // log to push it out. Consider keeping the timestamp/body between calls to readAt().
837 dumpLine(timestamp, body);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800838 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800839#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800840 size_t width = 1;
841 while (maxSec >= 10) {
842 ++width;
843 maxSec /= 10;
844 }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800845 if (maxSec >= 0) {
Glenn Kasten95d287d2014-04-28 14:11:45 -0700846 timestamp.appendFormat("[%*s]", (int) width + 4, "");
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800847 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700848 bool deferredTimestamp = false;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800849#endif
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700850
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800851 for (auto entry = snapshot.begin(); entry != snapshot.end();) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800852 switch (entry->type) {
853#if 0
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800854 case EVENT_STRING:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800855 body.appendFormat("%.*s", (int) entry.length(), entry.data());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700856 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800857 case EVENT_TIMESTAMP: {
858 // already checked that length == sizeof(struct timespec);
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800859 entry.copyData((const uint8_t*) &ts);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800860 long prevNsec = ts.tv_nsec;
861 long deltaMin = LONG_MAX;
862 long deltaMax = -1;
863 long deltaTotal = 0;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800864 auto aux(entry);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800865 for (;;) {
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800866 ++aux;
867 if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800868 break;
869 }
870 struct timespec tsNext;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800871 aux.copyData((const uint8_t*) &tsNext);
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800872 if (tsNext.tv_sec != ts.tv_sec) {
873 break;
874 }
875 long delta = tsNext.tv_nsec - prevNsec;
876 if (delta < 0) {
877 break;
878 }
879 if (delta < deltaMin) {
880 deltaMin = delta;
881 }
882 if (delta > deltaMax) {
883 deltaMax = delta;
884 }
885 deltaTotal += delta;
886 prevNsec = tsNext.tv_nsec;
887 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800888 size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700889 if (deferredTimestamp) {
890 dumpLine(timestamp, body);
891 deferredTimestamp = false;
892 }
893 timestamp.clear();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800894 if (n >= kSquashTimestamp) {
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700895 timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
896 (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
897 (int) ((ts.tv_nsec + deltaTotal) / 1000000),
898 (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800899 entry = aux;
900 // advance = 0;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800901 break;
902 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700903 timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
904 (int) (ts.tv_nsec / 1000000));
905 deferredTimestamp = true;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800906 }
907 break;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800908 case EVENT_INTEGER:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800909 appendInt(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800910 break;
911 case EVENT_FLOAT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800912 appendFloat(&body, entry.data());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800913 break;
914 case EVENT_PID:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800915 appendPID(&body, entry.data(), entry.length());
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800916 break;
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800917#endif
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800918 case EVENT_START_FMT:
Nicolas Rouletcd5dd012017-02-13 12:09:28 -0800919 // right now, this is the only supported case
920 entry = handleFormat(FormatEntry(entry), &timestamp, &body);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800921 break;
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700922 case EVENT_HISTOGRAM_ENTRY_TS: {
923 HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
924 // TODO This memcpies are here to avoid unaligned memory access crash.
925 // There's probably a more efficient way to do it
926 log_hash_t hash;
927 memcpy(&hash, &(data->hash), sizeof(hash));
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700928 int64_t ts;
929 memcpy(&ts, &data->ts, sizeof(ts));
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700930 const std::pair<log_hash_t, int> key(hash, data->author);
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700931 // TODO might want to filter excessively high outliers, which are usually caused
932 // by the thread being inactive.
933 mHists[key].push_back(ts);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700934 ++entry;
935 break;
936 }
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700937 case EVENT_HISTOGRAM_FLUSH: {
938 HistogramEntry histEntry(entry);
939 // Log timestamp
940 int64_t ts = histEntry.timestamp();
941 timestamp.clear();
942 timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
943 (int) ((ts / (1000 * 1000)) % 1000));
944 // Log histograms
945 body.appendFormat("Histogram flush - ");
946 handleAuthor(histEntry, &body);
947 body.appendFormat("\n");
948 for (auto hist = mHists.begin(); hist != mHists.end();) {
949 if (hist->first.second == histEntry.author()) {
950 body.appendFormat("Histogram %X", (int)hist->first.first);
951 drawHistogram(&body, hist->second, indent + timestamp.size());
952 hist = mHists.erase(hist);
953 } else {
954 ++hist;
955 }
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700956 }
Nicolas Roulet537ad7d2017-03-21 16:24:30 -0700957 ++entry;
958 break;
Nicolas Rouletad82aa62017-04-03 19:15:20 -0700959 }
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800960 case EVENT_END_FMT:
961 body.appendFormat("warning: got to end format event");
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800962 ++entry;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800963 break;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800964 case EVENT_RESERVED:
965 default:
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800966 body.appendFormat("warning: unexpected event %d", entry->type);
967 ++entry;
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800968 break;
969 }
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700970
971 if (!body.isEmpty()) {
972 dumpLine(timestamp, body);
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800973 // deferredTimestamp = false;
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700974 }
975 }
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -0800976 // if (deferredTimestamp) {
977 // dumpLine(timestamp, body);
978 // }
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800979}
980
Nicolas Roulet40a44982017-02-03 13:39:57 -0800981void NBLog::Reader::dump(int fd, size_t indent)
982{
983 // get a snapshot, dump it
984 std::unique_ptr<Snapshot> snap = getSnapshot();
985 dump(fd, indent, *snap);
986}
987
Nicolas Rouletfe1e1442017-01-30 12:02:03 -0800988void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700989{
990 if (mFd >= 0) {
Elliott Hughes8b5f6422014-05-22 01:22:06 -0700991 dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
Glenn Kasten4e01ef62013-07-11 14:29:59 -0700992 } else {
993 ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
994 }
995 body.clear();
996}
997
Glenn Kasten11d8dfc2013-01-14 14:53:13 -0800998bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
999{
Glenn Kasten481fb672013-09-30 14:39:28 -07001000 return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001001}
1002
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001003void NBLog::appendTimestamp(String8 *body, const void *data) {
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001004 int64_t ts;
1005 memcpy(&ts, data, sizeof(ts));
1006 body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
1007 (int) ((ts / (1000 * 1000)) % 1000));
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001008}
1009
1010void NBLog::appendInt(String8 *body, const void *data) {
1011 int x = *((int*) data);
1012 body->appendFormat("<%d>", x);
1013}
1014
1015void NBLog::appendFloat(String8 *body, const void *data) {
1016 float f;
1017 memcpy(&f, data, sizeof(float));
1018 body->appendFormat("<%f>", f);
1019}
1020
Nicolas Rouletc20cb502017-02-01 12:35:24 -08001021void NBLog::appendPID(String8 *body, const void* data, size_t length) {
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001022 pid_t id = *((pid_t*) data);
Nicolas Rouletc20cb502017-02-01 12:35:24 -08001023 char * name = &((char*) data)[sizeof(pid_t)];
1024 body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001025}
1026
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001027String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
Nicolas Roulet2aedf372017-03-29 11:27:03 -07001028{
1029 String8 str;
1030 str.append("[ ");
1031 for(size_t i = 0; i < size; i++)
1032 {
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001033 str.appendFormat("%d ", buffer[i]);
Nicolas Roulet2aedf372017-03-29 11:27:03 -07001034 }
1035 str.append("]");
1036 return str;
1037}
1038
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001039String8 NBLog::bufferDump(const EntryIterator &it)
Nicolas Roulet2aedf372017-03-29 11:27:03 -07001040{
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001041 return bufferDump(it, it->length + Entry::kOverhead);
Nicolas Roulet2aedf372017-03-29 11:27:03 -07001042}
1043
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001044NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001045 String8 *timestamp,
1046 String8 *body) {
Nicolas Roulet40a44982017-02-03 13:39:57 -08001047 // log timestamp
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001048 int64_t ts = fmtEntry.timestamp();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001049 timestamp->clear();
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001050 timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
1051 (int) ((ts / (1000 * 1000)) % 1000));
Nicolas Roulet40a44982017-02-03 13:39:57 -08001052
Nicolas Rouletbd0c6b42017-03-16 13:54:23 -07001053 // log unique hash
1054 log_hash_t hash = fmtEntry.hash();
1055 // print only lower 16bit of hash as hex and line as int to reduce spam in the log
1056 body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
1057
Nicolas Roulet40a44982017-02-03 13:39:57 -08001058 // log author (if present)
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001059 handleAuthor(fmtEntry, body);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001060
1061 // log string
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001062 NBLog::EntryIterator arg = fmtEntry.args();
Nicolas Roulet40a44982017-02-03 13:39:57 -08001063
1064 const char* fmt = fmtEntry.formatString();
1065 size_t fmt_length = fmtEntry.formatStringLength();
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001066
1067 for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
1068 if (fmt[fmt_offset] != '%') {
1069 body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
1070 continue;
1071 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001072 // case "%%""
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001073 if (fmt[++fmt_offset] == '%') {
1074 body->append("%");
1075 continue;
1076 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001077 // case "%\0"
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001078 if (fmt_offset == fmt_length) {
1079 continue;
1080 }
1081
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001082 NBLog::Event event = (NBLog::Event) arg->type;
1083 size_t length = arg->length;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001084
1085 // TODO check length for event type is correct
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001086
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001087 if (event == EVENT_END_FMT) {
1088 break;
1089 }
1090
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001091 // TODO: implement more complex formatting such as %.3f
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001092 const uint8_t *datum = arg->data; // pointer to the current event args
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001093 switch(fmt[fmt_offset])
1094 {
1095 case 's': // string
Nicolas Roulet4da78202017-02-03 12:53:39 -08001096 ALOGW_IF(event != EVENT_STRING,
1097 "NBLog Reader incompatible event for string specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001098 body->append((const char*) datum, length);
1099 break;
1100
1101 case 't': // timestamp
Nicolas Roulet4da78202017-02-03 12:53:39 -08001102 ALOGW_IF(event != EVENT_TIMESTAMP,
1103 "NBLog Reader incompatible event for timestamp specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001104 appendTimestamp(body, datum);
1105 break;
1106
1107 case 'd': // integer
Nicolas Roulet4da78202017-02-03 12:53:39 -08001108 ALOGW_IF(event != EVENT_INTEGER,
1109 "NBLog Reader incompatible event for integer specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001110 appendInt(body, datum);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001111 break;
1112
1113 case 'f': // float
Nicolas Roulet4da78202017-02-03 12:53:39 -08001114 ALOGW_IF(event != EVENT_FLOAT,
1115 "NBLog Reader incompatible event for float specifier: %d", event);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001116 appendFloat(body, datum);
1117 break;
1118
1119 case 'p': // pid
Nicolas Roulet4da78202017-02-03 12:53:39 -08001120 ALOGW_IF(event != EVENT_PID,
1121 "NBLog Reader incompatible event for pid specifier: %d", event);
Nicolas Rouletc20cb502017-02-01 12:35:24 -08001122 appendPID(body, datum, length);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001123 break;
1124
1125 default:
1126 ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
1127 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001128 ++arg;
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001129 }
Nicolas Rouletcd5dd012017-02-13 12:09:28 -08001130 ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
1131 ++arg;
1132 return arg;
Nicolas Roulet40a44982017-02-03 13:39:57 -08001133}
1134
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001135static int widthOf(int x) {
1136 int width = 0;
1137 while (x > 0) {
1138 ++width;
1139 x /= 10;
1140 }
1141 return width;
1142}
1143
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001144static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001145 // TODO allow buckets of variable resolution
1146 std::map<int, int> buckets;
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001147 for (size_t i = 1; i < samples.size(); ++i) {
1148 ++buckets[deltaMs(samples[i - 1], samples[i])];
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001149 }
1150 return buckets;
1151}
1152
1153// TODO put this function in separate file. Make it return a std::string instead of modifying body
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001154void NBLog::Reader::drawHistogram(String8 *body,
1155 const std::vector<int64_t> &samples,
1156 int indent,
1157 int maxHeight) {
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001158 std::map<int, int> buckets = buildBuckets(samples);
1159 // TODO add option for log scale
1160 static const char *underscores = "________________";
1161 static const char *spaces = " ";
1162
1163 auto it = buckets.begin();
1164 int maxLabel = it->first;
1165 int maxVal = it->second;
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001166 // Compute maximum values
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001167 while (++it != buckets.end()) {
1168 if (it->first > maxLabel) {
1169 maxLabel = it->first;
1170 }
1171 if (it->second > maxVal) {
1172 maxVal = it->second;
1173 }
1174 }
1175 int height = maxVal;
1176 int leftPadding = widthOf(maxVal);
1177 int colWidth = std::max(std::max(widthOf(maxLabel) + 1, 3), leftPadding + 2);
1178 int scalingFactor = 1;
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001179 // scale data if it exceeds maximum height
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001180 if (height > maxHeight) {
1181 scalingFactor = (height + maxHeight) / maxHeight;
1182 height /= scalingFactor;
1183 }
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001184 // write header line with bucket values
1185 body->appendFormat("\n%*s", indent, " ");
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001186 body->appendFormat("%*s", leftPadding + 2, " ");
1187 for (auto const &x : buckets)
1188 {
1189 body->appendFormat("[%*d]", colWidth - 2, x.second);
1190 }
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001191 // write histogram ascii art
1192 body->appendFormat("\n%*s", indent, " ");
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001193 for (int row = height * scalingFactor; row > 0; row -= scalingFactor)
1194 {
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001195 body->appendFormat("%*u|", leftPadding, row);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001196 for (auto const &x : buckets) {
1197 body->appendFormat("%.*s%s", colWidth - 2,
1198 (row == scalingFactor) ? underscores : spaces,
1199 x.second < row ? ((row == scalingFactor) ? "__" : " ") : "[]");
1200 }
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001201 body->appendFormat("\n%*s", indent, " ");
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001202 }
Nicolas Rouletad82aa62017-04-03 19:15:20 -07001203 // write footer with bucket labels
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001204 body->appendFormat("%*s", leftPadding + 1, " ");
1205 for (auto const &x : buckets)
1206 {
1207 body->appendFormat("%*d", colWidth, x.first);
1208 }
1209 body->appendFormat("\n");
1210}
1211
Nicolas Roulet40a44982017-02-03 13:39:57 -08001212// ---------------------------------------------------------------------------
1213
1214NBLog::Merger::Merger(const void *shared, size_t size):
1215 mBuffer(NULL),
1216 mShared((Shared *) shared),
1217 mFifo(mShared != NULL ?
1218 new audio_utils_fifo(size, sizeof(uint8_t),
1219 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
1220 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
1221 {}
1222
1223void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
1224 mNamedReaders.push_back(reader);
1225}
1226
1227// items placed in priority queue during merge
1228// composed by a timestamp and the index of the snapshot where the timestamp came from
1229struct MergeItem
1230{
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001231 int64_t ts;
Nicolas Roulet40a44982017-02-03 13:39:57 -08001232 int index;
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001233 MergeItem(int64_t ts, int index): ts(ts), index(index) {}
Nicolas Roulet40a44982017-02-03 13:39:57 -08001234};
1235
1236// operators needed for priority queue in merge
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001237// bool operator>(const int64_t &t1, const int64_t &t2) {
1238// return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
1239// }
Nicolas Roulet40a44982017-02-03 13:39:57 -08001240
1241bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001242 return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001243}
1244
1245// Merge registered readers, sorted by timestamp
1246void NBLog::Merger::merge() {
1247 int nLogs = mNamedReaders.size();
1248 std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001249 std::vector<NBLog::EntryIterator> offsets(nLogs);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001250 for (int i = 0; i < nLogs; ++i) {
1251 snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001252 offsets[i] = snapshots[i]->begin();
Nicolas Roulet40a44982017-02-03 13:39:57 -08001253 }
1254 // initialize offsets
Nicolas Roulet40a44982017-02-03 13:39:57 -08001255 // TODO custom heap implementation could allow to update top, improving performance
1256 // for bursty buffers
1257 std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
1258 for (int i = 0; i < nLogs; ++i)
1259 {
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001260 if (offsets[i] != snapshots[i]->end()) {
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001261 int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001262 timestamps.emplace(ts, i);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001263 }
1264 }
1265
1266 while (!timestamps.empty()) {
1267 // find minimum timestamp
1268 int index = timestamps.top().index;
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001269 // copy it to the log, increasing offset
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001270 offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
1271 index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001272 // update data structures
Nicolas Roulet40a44982017-02-03 13:39:57 -08001273 timestamps.pop();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001274 if (offsets[index] != snapshots[index]->end()) {
Nicolas Rouletf42f1562017-03-30 19:16:22 -07001275 int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
Nicolas Roulet6ea1d7e2017-02-14 16:17:31 -08001276 timestamps.emplace(ts, index);
Nicolas Roulet40a44982017-02-03 13:39:57 -08001277 }
1278 }
1279}
1280
1281const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
1282 return &mNamedReaders;
1283}
1284
1285NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
1286 : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
1287
Nicolas Roulet537ad7d2017-03-21 16:24:30 -07001288void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
1289 int author = entry.author();
Nicolas Roulet40a44982017-02-03 13:39:57 -08001290 const char* name = (*mNamedReaders)[author].name();
1291 body->appendFormat("%s: ", name);
Nicolas Rouletfe1e1442017-01-30 12:02:03 -08001292}
1293
Nicolas Rouletdcdfaec2017-02-14 10:18:39 -08001294NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
1295 : mMerger(merger),
1296 mTimeoutUs(0) {}
1297
1298NBLog::MergeThread::~MergeThread() {
1299 // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
1300 requestExit();
1301 setTimeoutUs(0);
1302 join();
1303}
1304
1305bool NBLog::MergeThread::threadLoop() {
1306 bool doMerge;
1307 {
1308 AutoMutex _l(mMutex);
1309 // If mTimeoutUs is negative, wait on the condition variable until it's positive.
1310 // If it's positive, wait kThreadSleepPeriodUs and then merge
1311 nsecs_t waitTime = mTimeoutUs > 0 ? kThreadSleepPeriodUs * 1000 : LLONG_MAX;
1312 mCond.waitRelative(mMutex, waitTime);
1313 doMerge = mTimeoutUs > 0;
1314 mTimeoutUs -= kThreadSleepPeriodUs;
1315 }
1316 if (doMerge) {
1317 mMerger.merge();
1318 }
1319 return true;
1320}
1321
1322void NBLog::MergeThread::wakeup() {
1323 setTimeoutUs(kThreadWakeupPeriodUs);
1324}
1325
1326void NBLog::MergeThread::setTimeoutUs(int time) {
1327 AutoMutex _l(mMutex);
1328 mTimeoutUs = time;
1329 mCond.signal();
1330}
1331
Glenn Kasten11d8dfc2013-01-14 14:53:13 -08001332} // namespace android