blob: fa5bceef0518c778e5989d9431dcdc27dc4cfc3e [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 */
Tom Cherryd5b38382020-05-12 13:16:41 -070016// for manual checking of stale entries during ChattyLogBuffer::erase()
Mark Salyzyn60636fa2016-10-24 16:22:17 -070017//#define DEBUG_CHECK_FOR_STALE_ENTRIES
Mark Salyzyn0175b072014-02-26 09:50:16 -080018
Tom Cherryd5b38382020-05-12 13:16:41 -070019#include "ChattyLogBuffer.h"
20
Mark Salyzyn671e3432014-05-06 07:34:59 -070021#include <ctype.h>
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -080022#include <endian.h>
Mark Salyzyn202e1532015-02-09 08:21:05 -080023#include <errno.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080024#include <stdio.h>
25#include <string.h>
Mark Salyzyn8fcfd852016-10-24 08:20:26 -070026#include <sys/cdefs.h>
Mark Salyzyn57a0af92014-05-09 17:44:18 -070027#include <sys/user.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080028#include <time.h>
29#include <unistd.h>
30
Mark Salyzyn511338d2015-05-19 09:12:30 -070031#include <unordered_map>
Tom Cherry10d086e2019-08-21 14:16:34 -070032#include <utility>
Mark Salyzyn511338d2015-05-19 09:12:30 -070033
Mark Salyzyn671e3432014-05-06 07:34:59 -070034#include <cutils/properties.h>
Mark Salyzynf10e2732016-09-27 13:08:23 -070035#include <private/android_logger.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080036
Mark Salyzynb6bee332015-09-08 08:56:32 -070037#include "LogKlog.h"
Mark Salyzyn671e3432014-05-06 07:34:59 -070038#include "LogReader.h"
Mark Salyzyna2c02222016-12-13 10:31:29 -080039#include "LogUtils.h"
Mark Salyzyn0175b072014-02-26 09:50:16 -080040
Mark Salyzyn8fcfd852016-10-24 08:20:26 -070041#ifndef __predict_false
42#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
43#endif
44
Mark Salyzyndfa7a072014-02-11 12:29:31 -080045// Default
Mark Salyzyndfa7a072014-02-11 12:29:31 -080046#define log_buffer_size(id) mMaxSize[id]
Mark Salyzyn671e3432014-05-06 07:34:59 -070047
Tom Cherryd5b38382020-05-12 13:16:41 -070048void ChattyLogBuffer::Init() {
Mark Salyzyndfa7a072014-02-11 12:29:31 -080049 log_id_for_each(i) {
Tom Cherryd5b38382020-05-12 13:16:41 -070050 if (SetSize(i, __android_logger_get_buffer_size(i))) {
51 SetSize(i, LOG_BUFFER_MIN_SIZE);
Mark Salyzyn57a0af92014-05-09 17:44:18 -070052 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -080053 }
Tom Cherrye170d1a2020-05-01 16:45:25 -070054 // Release any sleeping reader threads to dump their current content.
Tom Cherry68630a02020-05-11 16:29:29 -070055 auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
56 for (const auto& reader_thread : reader_list_->reader_threads()) {
57 reader_thread->triggerReader_Locked();
Mark Salyzynb6bee332015-09-08 08:56:32 -070058 }
Mark Salyzyn0175b072014-02-26 09:50:16 -080059}
60
Tom Cherryd5b38382020-05-12 13:16:41 -070061ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
62 LogStatistics* stats)
Tom Cherry68630a02020-05-11 16:29:29 -070063 : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) {
Mark Salyzyn3c501b52017-04-18 14:09:45 -070064 pthread_rwlock_init(&mLogElementsLock, nullptr);
Mark Salyzyn11e55cb2015-03-10 16:45:17 -070065
Mark Salyzyna2c02222016-12-13 10:31:29 -080066 log_id_for_each(i) {
Mark Salyzynae2abf12017-03-31 10:48:39 -070067 lastLoggedElements[i] = nullptr;
68 droppedElements[i] = nullptr;
Mark Salyzyna2c02222016-12-13 10:31:29 -080069 }
70
Tom Cherryd5b38382020-05-12 13:16:41 -070071 Init();
Mark Salyzyn11e55cb2015-03-10 16:45:17 -070072}
73
Tom Cherryd5b38382020-05-12 13:16:41 -070074ChattyLogBuffer::~ChattyLogBuffer() {
Mark Salyzyna2c02222016-12-13 10:31:29 -080075 log_id_for_each(i) {
76 delete lastLoggedElements[i];
77 delete droppedElements[i];
78 }
79}
80
Tom Cherryd5b38382020-05-12 13:16:41 -070081LogBufferElementCollection::iterator ChattyLogBuffer::GetOldest(log_id_t log_id) {
Tom Cherry385c2c92020-04-29 17:58:18 -070082 auto it = mLogElements.begin();
Tom Cherry20118ee2020-05-04 10:17:42 -070083 if (oldest_[log_id]) {
84 it = *oldest_[log_id];
Tom Cherry385c2c92020-04-29 17:58:18 -070085 }
86 while (it != mLogElements.end() && (*it)->getLogId() != log_id) {
87 it++;
88 }
89 if (it != mLogElements.end()) {
Tom Cherry20118ee2020-05-04 10:17:42 -070090 oldest_[log_id] = it;
Tom Cherry385c2c92020-04-29 17:58:18 -070091 }
92 return it;
93}
94
Mark Salyzyn501c3732017-03-10 14:31:54 -080095enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -080096
Tom Cherryd5b38382020-05-12 13:16:41 -070097static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) {
Mark Salyzyna2c02222016-12-13 10:31:29 -080098 // is it mostly identical?
Mark Salyzyn501c3732017-03-10 14:31:54 -080099 // if (!elem) return DIFFERENT;
Mark Salyzyn0484b3b2016-08-11 08:02:06 -0700100 ssize_t lenl = elem->getMsgLen();
101 if (lenl <= 0) return DIFFERENT; // value if this represents a chatty elem
Mark Salyzyn501c3732017-03-10 14:31:54 -0800102 // if (!last) return DIFFERENT;
Mark Salyzyn0484b3b2016-08-11 08:02:06 -0700103 ssize_t lenr = last->getMsgLen();
104 if (lenr <= 0) return DIFFERENT; // value if this represents a chatty elem
Mark Salyzyn501c3732017-03-10 14:31:54 -0800105 // if (elem->getLogId() != last->getLogId()) return DIFFERENT;
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800106 if (elem->getUid() != last->getUid()) return DIFFERENT;
107 if (elem->getPid() != last->getPid()) return DIFFERENT;
108 if (elem->getTid() != last->getTid()) return DIFFERENT;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800109
110 // last is more than a minute old, stop squashing identical messages
Tom Cherryd5b38382020-05-12 13:16:41 -0700111 if (elem->getRealTime().nsec() > (last->getRealTime().nsec() + 60 * NS_PER_SEC))
Mark Salyzyn501c3732017-03-10 14:31:54 -0800112 return DIFFERENT;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800113
114 // Identical message
115 const char* msgl = elem->getMsg();
116 const char* msgr = last->getMsg();
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800117 if (lenl == lenr) {
118 if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
119 // liblog tagged messages (content gets summed)
Tom Cherryd5b38382020-05-12 13:16:41 -0700120 if (elem->getLogId() == LOG_ID_EVENTS && lenl == sizeof(android_log_event_int_t) &&
121 !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
122 elem->getTag() == LIBLOG_LOG_TAG) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800123 return SAME_LIBLOG;
Mark Salyzyn1598fe02017-03-13 15:41:59 -0700124 }
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800125 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800126
127 // audit message (except sequence number) identical?
Tom Cherryd5b38382020-05-12 13:16:41 -0700128 if (last->isBinary() && lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
129 lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t))) {
130 if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800131 return DIFFERENT;
Mark Salyzyn1598fe02017-03-13 15:41:59 -0700132 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800133 msgl += sizeof(android_log_event_string_t);
134 lenl -= sizeof(android_log_event_string_t);
135 msgr += sizeof(android_log_event_string_t);
136 lenr -= sizeof(android_log_event_string_t);
137 }
Mark Salyzyn0484b3b2016-08-11 08:02:06 -0700138 static const char avc[] = "): avc: ";
Mark Salyzyn501c3732017-03-10 14:31:54 -0800139 const char* avcl = android::strnstr(msgl, lenl, avc);
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800140 if (!avcl) return DIFFERENT;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800141 lenl -= avcl - msgl;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800142 const char* avcr = android::strnstr(msgr, lenr, avc);
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800143 if (!avcr) return DIFFERENT;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800144 lenr -= avcr - msgr;
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800145 if (lenl != lenr) return DIFFERENT;
Tom Cherryd5b38382020-05-12 13:16:41 -0700146 if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800147 return DIFFERENT;
Mark Salyzyn1598fe02017-03-13 15:41:59 -0700148 }
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800149 return SAME;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800150}
151
Tom Cherryd5b38382020-05-12 13:16:41 -0700152int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
153 const char* msg, uint16_t len) {
Yi Kong141ccee2018-03-01 17:48:53 -0500154 if (log_id >= LOG_ID_MAX) {
Mark Salyzyn202e1532015-02-09 08:21:05 -0800155 return -EINVAL;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800156 }
Mark Salyzyne59c4692014-10-02 13:07:05 -0700157
Mark Salyzyn206ed8e2017-05-18 10:06:00 -0700158 // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
159 // This prevents any chance that an outside source can request an
160 // exact entry with time specified in ms or us precision.
161 if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
162
Tom Cherry2ac86de2020-02-20 13:21:51 -0800163 LogBufferElement* elem = new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
164
165 // b/137093665: don't coalesce security messages.
166 if (log_id == LOG_ID_SECURITY) {
167 wrlock();
168 log(elem);
169 unlock();
170
171 return len;
172 }
173
174 int prio = ANDROID_LOG_INFO;
175 const char* tag = nullptr;
176 size_t tag_len = 0;
177 if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
Tom Cherry1a12ae32020-05-01 16:13:18 -0700178 tag = tags_->tagToName(elem->getTag());
Tom Cherry2ac86de2020-02-20 13:21:51 -0800179 if (tag) {
180 tag_len = strlen(tag);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800181 }
Tom Cherry2ac86de2020-02-20 13:21:51 -0800182 } else {
183 prio = *msg;
184 tag = msg + 1;
185 tag_len = strnlen(tag, len - 1);
186 }
187 if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
188 // Log traffic received to total
Tom Cherry64e90162020-05-07 14:44:43 -0700189 stats_->AddTotal(elem);
Tom Cherry2ac86de2020-02-20 13:21:51 -0800190 delete elem;
191 return -EACCES;
Mark Salyzyne59c4692014-10-02 13:07:05 -0700192 }
Mark Salyzyn0175b072014-02-26 09:50:16 -0800193
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700194 wrlock();
Mark Salyzyna2c02222016-12-13 10:31:29 -0800195 LogBufferElement* currentLast = lastLoggedElements[log_id];
196 if (currentLast) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800197 LogBufferElement* dropped = droppedElements[log_id];
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700198 uint16_t count = dropped ? dropped->getDropped() : 0;
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800199 //
200 // State Init
201 // incoming:
Mark Salyzynae2abf12017-03-31 10:48:39 -0700202 // dropped = nullptr
203 // currentLast = nullptr;
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800204 // elem = incoming message
205 // outgoing:
Mark Salyzynae2abf12017-03-31 10:48:39 -0700206 // dropped = nullptr -> State 0
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800207 // currentLast = copy of elem
208 // log elem
209 // State 0
210 // incoming:
211 // count = 0
Mark Salyzynae2abf12017-03-31 10:48:39 -0700212 // dropped = nullptr
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800213 // currentLast = copy of last message
214 // elem = incoming message
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800215 // outgoing: if match != DIFFERENT
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800216 // dropped = copy of first identical message -> State 1
217 // currentLast = reference to elem
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800218 // break: if match == DIFFERENT
Mark Salyzynae2abf12017-03-31 10:48:39 -0700219 // dropped = nullptr -> State 0
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800220 // delete copy of last message (incoming currentLast)
221 // currentLast = copy of elem
222 // log elem
223 // State 1
224 // incoming:
225 // count = 0
226 // dropped = copy of first identical message
227 // currentLast = reference to last held-back incoming
228 // message
229 // elem = incoming message
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800230 // outgoing: if match == SAME
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800231 // delete copy of first identical message (dropped)
232 // dropped = reference to last held-back incoming
233 // message set to chatty count of 1 -> State 2
234 // currentLast = reference to elem
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800235 // outgoing: if match == SAME_LIBLOG
236 // dropped = copy of first identical message -> State 1
237 // take sum of currentLast and elem
238 // if sum overflows:
239 // log currentLast
240 // currentLast = reference to elem
241 // else
242 // delete currentLast
243 // currentLast = reference to elem, sum liblog.
244 // break: if match == DIFFERENT
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800245 // delete dropped
Mark Salyzynae2abf12017-03-31 10:48:39 -0700246 // dropped = nullptr -> State 0
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800247 // log reference to last held-back (currentLast)
248 // currentLast = copy of elem
249 // log elem
250 // State 2
251 // incoming:
252 // count = chatty count
253 // dropped = chatty message holding count
254 // currentLast = reference to last held-back incoming
255 // message.
256 // dropped = chatty message holding count
257 // elem = incoming message
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800258 // outgoing: if match != DIFFERENT
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800259 // delete chatty message holding count
260 // dropped = reference to last held-back incoming
261 // message, set to chatty count + 1
262 // currentLast = reference to elem
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800263 // break: if match == DIFFERENT
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800264 // log dropped (chatty message)
Mark Salyzynae2abf12017-03-31 10:48:39 -0700265 // dropped = nullptr -> State 0
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800266 // log reference to last held-back (currentLast)
267 // currentLast = copy of elem
268 // log elem
269 //
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800270 enum match_type match = identical(elem, currentLast);
271 if (match != DIFFERENT) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800272 if (dropped) {
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800273 // Sum up liblog tag messages?
274 if ((count == 0) /* at Pass 1 */ && (match == SAME_LIBLOG)) {
Tom Cherryd5b38382020-05-12 13:16:41 -0700275 android_log_event_int_t* event = reinterpret_cast<android_log_event_int_t*>(
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800276 const_cast<char*>(currentLast->getMsg()));
277 //
278 // To unit test, differentiate with something like:
279 // event->header.tag = htole32(CHATTY_LOG_TAG);
280 // here, then instead of delete currentLast below,
281 // log(currentLast) to see the incremental sums form.
282 //
283 uint32_t swab = event->payload.data;
284 unsigned long long total = htole32(swab);
285 event = reinterpret_cast<android_log_event_int_t*>(
Tom Cherryd5b38382020-05-12 13:16:41 -0700286 const_cast<char*>(elem->getMsg()));
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800287 swab = event->payload.data;
288
289 lastLoggedElements[LOG_ID_EVENTS] = elem;
290 total += htole32(swab);
291 // check for overflow
292 if (total >= UINT32_MAX) {
293 log(currentLast);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700294 unlock();
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800295 return len;
296 }
Tom Cherry64e90162020-05-07 14:44:43 -0700297 stats_->AddTotal(currentLast);
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800298 delete currentLast;
299 swab = total;
300 event->payload.data = htole32(swab);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700301 unlock();
Mark Salyzyn1dfb4de2016-12-16 16:09:15 -0800302 return len;
303 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800304 if (count == USHRT_MAX) {
305 log(dropped);
306 count = 1;
307 } else {
308 delete dropped;
309 ++count;
310 }
311 }
312 if (count) {
Tom Cherry64e90162020-05-07 14:44:43 -0700313 stats_->AddTotal(currentLast);
Mark Salyzyna2c02222016-12-13 10:31:29 -0800314 currentLast->setDropped(count);
315 }
316 droppedElements[log_id] = currentLast;
317 lastLoggedElements[log_id] = elem;
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700318 unlock();
Mark Salyzyna2c02222016-12-13 10:31:29 -0800319 return len;
320 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800321 if (dropped) { // State 1 or 2
322 if (count) { // State 2
323 log(dropped); // report chatty
324 } else { // State 1
325 delete dropped;
Mark Salyzyn8f83a352016-12-16 16:09:15 -0800326 }
Mark Salyzynae2abf12017-03-31 10:48:39 -0700327 droppedElements[log_id] = nullptr;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800328 log(currentLast); // report last message in the series
329 } else { // State 0
Mark Salyzyna2c02222016-12-13 10:31:29 -0800330 delete currentLast;
331 }
332 }
333 lastLoggedElements[log_id] = new LogBufferElement(*elem);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800334
Mark Salyzyna2c02222016-12-13 10:31:29 -0800335 log(elem);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700336 unlock();
Mark Salyzyna2c02222016-12-13 10:31:29 -0800337
338 return len;
339}
340
Tom Cherryd5b38382020-05-12 13:16:41 -0700341// assumes ChattyLogBuffer::wrlock() held, owns elem, look after garbage collection
342void ChattyLogBuffer::log(LogBufferElement* elem) {
Tom Cherry65abf392019-08-21 13:17:12 -0700343 mLogElements.push_back(elem);
Tom Cherry64e90162020-05-07 14:44:43 -0700344 stats_->Add(elem);
Mark Salyzyna2c02222016-12-13 10:31:29 -0800345 maybePrune(elem->getLogId());
Tom Cherry68630a02020-05-11 16:29:29 -0700346 reader_list_->NotifyNewLog(1 << elem->getLogId());
Mark Salyzyn0175b072014-02-26 09:50:16 -0800347}
348
Tom Cherryd5b38382020-05-12 13:16:41 -0700349// ChattyLogBuffer::wrlock() must be held when this function is called.
350void ChattyLogBuffer::maybePrune(log_id_t id) {
Tom Cherry64e90162020-05-07 14:44:43 -0700351 unsigned long prune_rows;
352 if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) {
353 prune(id, prune_rows);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800354 }
355}
356
Tom Cherryd5b38382020-05-12 13:16:41 -0700357LogBufferElementCollection::iterator ChattyLogBuffer::erase(LogBufferElementCollection::iterator it,
358 bool coalesce) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800359 LogBufferElement* element = *it;
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700360 log_id_t id = element->getLogId();
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700361
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700362 // Remove iterator references in the various lists that will become stale
363 // after the element is erased from the main logging list.
364
Mark Salyzyn501c3732017-03-10 14:31:54 -0800365 { // start of scope for found iterator
Tom Cherryd5b38382020-05-12 13:16:41 -0700366 int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag()
367 : element->getUid();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700368 LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
369 if ((found != mLastWorst[id].end()) && (it == found->second)) {
370 mLastWorst[id].erase(found);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700371 }
Mark Salyzync892ea32015-08-19 17:06:11 -0700372 }
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700373
Mark Salyzyn501c3732017-03-10 14:31:54 -0800374 { // start of scope for pid found iterator
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700375 // element->getUid() may not be AID_SYSTEM for next-best-watermark.
Mark Salyzyn8fcfd852016-10-24 08:20:26 -0700376 // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
377 // long term code stability, find() check should be fast for those ids.
Tom Cherryd5b38382020-05-12 13:16:41 -0700378 LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element->getPid());
379 if (found != mLastWorstPidOfSystem[id].end() && it == found->second) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700380 mLastWorstPidOfSystem[id].erase(found);
381 }
382 }
383
Mark Salyzyn7fd6c5c2016-01-19 16:04:41 -0800384 bool setLast[LOG_ID_MAX];
385 bool doSetLast = false;
Tom Cherry20118ee2020-05-04 10:17:42 -0700386 log_id_for_each(i) { doSetLast |= setLast[i] = oldest_[i] && it == *oldest_[i]; }
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700387#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
388 LogBufferElementCollection::iterator bad = it;
Tom Cherryd5b38382020-05-12 13:16:41 -0700389 int key =
390 (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() : element->getUid();
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700391#endif
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700392 it = mLogElements.erase(it);
Mark Salyzyn7fd6c5c2016-01-19 16:04:41 -0800393 if (doSetLast) {
394 log_id_for_each(i) {
395 if (setLast[i]) {
Tom Cherry385c2c92020-04-29 17:58:18 -0700396 if (__predict_false(it == mLogElements.end())) {
Tom Cherry20118ee2020-05-04 10:17:42 -0700397 oldest_[i] = std::nullopt;
Mark Salyzyn7fd6c5c2016-01-19 16:04:41 -0800398 } else {
Tom Cherry20118ee2020-05-04 10:17:42 -0700399 oldest_[i] = it; // Store the next iterator even if it does not correspond to
Tom Cherry385c2c92020-04-29 17:58:18 -0700400 // the same log_id, as a starting point for GetOldest().
Mark Salyzyn7fd6c5c2016-01-19 16:04:41 -0800401 }
402 }
Mark Salyzyn507eb9f2016-01-11 10:58:09 -0800403 }
404 }
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700405#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
406 log_id_for_each(i) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800407 for (auto b : mLastWorst[i]) {
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700408 if (bad == b.second) {
Tom Cherryd5b38382020-05-12 13:16:41 -0700409 android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i, b.first, key);
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700410 }
411 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800412 for (auto b : mLastWorstPidOfSystem[i]) {
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700413 if (bad == b.second) {
Tom Cherryd5b38382020-05-12 13:16:41 -0700414 android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i, b.first);
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700415 }
416 }
Mark Salyzyn60636fa2016-10-24 16:22:17 -0700417 }
418#endif
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700419 if (coalesce) {
Tom Cherry64e90162020-05-07 14:44:43 -0700420 stats_->Erase(element);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700421 } else {
Tom Cherry64e90162020-05-07 14:44:43 -0700422 stats_->Subtract(element);
Mark Salyzyn831aa292015-09-03 16:08:50 -0700423 }
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700424 delete element;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700425
426 return it;
427}
428
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700429// Define a temporary mechanism to report the last LogBufferElement pointer
430// for the specified uid, pid and tid. Used below to help merge-sort when
431// pruning for worst UID.
432class LogBufferElementKey {
433 const union {
434 struct {
Mark Salyzyn684bdb52016-12-13 12:44:20 -0800435 uint32_t uid;
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700436 uint16_t pid;
437 uint16_t tid;
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700438 } __packed;
439 uint64_t value;
440 } __packed;
441
Tom Cherryd5b38382020-05-12 13:16:41 -0700442 public:
443 LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) : uid(uid), pid(pid), tid(tid) {}
444 explicit LogBufferElementKey(uint64_t key) : value(key) {}
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700445
Tom Cherryd5b38382020-05-12 13:16:41 -0700446 uint64_t getKey() { return value; }
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700447};
448
Mark Salyzyn511338d2015-05-19 09:12:30 -0700449class LogBufferElementLast {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800450 typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700451 LogBufferElementMap map;
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700452
Tom Cherryd5b38382020-05-12 13:16:41 -0700453 public:
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700454 bool coalesce(LogBufferElement* element, uint16_t dropped) {
Tom Cherryd5b38382020-05-12 13:16:41 -0700455 LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid());
Mark Salyzyn511338d2015-05-19 09:12:30 -0700456 LogBufferElementMap::iterator it = map.find(key.getKey());
457 if (it != map.end()) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800458 LogBufferElement* found = it->second;
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700459 uint16_t moreDropped = found->getDropped();
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700460 if ((dropped + moreDropped) > USHRT_MAX) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700461 map.erase(it);
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700462 } else {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700463 found->setDropped(dropped + moreDropped);
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700464 return true;
465 }
466 }
467 return false;
468 }
469
Mark Salyzyn501c3732017-03-10 14:31:54 -0800470 void add(LogBufferElement* element) {
Tom Cherryd5b38382020-05-12 13:16:41 -0700471 LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid());
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700472 map[key.getKey()] = element;
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700473 }
474
Tom Cherryd5b38382020-05-12 13:16:41 -0700475 void clear() { map.clear(); }
Mark Salyzyne06a6e02015-04-20 14:08:56 -0700476
Mark Salyzyn501c3732017-03-10 14:31:54 -0800477 void clear(LogBufferElement* element) {
Tom Cherry10d086e2019-08-21 14:16:34 -0700478 uint64_t current = element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800479 for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
480 LogBufferElement* mapElement = it->second;
Tom Cherry10d086e2019-08-21 14:16:34 -0700481 if (mapElement->getDropped() >= EXPIRE_THRESHOLD &&
482 current > mapElement->getRealTime().nsec()) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700483 it = map.erase(it);
484 } else {
485 ++it;
Mark Salyzyne06a6e02015-04-20 14:08:56 -0700486 }
487 }
488 }
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700489};
490
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700491// If the selected reader is blocking our pruning progress, decide on
492// what kind of mitigation is necessary to unblock the situation.
Tom Cherryd5b38382020-05-12 13:16:41 -0700493void ChattyLogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) {
Tom Cherry64e90162020-05-07 14:44:43 -0700494 if (stats_->Sizes(id) > (2 * log_buffer_size(id))) { // +100%
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700495 // A misbehaving or slow reader has its connection
496 // dropped if we hit too much memory pressure.
Tom Cherryd5b38382020-05-12 13:16:41 -0700497 android::prdebug("Kicking blocked reader, pid %d, from ChattyLogBuffer::kickMe()\n",
Tom Cherrycef47bb2020-05-04 17:10:16 -0700498 me->client()->getPid());
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700499 me->release_Locked();
Tom Cherry68630a02020-05-11 16:29:29 -0700500 } else if (me->deadline().time_since_epoch().count() != 0) {
501 // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700502 me->triggerReader_Locked();
503 } else {
504 // tell slow reader to skip entries to catch up
Tom Cherry21f16a02019-11-15 17:37:03 -0800505 android::prdebug(
Tom Cherryd5b38382020-05-12 13:16:41 -0700506 "Skipping %lu entries from slow reader, pid %d, from ChattyLogBuffer::kickMe()\n",
Tom Cherrycef47bb2020-05-04 17:10:16 -0700507 pruneRows, me->client()->getPid());
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700508 me->triggerSkip_Locked(id, pruneRows);
509 }
510}
511
Mark Salyzyn0175b072014-02-26 09:50:16 -0800512// prune "pruneRows" of type "id" from the buffer.
513//
Mark Salyzyn5bb29722015-09-08 09:12:51 -0700514// This garbage collection task is used to expire log entries. It is called to
515// remove all logs (clear), all UID logs (unprivileged clear), or every
516// 256 or 10% of the total logs (whichever is less) to prune the logs.
517//
518// First there is a prep phase where we discover the reader region lock that
519// acts as a backstop to any pruning activity to stop there and go no further.
520//
521// There are three major pruning loops that follow. All expire from the oldest
522// entries. Since there are multiple log buffers, the Android logging facility
523// will appear to drop entries 'in the middle' when looking at multiple log
524// sources and buffers. This effect is slightly more prominent when we prune
525// the worst offender by logging source. Thus the logs slowly loose content
526// and value as you move back in time. This is preferred since chatty sources
527// invariably move the logs value down faster as less chatty sources would be
528// expired in the noise.
529//
530// The first loop performs blacklisting and worst offender pruning. Falling
531// through when there are no notable worst offenders and have not hit the
532// region lock preventing further worst offender pruning. This loop also looks
533// after managing the chatty log entries and merging to help provide
534// statistical basis for blame. The chatty entries are not a notification of
535// how much logs you may have, but instead represent how much logs you would
536// have had in a virtual log buffer that is extended to cover all the in-memory
537// logs without loss. They last much longer than the represented pruned logs
538// since they get multiplied by the gains in the non-chatty log sources.
539//
540// The second loop get complicated because an algorithm of watermarks and
541// history is maintained to reduce the order and keep processing time
542// down to a minimum at scale. These algorithms can be costly in the face
543// of larger log buffers, or severly limited processing time granted to a
544// background task at lowest priority.
545//
546// This second loop does straight-up expiration from the end of the logs
547// (again, remember for the specified log buffer id) but does some whitelist
548// preservation. Thus whitelist is a Hail Mary low priority, blacklists and
549// spam filtration all take priority. This second loop also checks if a region
550// lock is causing us to buffer too much in the logs to help the reader(s),
551// and will tell the slowest reader thread to skip log entries, and if
552// persistent and hits a further threshold, kill the reader thread.
553//
554// The third thread is optional, and only gets hit if there was a whitelist
555// and more needs to be pruned against the backstop of the region lock.
556//
Tom Cherryd5b38382020-05-12 13:16:41 -0700557// ChattyLogBuffer::wrlock() must be held when this function is called.
Mark Salyzyn5bb29722015-09-08 09:12:51 -0700558//
Tom Cherryd5b38382020-05-12 13:16:41 -0700559bool ChattyLogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
Tom Cherry6ec71e92020-05-04 12:53:36 -0700560 LogReaderThread* oldest = nullptr;
Mark Salyzync5dc9702015-09-16 15:34:00 -0700561 bool busy = false;
Mark Salyzyn2b25c662015-09-16 15:34:00 -0700562 bool clearAll = pruneRows == ULONG_MAX;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800563
Tom Cherry68630a02020-05-11 16:29:29 -0700564 auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
Mark Salyzyn0175b072014-02-26 09:50:16 -0800565
566 // Region locked?
Tom Cherry68630a02020-05-11 16:29:29 -0700567 for (const auto& reader_thread : reader_list_->reader_threads()) {
568 if (!reader_thread->IsWatching(id)) {
569 continue;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800570 }
Tom Cherry68630a02020-05-11 16:29:29 -0700571 if (!oldest || oldest->start() > reader_thread->start() ||
572 (oldest->start() == reader_thread->start() &&
573 reader_thread->deadline().time_since_epoch().count() != 0)) {
574 oldest = reader_thread.get();
575 }
Mark Salyzyn0175b072014-02-26 09:50:16 -0800576 }
577
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800578 LogBufferElementCollection::iterator it;
579
Mark Salyzyn501c3732017-03-10 14:31:54 -0800580 if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
Mark Salyzyn43a5f312016-09-01 15:48:36 -0700581 // Only here if clear all request from non system source, so chatty
582 // filter logistics is not required.
Tom Cherry385c2c92020-04-29 17:58:18 -0700583 it = GetOldest(id);
Mark Salyzyn507eb9f2016-01-11 10:58:09 -0800584 while (it != mLogElements.end()) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800585 LogBufferElement* element = *it;
Mark Salyzyn1a240b42014-06-12 11:16:16 -0700586
Tom Cherryd5b38382020-05-12 13:16:41 -0700587 if (element->getLogId() != id || element->getUid() != caller_uid) {
Mark Salyzyn2b25c662015-09-16 15:34:00 -0700588 ++it;
589 continue;
590 }
591
Tom Cherrycef47bb2020-05-04 17:10:16 -0700592 if (oldest && oldest->start() <= element->getSequence()) {
Tom Cherry5e266552020-04-08 10:47:26 -0700593 busy = true;
594 kickMe(oldest, id, pruneRows);
Mark Salyzyn1a240b42014-06-12 11:16:16 -0700595 break;
596 }
597
Mark Salyzyn2b25c662015-09-16 15:34:00 -0700598 it = erase(it);
Mark Salyzyn43a5f312016-09-01 15:48:36 -0700599 if (--pruneRows == 0) {
600 break;
601 }
Mark Salyzyn1a240b42014-06-12 11:16:16 -0700602 }
Mark Salyzync5dc9702015-09-16 15:34:00 -0700603 return busy;
Mark Salyzyn1a240b42014-06-12 11:16:16 -0700604 }
605
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700606 // prune by worst offenders; by blacklist, UID, and by PID of system UID
Tom Cherry5a3db392020-05-01 17:03:20 -0700607 bool hasBlacklist = (id != LOG_ID_SECURITY) && prune_->naughty();
Mark Salyzyn2b25c662015-09-16 15:34:00 -0700608 while (!clearAll && (pruneRows > 0)) {
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800609 // recalculate the worst offender on every batched pass
Mark Salyzyn501c3732017-03-10 14:31:54 -0800610 int worst = -1; // not valid for getUid() or getKey()
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800611 size_t worst_sizes = 0;
612 size_t second_worst_sizes = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800613 pid_t worstPid = 0; // POSIX guarantees PID != 0
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800614
Tom Cherry5a3db392020-05-01 17:03:20 -0700615 if (worstUidEnabledForLogid(id) && prune_->worstUidEnabled()) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700616 // Calculate threshold as 12.5% of available storage
617 size_t threshold = log_buffer_size(id) / 8;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700618
Tom Cherryb6b78e92020-05-07 09:13:12 -0700619 if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
Tom Cherry64e90162020-05-07 14:44:43 -0700620 stats_->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
Mark Salyzyn8fcfd852016-10-24 08:20:26 -0700621 // per-pid filter for AID_SYSTEM sources is too complex
Mark Salyzyn6a066942016-07-14 15:34:30 -0700622 } else {
Tom Cherry64e90162020-05-07 14:44:43 -0700623 stats_->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700624
Tom Cherryb6b78e92020-05-07 09:13:12 -0700625 if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
Tom Cherry64e90162020-05-07 14:44:43 -0700626 stats_->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700627 }
628 }
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800629 }
630
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700631 // skip if we have neither worst nor naughty filters
Mark Salyzyn6a066942016-07-14 15:34:30 -0700632 if ((worst == -1) && !hasBlacklist) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700633 break;
634 }
635
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800636 bool kick = false;
Tom Cherry385c2c92020-04-29 17:58:18 -0700637 bool leading = true; // true if starting from the oldest log entry, false if starting from
638 // a specific chatty entry.
Mark Salyzyn5bb29722015-09-08 09:12:51 -0700639 // Perform at least one mandatory garbage collection cycle in following
640 // - clear leading chatty tags
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700641 // - coalesce chatty tags
Mark Salyzyn5bb29722015-09-08 09:12:51 -0700642 // - check age-out of preserved logs
643 bool gc = pruneRows <= 1;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700644 if (!gc && (worst != -1)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800645 { // begin scope for worst found iterator
Tom Cherryd5b38382020-05-12 13:16:41 -0700646 LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
647 if (found != mLastWorst[id].end() && found->second != mLogElements.end()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700648 leading = false;
649 it = found->second;
650 }
651 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800652 if (worstPid) { // begin scope for pid worst found iterator
Mark Salyzyn8fcfd852016-10-24 08:20:26 -0700653 // FYI: worstPid only set if !LOG_ID_EVENTS and
654 // !LOG_ID_SECURITY, not going to make that assumption ...
Tom Cherryd5b38382020-05-12 13:16:41 -0700655 LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid);
656 if (found != mLastWorstPidOfSystem[id].end() &&
657 found->second != mLogElements.end()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700658 leading = false;
659 it = found->second;
660 }
Mark Salyzync892ea32015-08-19 17:06:11 -0700661 }
662 }
Tom Cherry385c2c92020-04-29 17:58:18 -0700663 if (leading) {
664 it = GetOldest(id);
665 }
Tom Cherryd5b38382020-05-12 13:16:41 -0700666 static const timespec too_old = {EXPIRE_HOUR_THRESHOLD * 60 * 60, 0};
Mark Salyzynccfe8442015-08-24 13:43:27 -0700667 LogBufferElementCollection::iterator lastt;
668 lastt = mLogElements.end();
669 --lastt;
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700670 LogBufferElementLast last;
Mark Salyzync892ea32015-08-19 17:06:11 -0700671 while (it != mLogElements.end()) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800672 LogBufferElement* element = *it;
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800673
Tom Cherrycef47bb2020-05-04 17:10:16 -0700674 if (oldest && oldest->start() <= element->getSequence()) {
Tom Cherry5e266552020-04-08 10:47:26 -0700675 busy = true;
Mark Salyzyn0878a7c2017-05-11 13:28:33 -0700676 // Do not let chatty eliding trigger any reader mitigation
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800677 break;
678 }
679
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700680 if (element->getLogId() != id) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800681 ++it;
682 continue;
683 }
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700684 // below this point element->getLogId() == id
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800685
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700686 uint16_t dropped = element->getDropped();
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800687
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700688 // remove any leading drops
689 if (leading && dropped) {
690 it = erase(it);
691 continue;
692 }
693
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700694 if (dropped && last.coalesce(element, dropped)) {
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700695 it = erase(it, true);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700696 continue;
697 }
698
Tom Cherryd5b38382020-05-12 13:16:41 -0700699 int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag()
700 : element->getUid();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700701
Tom Cherry5a3db392020-05-01 17:03:20 -0700702 if (hasBlacklist && prune_->naughty(element)) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700703 last.clear(element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700704 it = erase(it);
705 if (dropped) {
706 continue;
707 }
708
709 pruneRows--;
710 if (pruneRows == 0) {
711 break;
712 }
713
Mark Salyzyn6a066942016-07-14 15:34:30 -0700714 if (key == worst) {
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700715 kick = true;
716 if (worst_sizes < second_worst_sizes) {
717 break;
718 }
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700719 worst_sizes -= element->getMsgLen();
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700720 }
721 continue;
722 }
723
Mark Salyzyn501c3732017-03-10 14:31:54 -0800724 if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old)) ||
725 (element->getRealTime() > (*lastt)->getRealTime())) {
Mark Salyzynccfe8442015-08-24 13:43:27 -0700726 break;
727 }
728
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700729 if (dropped) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700730 last.add(element);
Tom Cherryd5b38382020-05-12 13:16:41 -0700731 if (worstPid && ((!gc && element->getPid() == worstPid) ||
732 mLastWorstPidOfSystem[id].find(element->getPid()) ==
733 mLastWorstPidOfSystem[id].end())) {
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700734 // element->getUid() may not be AID_SYSTEM, next best
Mark Salyzyn8fcfd852016-10-24 08:20:26 -0700735 // watermark if current one empty. id is not LOG_ID_EVENTS
736 // or LOG_ID_SECURITY because of worstPid check.
Mark Salyzyn1eefca22016-09-01 07:28:44 -0700737 mLastWorstPidOfSystem[id][element->getPid()] = it;
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700738 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800739 if ((!gc && !worstPid && (key == worst)) ||
740 (mLastWorst[id].find(key) == mLastWorst[id].end())) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700741 mLastWorst[id][key] = it;
Mark Salyzyn49afe0d2015-08-24 13:43:27 -0700742 }
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800743 ++it;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700744 continue;
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800745 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700746
Tom Cherryd5b38382020-05-12 13:16:41 -0700747 if (key != worst || (worstPid && element->getPid() != worstPid)) {
Mark Salyzyn59212762015-06-01 09:41:19 -0700748 leading = false;
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700749 last.clear(element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700750 ++it;
751 continue;
752 }
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700753 // key == worst below here
754 // If worstPid set, then element->getPid() == worstPid below here
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700755
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700756 pruneRows--;
757 if (pruneRows == 0) {
758 break;
759 }
760
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700761 kick = true;
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700762
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700763 uint16_t len = element->getMsgLen();
Mark Salyzyn5392aac2015-05-22 10:03:31 -0700764
765 // do not create any leading drops
766 if (leading) {
767 it = erase(it);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700768 } else {
Tom Cherry64e90162020-05-07 14:44:43 -0700769 stats_->Drop(element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700770 element->setDropped(1);
771 if (last.coalesce(element, 1)) {
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700772 it = erase(it, true);
Mark Salyzyn5392aac2015-05-22 10:03:31 -0700773 } else {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700774 last.add(element);
Tom Cherryd5b38382020-05-12 13:16:41 -0700775 if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) ==
776 mLastWorstPidOfSystem[id].end())) {
Mark Salyzynfa07f9d2016-10-21 09:46:42 -0700777 // element->getUid() may not be AID_SYSTEM, next best
Mark Salyzyn8fcfd852016-10-24 08:20:26 -0700778 // watermark if current one empty. id is not
779 // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700780 mLastWorstPidOfSystem[id][worstPid] = it;
781 }
Tom Cherryd5b38382020-05-12 13:16:41 -0700782 if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700783 mLastWorst[id][worst] = it;
Mark Salyzyn5bb29722015-09-08 09:12:51 -0700784 }
Mark Salyzyn5392aac2015-05-22 10:03:31 -0700785 ++it;
786 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700787 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700788 if (worst_sizes < second_worst_sizes) {
789 break;
790 }
791 worst_sizes -= len;
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800792 }
Mark Salyzyn2c9d9092015-04-17 15:38:04 -0700793 last.clear();
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800794
Tom Cherry5a3db392020-05-01 17:03:20 -0700795 if (!kick || !prune_->worstUidEnabled()) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800796 break; // the following loop will ask bad clients to skip/drop
Mark Salyzyn64d6fe92014-02-06 18:11:13 -0800797 }
798 }
799
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800800 bool whitelist = false;
Tom Cherry5a3db392020-05-01 17:03:20 -0700801 bool hasWhitelist = (id != LOG_ID_SECURITY) && prune_->nice() && !clearAll;
Tom Cherry385c2c92020-04-29 17:58:18 -0700802 it = GetOldest(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800803 while ((pruneRows > 0) && (it != mLogElements.end())) {
804 LogBufferElement* element = *it;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700805
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700806 if (element->getLogId() != id) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700807 it++;
808 continue;
809 }
810
Tom Cherrycef47bb2020-05-04 17:10:16 -0700811 if (oldest && oldest->start() <= element->getSequence()) {
Tom Cherry5e266552020-04-08 10:47:26 -0700812 busy = true;
813 if (!whitelist) kickMe(oldest, id, pruneRows);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700814 break;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800815 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700816
Tom Cherry5a3db392020-05-01 17:03:20 -0700817 if (hasWhitelist && !element->getDropped() && prune_->nice(element)) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700818 // WhiteListed
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700819 whitelist = true;
820 it++;
821 continue;
822 }
823
824 it = erase(it);
825 pruneRows--;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800826 }
827
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700828 // Do not save the whitelist if we are reader range limited
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800829 if (whitelist && (pruneRows > 0)) {
Tom Cherry385c2c92020-04-29 17:58:18 -0700830 it = GetOldest(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800831 while ((it != mLogElements.end()) && (pruneRows > 0)) {
832 LogBufferElement* element = *it;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700833
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700834 if (element->getLogId() != id) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700835 ++it;
836 continue;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800837 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700838
Tom Cherrycef47bb2020-05-04 17:10:16 -0700839 if (oldest && oldest->start() <= element->getSequence()) {
Tom Cherry5e266552020-04-08 10:47:26 -0700840 busy = true;
841 kickMe(oldest, id, pruneRows);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700842 break;
843 }
844
845 it = erase(it);
846 pruneRows--;
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800847 }
848 }
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800849
Mark Salyzync5dc9702015-09-16 15:34:00 -0700850 return (pruneRows > 0) && busy;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800851}
852
853// clear all rows of type "id" from the buffer.
Tom Cherryd5b38382020-05-12 13:16:41 -0700854bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) {
Mark Salyzync5dc9702015-09-16 15:34:00 -0700855 bool busy = true;
856 // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
857 for (int retry = 4;;) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800858 if (retry == 1) { // last pass
Mark Salyzync5dc9702015-09-16 15:34:00 -0700859 // Check if it is still busy after the sleep, we say prune
860 // one entry, not another clear run, so we are looking for
861 // the quick side effect of the return value to tell us if
862 // we have a _blocked_ reader.
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700863 wrlock();
Mark Salyzync5dc9702015-09-16 15:34:00 -0700864 busy = prune(id, 1, uid);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700865 unlock();
Mark Salyzync5dc9702015-09-16 15:34:00 -0700866 // It is still busy, blocked reader(s), lets kill them all!
867 // otherwise, lets be a good citizen and preserve the slow
868 // readers and let the clear run (below) deal with determining
869 // if we are still blocked and return an error code to caller.
870 if (busy) {
Tom Cherry68630a02020-05-11 16:29:29 -0700871 auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
872 for (const auto& reader_thread : reader_list_->reader_threads()) {
873 if (reader_thread->IsWatching(id)) {
Tom Cherry21f16a02019-11-15 17:37:03 -0800874 android::prdebug(
Tom Cherryd5b38382020-05-12 13:16:41 -0700875 "Kicking blocked reader, pid %d, from ChattyLogBuffer::clear()\n",
Tom Cherry68630a02020-05-11 16:29:29 -0700876 reader_thread->client()->getPid());
877 reader_thread->release_Locked();
Mark Salyzync5dc9702015-09-16 15:34:00 -0700878 }
Mark Salyzync5dc9702015-09-16 15:34:00 -0700879 }
Mark Salyzync5dc9702015-09-16 15:34:00 -0700880 }
881 }
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700882 wrlock();
Mark Salyzync5dc9702015-09-16 15:34:00 -0700883 busy = prune(id, ULONG_MAX, uid);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700884 unlock();
Mark Salyzync5dc9702015-09-16 15:34:00 -0700885 if (!busy || !--retry) {
886 break;
887 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800888 sleep(1); // Let reader(s) catch up after notification
Mark Salyzync5dc9702015-09-16 15:34:00 -0700889 }
890 return busy;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800891}
892
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800893// set the total space allocated to "id"
Tom Cherryd5b38382020-05-12 13:16:41 -0700894int ChattyLogBuffer::SetSize(log_id_t id, unsigned long size) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800895 // Reasonable limits ...
Mark Salyzynf10e2732016-09-27 13:08:23 -0700896 if (!__android_logger_valid_buffer_size(size)) {
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800897 return -1;
898 }
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700899 wrlock();
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800900 log_buffer_size(id) = size;
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700901 unlock();
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800902 return 0;
903}
904
905// get the total space allocated to "id"
Tom Cherryd5b38382020-05-12 13:16:41 -0700906unsigned long ChattyLogBuffer::GetSize(log_id_t id) {
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700907 rdlock();
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800908 size_t retval = log_buffer_size(id);
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700909 unlock();
Mark Salyzyndfa7a072014-02-11 12:29:31 -0800910 return retval;
911}
912
Tom Cherryd5b38382020-05-12 13:16:41 -0700913uint64_t ChattyLogBuffer::FlushTo(
Tom Cherry68630a02020-05-11 16:29:29 -0700914 SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged, bool security,
915 const std::function<FlushToResult(const LogBufferElement* element)>& filter) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800916 LogBufferElementCollection::iterator it;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800917 uid_t uid = reader->getUid();
918
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700919 rdlock();
Dragoslav Mitrinovic8e8e8db2015-01-15 09:29:43 -0600920
Tom Cherry10d086e2019-08-21 14:16:34 -0700921 if (start <= 1) {
Dragoslav Mitrinovic8e8e8db2015-01-15 09:29:43 -0600922 // client wants to start from the beginning
923 it = mLogElements.begin();
924 } else {
925 // Client wants to start from some specified time. Chances are
926 // we are better off starting from the end of the time sorted list.
Tom Cherry10d086e2019-08-21 14:16:34 -0700927 for (it = mLogElements.end(); it != mLogElements.begin();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800928 /* do nothing */) {
Dragoslav Mitrinovic8e8e8db2015-01-15 09:29:43 -0600929 --it;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800930 LogBufferElement* element = *it;
Tom Cherry10d086e2019-08-21 14:16:34 -0700931 if (element->getSequence() <= start) {
932 it++;
Dragoslav Mitrinovic8e8e8db2015-01-15 09:29:43 -0600933 break;
934 }
935 }
936 }
937
Tom Cherry10d086e2019-08-21 14:16:34 -0700938 uint64_t curr = start;
Mark Salyzynb5b87962017-01-23 14:20:31 -0800939
Dragoslav Mitrinovic8e8e8db2015-01-15 09:29:43 -0600940 for (; it != mLogElements.end(); ++it) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800941 LogBufferElement* element = *it;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800942
943 if (!privileged && (element->getUid() != uid)) {
944 continue;
945 }
946
Mark Salyzyn8fa88962016-01-26 14:32:35 -0800947 if (!security && (element->getLogId() == LOG_ID_SECURITY)) {
948 continue;
949 }
950
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700951 // NB: calling out to another object with wrlock() held (safe)
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800952 if (filter) {
Tom Cherry68630a02020-05-11 16:29:29 -0700953 FlushToResult ret = filter(element);
954 if (ret == FlushToResult::kSkip) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800955 continue;
956 }
Tom Cherry68630a02020-05-11 16:29:29 -0700957 if (ret == FlushToResult::kStop) {
Mark Salyzynf7c0f752015-03-03 13:39:37 -0800958 break;
959 }
Mark Salyzyn0175b072014-02-26 09:50:16 -0800960 }
961
Mark Salyzynae2abf12017-03-31 10:48:39 -0700962 bool sameTid = false;
963 if (lastTid) {
964 sameTid = lastTid[element->getLogId()] == element->getTid();
965 // Dropped (chatty) immediately following a valid log from the
966 // same source in the same log buffer indicates we have a
967 // multiple identical squash. chatty that differs source
968 // is due to spam filter. chatty to chatty of different
969 // source is also due to spam filter.
970 lastTid[element->getLogId()] =
Tom Cherryd5b38382020-05-12 13:16:41 -0700971 (element->getDropped() && !sameTid) ? 0 : element->getTid();
Mark Salyzynae2abf12017-03-31 10:48:39 -0700972 }
Mark Salyzynb5b87962017-01-23 14:20:31 -0800973
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700974 unlock();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800975
976 // range locking in LastLogTimes looks after us
Tom Cherry64e90162020-05-07 14:44:43 -0700977 curr = element->flushTo(reader, stats_, sameTid);
Mark Salyzyn0175b072014-02-26 09:50:16 -0800978
Mark Salyzyn206ed8e2017-05-18 10:06:00 -0700979 if (curr == element->FLUSH_ERROR) {
980 return curr;
Mark Salyzyneb45db22017-05-17 19:55:12 +0000981 }
Mark Salyzyn0175b072014-02-26 09:50:16 -0800982
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700983 rdlock();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800984 }
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700985 unlock();
Mark Salyzyn0175b072014-02-26 09:50:16 -0800986
Mark Salyzyn206ed8e2017-05-18 10:06:00 -0700987 return curr;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800988}