1 /*
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 
33 namespace android {
34 namespace NBLog {
35 
Writer(void * shared,size_t size)36 Writer::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 
Writer(const sp<IMemory> & iMemory,size_t size)58 Writer::Writer(const sp<IMemory>& iMemory, size_t size)
59     // 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)
64 {
65     mIMemory = iMemory;
66 }
67 
~Writer()68 Writer::~Writer()
69 {
70     delete mFifoWriter;
71     delete mFifo;
72     delete[] mPidTag;
73 }
74 
log(const char * string)75 void 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 
logf(const char * fmt,...)88 void 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 
logTimestamp()99 void 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 
logFormat(const char * fmt,log_hash_t hash,...)110 void 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 
logEventHistTs(Event event,log_hash_t hash)121 void 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 
isEnabled() const136 bool Writer::isEnabled() const
137 {
138     return mEnabled;
139 }
140 
setEnabled(bool enabled)141 bool Writer::setEnabled(bool enabled)
142 {
143     bool old = mEnabled;
144     mEnabled = enabled && mShared != NULL;
145     return old;
146 }
147 
log(const Entry & etr,bool trusted)148 void 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 
log(Event event,const void * data,size_t length)172 void 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 
logvf(const char * fmt,va_list ap)191 void 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 
logStart(const char * fmt)208 void 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 
logTimestampFormat()220 void 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 
logVFormat(const char * fmt,log_hash_t hash,va_list argp)233 void 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 
LockedWriter(void * shared,size_t size)301 LockedWriter::LockedWriter(void *shared, size_t size)
302     : Writer(shared, size)
303 {
304 }
305 
isEnabled() const306 bool LockedWriter::isEnabled() const
307 {
308     Mutex::Autolock _l(mLock);
309     return Writer::isEnabled();
310 }
311 
setEnabled(bool enabled)312 bool LockedWriter::setEnabled(bool enabled)
313 {
314     Mutex::Autolock _l(mLock);
315     return Writer::setEnabled(enabled);
316 }
317 
log(const Entry & entry,bool trusted)318 void 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
325