blob: aa44264088bf0d61e3853ebd4a6c2657e4ede70c [file] [log] [blame]
Mark Salyzyn0175b072014-02-26 09:50:16 -08001/*
2 * Copyright (C) 2012-2014 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#include <stdio.h>
18#include <string.h>
19#include <time.h>
20#include <unistd.h>
21
22#include <log/logger.h>
23
24#include "LogBuffer.h"
Mark Salyzyn34facab2014-02-06 14:48:50 -080025#include "LogStatistics.h"
Mark Salyzyndfa7a072014-02-11 12:29:31 -080026#include "LogWhiteBlackList.h"
Mark Salyzyn0175b072014-02-26 09:50:16 -080027#include "LogReader.h"
28
Mark Salyzyndfa7a072014-02-11 12:29:31 -080029// Default
Mark Salyzyn0175b072014-02-26 09:50:16 -080030#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
Mark Salyzyndfa7a072014-02-11 12:29:31 -080031#ifdef USERDEBUG_BUILD
32#define log_buffer_size(id) mMaxSize[id]
33#else
34#define log_buffer_size(id) LOG_BUFFER_SIZE
35#endif
Mark Salyzyn0175b072014-02-26 09:50:16 -080036
37LogBuffer::LogBuffer(LastLogTimes *times)
38 : mTimes(*times) {
Mark Salyzyn0175b072014-02-26 09:50:16 -080039 pthread_mutex_init(&mLogElementsLock, NULL);
Mark Salyzyne457b742014-02-19 17:18:31 -080040 dgram_qlen_statistics = false;
41
Mark Salyzyndfa7a072014-02-11 12:29:31 -080042 log_id_for_each(i) {
43 mMaxSize[i] = LOG_BUFFER_SIZE;
44 }
Mark Salyzyn0175b072014-02-26 09:50:16 -080045}
46
Mark Salyzyn7e2f83c2014-03-05 07:41:49 -080047void LogBuffer::log(log_id_t log_id, log_time realtime,
Mark Salyzynb992d0d2014-03-20 16:09:38 -070048 uid_t uid, pid_t pid, pid_t tid,
49 const char *msg, unsigned short len) {
Mark Salyzyn0175b072014-02-26 09:50:16 -080050 if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
51 return;
52 }
53 LogBufferElement *elem = new LogBufferElement(log_id, realtime,
Mark Salyzynb992d0d2014-03-20 16:09:38 -070054 uid, pid, tid, msg, len);
Mark Salyzyn0175b072014-02-26 09:50:16 -080055
56 pthread_mutex_lock(&mLogElementsLock);
57
58 // Insert elements in time sorted order if possible
59 // NB: if end is region locked, place element at end of list
60 LogBufferElementCollection::iterator it = mLogElements.end();
61 LogBufferElementCollection::iterator last = it;
62 while (--it != mLogElements.begin()) {
Mark Salyzync03e72c2014-02-18 11:23:53 -080063 if ((*it)->getRealTime() <= realtime) {
Mark Salyzyne457b742014-02-19 17:18:31 -080064 // halves the peak performance, use with caution
65 if (dgram_qlen_statistics) {
66 LogBufferElementCollection::iterator ib = it;
67 unsigned short buckets, num = 1;
68 for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) {
69 buckets -= num;
70 num += buckets;
71 while (buckets && (--ib != mLogElements.begin())) {
72 --buckets;
73 }
74 if (buckets) {
75 break;
76 }
77 stats.recordDiff(
78 elem->getRealTime() - (*ib)->getRealTime(), i);
79 }
80 }
Mark Salyzyn0175b072014-02-26 09:50:16 -080081 break;
82 }
83 last = it;
84 }
Mark Salyzync03e72c2014-02-18 11:23:53 -080085
Mark Salyzyn0175b072014-02-26 09:50:16 -080086 if (last == mLogElements.end()) {
87 mLogElements.push_back(elem);
88 } else {
89 log_time end;
90 bool end_set = false;
91 bool end_always = false;
92
93 LogTimeEntry::lock();
94
95 LastLogTimes::iterator t = mTimes.begin();
96 while(t != mTimes.end()) {
97 LogTimeEntry *entry = (*t);
98 if (entry->owned_Locked()) {
99 if (!entry->mNonBlock) {
100 end_always = true;
101 break;
102 }
103 if (!end_set || (end <= entry->mEnd)) {
104 end = entry->mEnd;
105 end_set = true;
106 }
107 }
108 t++;
109 }
110
111 if (end_always
Mark Salyzync03e72c2014-02-18 11:23:53 -0800112 || (end_set && (end >= (*last)->getMonotonicTime()))) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800113 mLogElements.push_back(elem);
114 } else {
115 mLogElements.insert(last,elem);
116 }
117
118 LogTimeEntry::unlock();
119 }
120
Mark Salyzyn34facab2014-02-06 14:48:50 -0800121 stats.add(len, log_id, uid, pid);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800122 maybePrune(log_id);
123 pthread_mutex_unlock(&mLogElementsLock);
124}
125
126// If we're using more than 256K of memory for log entries, prune
Mark Salyzyn740f9b42014-01-13 16:37:51 -0800127// at least 10% of the log entries.
Mark Salyzyn0175b072014-02-26 09:50:16 -0800128//
129// mLogElementsLock must be held when this function is called.
130void LogBuffer::maybePrune(log_id_t id) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800131 size_t sizes = stats.sizes(id);
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800132 if (sizes > log_buffer_size(id)) {
133 size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800134 size_t elements = stats.elements(id);
Mark Salyzyn740f9b42014-01-13 16:37:51 -0800135 unsigned long pruneRows = elements * sizeOver90Percent / sizes;
136 elements /= 10;
137 if (pruneRows <= elements) {
138 pruneRows = elements;
139 }
140 prune(id, pruneRows);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800141 }
142}
143
144// prune "pruneRows" of type "id" from the buffer.
145//
146// mLogElementsLock must be held when this function is called.
147void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
148 LogTimeEntry *oldest = NULL;
149
150 LogTimeEntry::lock();
151
152 // Region locked?
153 LastLogTimes::iterator t = mTimes.begin();
154 while(t != mTimes.end()) {
155 LogTimeEntry *entry = (*t);
156 if (entry->owned_Locked()
157 && (!oldest || (oldest->mStart > entry->mStart))) {
158 oldest = entry;
159 }
160 t++;
161 }
162
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800163 LogBufferElementCollection::iterator it;
164
165 // prune by worst offender by uid
166 while (pruneRows > 0) {
167 // recalculate the worst offender on every batched pass
168 uid_t worst = (uid_t) -1;
169 size_t worst_sizes = 0;
170 size_t second_worst_sizes = 0;
171
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800172#ifdef USERDEBUG_BUILD
173 if (mPrune.worstUidEnabled())
174#endif
175 {
176 LidStatistics &l = stats.id(id);
177 UidStatisticsCollection::iterator iu;
178 for (iu = l.begin(); iu != l.end(); ++iu) {
179 UidStatistics *u = (*iu);
180 size_t sizes = u->sizes();
181 if (worst_sizes < sizes) {
182 second_worst_sizes = worst_sizes;
183 worst_sizes = sizes;
184 worst = u->getUid();
185 }
186 if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
187 second_worst_sizes = sizes;
188 }
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800189 }
190 }
191
192 bool kick = false;
193 for(it = mLogElements.begin(); it != mLogElements.end();) {
194 LogBufferElement *e = *it;
195
196 if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
197 break;
198 }
199
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800200 if (e->getLogId() != id) {
201 ++it;
202 continue;
203 }
204
205 uid_t uid = e->getUid();
206
207 if (uid == worst) {
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800208 it = mLogElements.erase(it);
209 unsigned short len = e->getMsgLen();
210 stats.subtract(len, id, worst, e->getPid());
211 delete e;
212 kick = true;
213 pruneRows--;
214 if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
215 break;
216 }
217 worst_sizes -= len;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800218 }
219#ifdef USERDEBUG_BUILD
220 else if (mPrune.naughty(e)) { // BlackListed
221 it = mLogElements.erase(it);
222 stats.subtract(e->getMsgLen(), id, uid, e->getPid());
223 delete e;
224 pruneRows--;
225 if (pruneRows == 0) {
226 break;
227 }
228 }
229#endif
230 else {
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800231 ++it;
232 }
233 }
234
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800235 if (!kick
236#ifdef USERDEBUG_BUILD
237 || !mPrune.worstUidEnabled()
238#endif
239 ) {
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800240 break; // the following loop will ask bad clients to skip/drop
241 }
242 }
243
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800244#ifdef USERDEBUG_BUILD
245 bool whitelist = false;
246#endif
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800247 it = mLogElements.begin();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800248 while((pruneRows > 0) && (it != mLogElements.end())) {
249 LogBufferElement *e = *it;
250 if (e->getLogId() == id) {
251 if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800252#ifdef USERDEBUG_BUILD
253 if (!whitelist)
254#endif
255 {
256 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
257 // kick a misbehaving log reader client off the island
258 oldest->release_Locked();
259 } else {
260 oldest->triggerSkip_Locked(pruneRows);
261 }
Mark Salyzyn0175b072014-02-26 09:50:16 -0800262 }
263 break;
264 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800265#ifdef USERDEBUG_BUILD
266 if (mPrune.nice(e)) { // WhiteListed
267 whitelist = true;
268 it++;
269 continue;
270 }
271#endif
Mark Salyzyn0175b072014-02-26 09:50:16 -0800272 it = mLogElements.erase(it);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800273 stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
Mark Salyzyn0175b072014-02-26 09:50:16 -0800274 delete e;
275 pruneRows--;
276 } else {
277 it++;
278 }
279 }
280
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800281#ifdef USERDEBUG_BUILD
282 if (whitelist && (pruneRows > 0)) {
283 it = mLogElements.begin();
284 while((it != mLogElements.end()) && (pruneRows > 0)) {
285 LogBufferElement *e = *it;
286 if (e->getLogId() == id) {
287 if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
288 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
289 // kick a misbehaving log reader client off the island
290 oldest->release_Locked();
291 } else {
292 oldest->triggerSkip_Locked(pruneRows);
293 }
294 break;
295 }
296 it = mLogElements.erase(it);
297 stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
298 delete e;
299 pruneRows--;
300 } else {
301 it++;
302 }
303 }
304 }
305#endif
306
Mark Salyzyn0175b072014-02-26 09:50:16 -0800307 LogTimeEntry::unlock();
308}
309
310// clear all rows of type "id" from the buffer.
311void LogBuffer::clear(log_id_t id) {
312 pthread_mutex_lock(&mLogElementsLock);
313 prune(id, ULONG_MAX);
314 pthread_mutex_unlock(&mLogElementsLock);
315}
316
317// get the used space associated with "id".
318unsigned long LogBuffer::getSizeUsed(log_id_t id) {
319 pthread_mutex_lock(&mLogElementsLock);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800320 size_t retval = stats.sizes(id);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800321 pthread_mutex_unlock(&mLogElementsLock);
322 return retval;
323}
324
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800325#ifdef USERDEBUG_BUILD
326
327// set the total space allocated to "id"
328int LogBuffer::setSize(log_id_t id, unsigned long size) {
329 // Reasonable limits ...
330 if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
331 return -1;
332 }
333 pthread_mutex_lock(&mLogElementsLock);
334 log_buffer_size(id) = size;
335 pthread_mutex_unlock(&mLogElementsLock);
336 return 0;
337}
338
339// get the total space allocated to "id"
340unsigned long LogBuffer::getSize(log_id_t id) {
341 pthread_mutex_lock(&mLogElementsLock);
342 size_t retval = log_buffer_size(id);
343 pthread_mutex_unlock(&mLogElementsLock);
344 return retval;
345}
346
347#else // ! USERDEBUG_BUILD
348
Mark Salyzyn0175b072014-02-26 09:50:16 -0800349// get the total space allocated to "id"
350unsigned long LogBuffer::getSize(log_id_t /*id*/) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800351 return log_buffer_size(id);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800352}
353
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800354#endif
355
Mark Salyzyn7e2f83c2014-03-05 07:41:49 -0800356log_time LogBuffer::flushTo(
357 SocketClient *reader, const log_time start, bool privileged,
Mark Salyzyn0175b072014-02-26 09:50:16 -0800358 bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
359 LogBufferElementCollection::iterator it;
360 log_time max = start;
361 uid_t uid = reader->getUid();
362
363 pthread_mutex_lock(&mLogElementsLock);
364 for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
365 LogBufferElement *element = *it;
366
367 if (!privileged && (element->getUid() != uid)) {
368 continue;
369 }
370
371 if (element->getMonotonicTime() <= start) {
372 continue;
373 }
374
375 // NB: calling out to another object with mLogElementsLock held (safe)
376 if (filter && !(*filter)(element, arg)) {
377 continue;
378 }
379
380 pthread_mutex_unlock(&mLogElementsLock);
381
382 // range locking in LastLogTimes looks after us
383 max = element->flushTo(reader);
384
385 if (max == element->FLUSH_ERROR) {
386 return max;
387 }
388
389 pthread_mutex_lock(&mLogElementsLock);
390 }
391 pthread_mutex_unlock(&mLogElementsLock);
392
393 return max;
394}
Mark Salyzyn34facab2014-02-06 14:48:50 -0800395
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800396void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800397 log_time oldest(CLOCK_MONOTONIC);
398
399 pthread_mutex_lock(&mLogElementsLock);
400
401 // Find oldest element in the log(s)
402 LogBufferElementCollection::iterator it;
403 for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
404 LogBufferElement *element = *it;
405
406 if ((logMask & (1 << element->getLogId()))) {
407 oldest = element->getMonotonicTime();
408 break;
409 }
410 }
411
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800412 stats.format(strp, uid, logMask, oldest);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800413
414 pthread_mutex_unlock(&mLogElementsLock);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800415}