blob: 86d3b9830fe2586305b94726a28c838faf06b674 [file] [log] [blame]
Eric Tanace588c2018-09-12 11:44:43 -07001/*
2 * Copyright (C) 2018 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 <stddef.h>
22#include <sys/prctl.h>
23
24#include <audio_utils/fifo.h>
25#include <binder/IMemory.h>
26#include <media/nblog/Entry.h>
27#include <media/nblog/Events.h>
28#include <media/nblog/Timeline.h>
29#include <media/nblog/Writer.h>
30#include <utils/Log.h>
31#include <utils/Mutex.h>
32
33namespace android {
34namespace NBLog {
35
36Writer::Writer(void *shared, size_t size)
37 : mShared((Shared *) shared),
38 mFifo(mShared != NULL ?
39 new audio_utils_fifo(size, sizeof(uint8_t),
40 mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
41 mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
42 mEnabled(mFifoWriter != NULL)
43{
44 // caching pid and process name
45 pid_t id = ::getpid();
46 char procName[16];
47 int status = prctl(PR_GET_NAME, procName);
48 if (status) { // error getting process name
49 procName[0] = '\0';
50 }
51 size_t length = strlen(procName);
52 mPidTagSize = length + sizeof(pid_t);
53 mPidTag = new char[mPidTagSize];
54 memcpy(mPidTag, &id, sizeof(pid_t));
55 memcpy(mPidTag + sizeof(pid_t), procName, length);
56}
57
58Writer::Writer(const sp<IMemory>& iMemory, size_t size)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -070059 // TODO: Using unsecurePointer() has some associated security pitfalls
60 // (see declaration for details).
61 // Either document why it is safe in this case or address the
62 // issue (e.g. by copying).
63 : Writer(iMemory != 0 ? (Shared *) iMemory->unsecurePointer() : NULL, size)
Eric Tanace588c2018-09-12 11:44:43 -070064{
65 mIMemory = iMemory;
66}
67
68Writer::~Writer()
69{
70 delete mFifoWriter;
71 delete mFifo;
72 delete[] mPidTag;
73}
74
75void Writer::log(const char *string)
76{
77 if (!mEnabled) {
78 return;
79 }
80 LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
81 size_t length = strlen(string);
82 if (length > Entry::kMaxLength) {
83 length = Entry::kMaxLength;
84 }
85 log(EVENT_STRING, string, length);
86}
87
88void Writer::logf(const char *fmt, ...)
89{
90 if (!mEnabled) {
91 return;
92 }
93 va_list ap;
94 va_start(ap, fmt);
95 Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
96 va_end(ap);
97}
98
99void Writer::logTimestamp()
100{
101 if (!mEnabled) {
102 return;
103 }
104 struct timespec ts;
105 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
106 log(EVENT_TIMESTAMP, &ts, sizeof(ts));
107 }
108}
109
110void Writer::logFormat(const char *fmt, log_hash_t hash, ...)
111{
112 if (!mEnabled) {
113 return;
114 }
115 va_list ap;
116 va_start(ap, hash);
117 Writer::logVFormat(fmt, hash, ap);
118 va_end(ap);
119}
120
121void Writer::logEventHistTs(Event event, log_hash_t hash)
122{
123 if (!mEnabled) {
124 return;
125 }
126 HistTsEntry data;
127 data.hash = hash;
128 data.ts = systemTime();
129 if (data.ts > 0) {
130 log(event, &data, sizeof(data));
131 } else {
132 ALOGE("Failed to get timestamp");
133 }
134}
135
136bool Writer::isEnabled() const
137{
138 return mEnabled;
139}
140
141bool Writer::setEnabled(bool enabled)
142{
143 bool old = mEnabled;
144 mEnabled = enabled && mShared != NULL;
145 return old;
146}
147
148void Writer::log(const Entry &etr, bool trusted)
149{
150 if (!mEnabled) {
151 return;
152 }
153 if (!trusted) {
154 log(etr.mEvent, etr.mData, etr.mLength);
155 return;
156 }
157 const size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
158 // need = number of bytes written to FIFO
159
160 // FIXME optimize this using memcpy for the data part of the Entry.
161 // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
162 // checks size of a single log Entry: type, length, data pointer and ending
163 uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
164 // write this data to temp array
165 for (size_t i = 0; i < need; i++) {
166 temp[i] = etr.copyEntryDataAt(i);
167 }
168 // write to circular buffer
169 mFifoWriter->write(temp, need);
170}
171
172void Writer::log(Event event, const void *data, size_t length)
173{
174 if (!mEnabled) {
175 return;
176 }
177 if (data == NULL || length > Entry::kMaxLength) {
178 // TODO Perhaps it makes sense to display truncated data or at least a
179 // message that the data is too long? The current behavior can create
180 // a confusion for a programmer debugging their code.
181 return;
182 }
183 // Ignore if invalid event
184 if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
185 return;
186 }
187 Entry etr(event, data, length);
188 log(etr, true /*trusted*/);
189}
190
191void Writer::logvf(const char *fmt, va_list ap)
192{
193 if (!mEnabled) {
194 return;
195 }
196 char buffer[Entry::kMaxLength + 1 /*NUL*/];
197 int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
198 if (length >= (int) sizeof(buffer)) {
199 length = sizeof(buffer) - 1;
200 // NUL termination is not required
201 // buffer[length] = '\0';
202 }
203 if (length >= 0) {
204 log(EVENT_STRING, buffer, length);
205 }
206}
207
208void Writer::logStart(const char *fmt)
209{
210 if (!mEnabled) {
211 return;
212 }
213 size_t length = strlen(fmt);
214 if (length > Entry::kMaxLength) {
215 length = Entry::kMaxLength;
216 }
217 log(EVENT_FMT_START, fmt, length);
218}
219
220void Writer::logTimestampFormat()
221{
222 if (!mEnabled) {
223 return;
224 }
225 const nsecs_t ts = systemTime();
226 if (ts > 0) {
227 log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
228 } else {
229 ALOGE("Failed to get timestamp");
230 }
231}
232
233void Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
234{
235 if (!mEnabled) {
236 return;
237 }
238 Writer::logStart(fmt);
239 int i;
240 double d;
241 float f;
242 char* s;
243 size_t length;
244 int64_t t;
245 Writer::logTimestampFormat();
246 log(EVENT_FMT_HASH, &hash, sizeof(hash));
247 for (const char *p = fmt; *p != '\0'; p++) {
248 // TODO: implement more complex formatting such as %.3f
249 if (*p != '%') {
250 continue;
251 }
252 switch(*++p) {
253 case 's': // string
254 s = va_arg(argp, char *);
255 length = strlen(s);
256 if (length > Entry::kMaxLength) {
257 length = Entry::kMaxLength;
258 }
259 log(EVENT_FMT_STRING, s, length);
260 break;
261
262 case 't': // timestamp
263 t = va_arg(argp, int64_t);
264 log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
265 break;
266
267 case 'd': // integer
268 i = va_arg(argp, int);
269 log(EVENT_FMT_INTEGER, &i, sizeof(i));
270 break;
271
272 case 'f': // float
273 d = va_arg(argp, double); // float arguments are promoted to double in vararg lists
274 f = (float)d;
275 log(EVENT_FMT_FLOAT, &f, sizeof(f));
276 break;
277
278 case 'p': // pid
279 log(EVENT_FMT_PID, mPidTag, mPidTagSize);
280 break;
281
282 // the "%\0" case finishes parsing
283 case '\0':
284 --p;
285 break;
286
287 case '%':
288 break;
289
290 default:
291 ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
292 break;
293 }
294 }
295 Entry etr(EVENT_FMT_END, nullptr, 0);
296 log(etr, true);
297}
298
299// ---------------------------------------------------------------------------
300
301LockedWriter::LockedWriter(void *shared, size_t size)
302 : Writer(shared, size)
303{
304}
305
306bool LockedWriter::isEnabled() const
307{
308 Mutex::Autolock _l(mLock);
309 return Writer::isEnabled();
310}
311
312bool LockedWriter::setEnabled(bool enabled)
313{
314 Mutex::Autolock _l(mLock);
315 return Writer::setEnabled(enabled);
316}
317
318void LockedWriter::log(const Entry &entry, bool trusted) {
319 Mutex::Autolock _l(mLock);
320 Writer::log(entry, trusted);
321}
322
323} // namespace NBLog
324} // namespace android