blob: 1705d48088e1b1bfe6170d5a5405c18beccf925b [file] [log] [blame]
Mark Salyzyn34facab2014-02-06 14:48:50 -08001/*
2 * Copyright (C) 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
Tom Cherry64e90162020-05-07 14:44:43 -070017#include "LogStatistics.h"
18
Mark Salyzync4e48232017-05-04 13:54:46 -070019#include <ctype.h>
Mark Salyzyn9a038632014-04-07 07:05:40 -070020#include <fcntl.h>
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070021#include <inttypes.h>
Mark Salyzynb8a95bd2016-04-07 11:06:31 -070022#include <pwd.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070023#include <stdio.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070024#include <string.h>
Mark Salyzynb8a95bd2016-04-07 11:06:31 -070025#include <sys/types.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070026#include <unistd.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080027
Mark Salyzyn9af33ee2016-10-05 12:34:37 -070028#include <list>
29
Tom Cherryf74503d2020-06-19 12:21:21 -070030#include <android-base/logging.h>
Mark Salyzyn03bb7592017-04-14 09:46:57 -070031#include <private/android_logger.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080032
Tom Cherry3dd3ec32020-06-02 15:39:21 -070033#include "LogBufferElement.h"
34
Mark Salyzyn03bb7592017-04-14 09:46:57 -070035static const uint64_t hourSec = 60 * 60;
36static const uint64_t monthSec = 31 * 24 * hourSec;
37
Tom Cherry64e90162020-05-07 14:44:43 -070038std::atomic<size_t> LogStatistics::SizesTotal;
Mark Salyzyn32962912016-09-12 10:29:17 -070039
Tom Cherryb0263af2020-06-03 15:38:32 -070040static std::string TagNameKey(const LogStatisticsElement& element) {
41 if (IsBinary(element.log_id)) {
42 uint32_t tag = element.tag;
43 if (tag) {
44 const char* cp = android::tagToName(tag);
45 if (cp) {
46 return std::string(cp);
47 }
48 }
49 return android::base::StringPrintf("[%" PRIu32 "]", tag);
50 }
51 const char* msg = element.msg;
52 if (!msg) {
53 return "chatty";
54 }
55 ++msg;
56 uint16_t len = element.msg_len;
57 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
58 if (!len) {
59 return "<NULL>";
60 }
61 return std::string(msg, len);
62}
63
Tom Cherryf74503d2020-06-19 12:21:21 -070064LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size)
65 : enable(enable_statistics), track_total_size_(track_total_size) {
Mark Salyzyn03bb7592017-04-14 09:46:57 -070066 log_time now(CLOCK_REALTIME);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070067 log_id_for_each(id) {
68 mSizes[id] = 0;
69 mElements[id] = 0;
Mark Salyzyn58b8be82015-09-30 07:40:09 -070070 mDroppedElements[id] = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070071 mSizesTotal[id] = 0;
72 mElementsTotal[id] = 0;
Mark Salyzyn03bb7592017-04-14 09:46:57 -070073 mOldest[id] = now;
74 mNewest[id] = now;
75 mNewestDropped[id] = now;
Mark Salyzyn34facab2014-02-06 14:48:50 -080076 }
77}
78
Mark Salyzyn720f6d12015-03-16 08:26:05 -070079namespace android {
80
Mark Salyzyn501c3732017-03-10 14:31:54 -080081size_t sizesTotal() {
82 return LogStatistics::sizesTotal();
83}
Mark Salyzyn32962912016-09-12 10:29:17 -070084
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070085// caller must own and free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -080086char* pidToName(pid_t pid) {
Yi Kongc8d09dd2018-07-13 17:39:22 -070087 char* retval = nullptr;
Mark Salyzyn501c3732017-03-10 14:31:54 -080088 if (pid == 0) { // special case from auditd/klogd for kernel
Mark Salyzynae4d9282014-10-15 08:49:39 -070089 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070090 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070091 char buffer[512];
92 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
Tom Cherry9b4246d2020-06-17 11:40:55 -070093 int fd = open(buffer, O_RDONLY | O_CLOEXEC);
Mark Salyzyn9a038632014-04-07 07:05:40 -070094 if (fd >= 0) {
95 ssize_t ret = read(fd, buffer, sizeof(buffer));
96 if (ret > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -080097 buffer[sizeof(buffer) - 1] = '\0';
Mark Salyzyn9a038632014-04-07 07:05:40 -070098 // frameworks intermediate state
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -080099 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700100 retval = strdup(buffer);
101 }
102 }
103 close(fd);
104 }
105 }
106 return retval;
107}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700108}
109
Tom Cherrya26f7df2020-05-19 17:48:42 -0700110void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
Tom Cherry64e90162020-05-07 14:44:43 -0700111 auto lock = std::lock_guard{lock_};
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700112
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700113 mSizesTotal[log_id] += size;
114 SizesTotal += size;
115 ++mElementsTotal[log_id];
116}
117
Tom Cherryf74503d2020-06-19 12:21:21 -0700118void LogStatistics::Add(LogStatisticsElement element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700119 auto lock = std::lock_guard{lock_};
Tom Cherryf74503d2020-06-19 12:21:21 -0700120
121 if (!track_total_size_) {
122 element.total_len = element.msg_len;
123 }
124
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700125 log_id_t log_id = element.log_id;
Tom Cherryf74503d2020-06-19 12:21:21 -0700126 uint16_t size = element.total_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800127 mSizes[log_id] += size;
128 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700129
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700130 // When caller adding a chatty entry, they will have already
131 // called add() and subtract() for each entry as they are
132 // evaluated and trimmed, thus recording size and number of
133 // elements, but we must recognize the manufactured dropped
134 // entry as not contributing to the lifetime totals.
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700135 if (element.dropped_count) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800136 ++mDroppedElements[log_id];
137 } else {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800138 mSizesTotal[log_id] += size;
Mark Salyzyn32962912016-09-12 10:29:17 -0700139 SizesTotal += size;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800140 ++mElementsTotal[log_id];
141 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700142
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700143 log_time stamp(element.realtime);
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700144 if (mNewest[log_id] < stamp) {
145 // A major time update invalidates the statistics :-(
146 log_time diff = stamp - mNewest[log_id];
147 mNewest[log_id] = stamp;
148
149 if (diff.tv_sec > hourSec) {
150 // approximate Do-Your-Best fixup
151 diff += mOldest[log_id];
152 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
153 diff = stamp;
154 }
155 if (diff <= stamp) {
156 mOldest[log_id] = diff;
157 if (mNewestDropped[log_id] < diff) {
158 mNewestDropped[log_id] = diff;
159 }
160 }
161 }
162 }
163
Mark Salyzynae4d9282014-10-15 08:49:39 -0700164 if (log_id == LOG_ID_KERNEL) {
165 return;
166 }
167
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700168 uidTable[log_id].Add(element.uid, element);
169 if (element.uid == AID_SYSTEM) {
170 pidSystemTable[log_id].Add(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700171 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700172
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700173 if (!enable) {
174 return;
175 }
176
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700177 pidTable.Add(element.pid, element);
178 tidTable.Add(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700179
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700180 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700181 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800182 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700183 securityTagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800184 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700185 tagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800186 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700187 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700188
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700189 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700190 tagNameTable.Add(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700191 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800192}
193
Tom Cherryf74503d2020-06-19 12:21:21 -0700194void LogStatistics::Subtract(LogStatisticsElement element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700195 auto lock = std::lock_guard{lock_};
Tom Cherryf74503d2020-06-19 12:21:21 -0700196
197 if (!track_total_size_) {
198 element.total_len = element.msg_len;
199 }
200
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700201 log_id_t log_id = element.log_id;
Tom Cherryf74503d2020-06-19 12:21:21 -0700202 uint16_t size = element.total_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800203 mSizes[log_id] -= size;
204 --mElements[log_id];
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700205 if (element.dropped_count) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700206 --mDroppedElements[log_id];
207 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700208
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700209 if (mOldest[log_id] < element.realtime) {
210 mOldest[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700211 }
212
Mark Salyzynae4d9282014-10-15 08:49:39 -0700213 if (log_id == LOG_ID_KERNEL) {
214 return;
215 }
216
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700217 uidTable[log_id].Subtract(element.uid, element);
218 if (element.uid == AID_SYSTEM) {
219 pidSystemTable[log_id].Subtract(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700220 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800221
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700222 if (!enable) {
223 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800224 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700225
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700226 pidTable.Subtract(element.pid, element);
227 tidTable.Subtract(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700228
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700229 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700230 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800231 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700232 securityTagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800233 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700234 tagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800235 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700236 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700237
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700238 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700239 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700240 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800241}
242
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700243// Atomically set an entry to drop
244// entry->setDropped(1) must follow this call, caller should do this explicitly.
Tom Cherryf74503d2020-06-19 12:21:21 -0700245void LogStatistics::Drop(LogStatisticsElement element) {
246 CHECK_EQ(element.dropped_count, 0U);
247
Tom Cherry64e90162020-05-07 14:44:43 -0700248 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700249 log_id_t log_id = element.log_id;
250 uint16_t size = element.msg_len;
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700251 mSizes[log_id] -= size;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700252 ++mDroppedElements[log_id];
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700253
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700254 if (mNewestDropped[log_id] < element.realtime) {
255 mNewestDropped[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700256 }
257
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700258 uidTable[log_id].Drop(element.uid, element);
259 if (element.uid == AID_SYSTEM) {
260 pidSystemTable[log_id].Drop(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700261 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700262
263 if (!enable) {
264 return;
265 }
266
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700267 pidTable.Drop(element.pid, element);
268 tidTable.Drop(element.tid, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700269
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700270 uint32_t tag = element.tag;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700271 if (tag) {
272 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700273 securityTagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700274 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700275 tagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700276 }
277 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700278
Tom Cherry9787f9a2020-05-19 19:01:16 -0700279 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700280}
281
Tom Cherryf74503d2020-06-19 12:21:21 -0700282void LogStatistics::Erase(LogStatisticsElement element) {
283 CHECK_GT(element.dropped_count, 0U);
284 CHECK_EQ(element.msg_len, 0U);
285
286 auto lock = std::lock_guard{lock_};
287
288 if (!track_total_size_) {
289 element.total_len = 0;
290 }
291
292 log_id_t log_id = element.log_id;
293 --mElements[log_id];
294 --mDroppedElements[log_id];
295 mSizes[log_id] -= element.total_len;
296
297 uidTable[log_id].Erase(element.uid, element);
298 if (element.uid == AID_SYSTEM) {
299 pidSystemTable[log_id].Erase(element.pid, element);
300 }
301
302 if (!enable) {
303 return;
304 }
305
306 pidTable.Erase(element.pid, element);
307 tidTable.Erase(element.tid, element);
308
309 uint32_t tag = element.tag;
310 if (tag) {
311 if (log_id == LOG_ID_SECURITY) {
312 securityTagTable.Erase(tag, element);
313 } else {
314 tagTable.Erase(tag, element);
315 }
316 }
317}
318
Tom Cherry64e90162020-05-07 14:44:43 -0700319const char* LogStatistics::UidToName(uid_t uid) const {
320 auto lock = std::lock_guard{lock_};
321 return UidToNameLocked(uid);
322}
323
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700324// caller must own and free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700325const char* LogStatistics::UidToNameLocked(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700326 // Local hard coded favourites
327 if (uid == AID_LOGD) {
328 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800329 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700330
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700331 // Android system
332 if (uid < AID_APP) {
333 // in bionic, thread safe as long as we copy the results
Mark Salyzyn501c3732017-03-10 14:31:54 -0800334 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700335 if (pwd) {
336 return strdup(pwd->pw_name);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700337 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800338 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700339
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700340 // Parse /data/system/packages.list
Jeff Sharkeydff44702016-12-13 11:55:19 -0700341 uid_t userId = uid % AID_USER_OFFSET;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800342 const char* name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700343 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
344 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
345 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700346 if (name) {
347 return name;
348 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700349
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700350 // Android application
351 if (uid >= AID_APP) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800352 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700353 if (pwd) {
354 return strdup(pwd->pw_name);
355 }
356 }
357
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700358 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn501c3732017-03-10 14:31:54 -0800359 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
360 ++it) {
361 const PidEntry& entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700362
Tom Cherry9787f9a2020-05-19 19:01:16 -0700363 if (entry.uid() == uid) {
364 const char* nameTmp = entry.name();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700365
Mark Salyzyn758058f2015-08-21 16:44:30 -0700366 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700367 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700368 name = strdup(nameTmp);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800369 } else if (fastcmp<strcmp>(name, nameTmp)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800370 free(const_cast<char*>(name));
Yi Kongc8d09dd2018-07-13 17:39:22 -0700371 name = nullptr;
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700372 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700373 }
374 }
375 }
376 }
377
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700378 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700379 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800380}
381
Tom Cherryb6b78e92020-05-07 09:13:12 -0700382template <typename TKey, typename TEntry>
383void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
384 int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700385 size_t* second_worst_sizes) const {
Tom Cherry4596b782020-06-03 13:49:24 -0700386 std::array<const TKey*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700387 std::array<const TEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700388 table.MaxEntries(AID_ROOT, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700389 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
390 return;
391 }
392 *worst_sizes = max_entries[0]->getSizes();
393 // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
394 // 100 characters.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700395 if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
Tom Cherry4596b782020-06-03 13:49:24 -0700396 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700397 *second_worst_sizes = max_entries[1]->getSizes();
398 if (*second_worst_sizes < threshold) {
399 *second_worst_sizes = threshold;
400 }
401 }
402}
403
404void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700405 size_t* second_worst_sizes) const {
406 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700407 WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
408}
409
410void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700411 size_t* second_worst_sizes) const {
412 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700413 WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
414}
415
416void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700417 size_t* second_worst_sizes) const {
418 auto lock = std::lock_guard{lock_};
Tom Cherry4596b782020-06-03 13:49:24 -0700419 std::array<const pid_t*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700420 std::array<const PidEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700421 pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700422 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
423 return;
424 }
425
Tom Cherry4596b782020-06-03 13:49:24 -0700426 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700427 *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
428}
429
Tom Cherry64e90162020-05-07 14:44:43 -0700430// Prune at most 10% of the log entries or maxPrune, whichever is less.
431bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
432 unsigned long* prune_rows) const {
433 static constexpr size_t kMinPrune = 4;
434 static constexpr size_t kMaxPrune = 256;
435
436 auto lock = std::lock_guard{lock_};
437 size_t sizes = mSizes[id];
438 if (sizes <= max_size) {
439 return false;
440 }
441 size_t size_over = sizes - ((max_size * 9) / 10);
442 size_t elements = mElements[id] - mDroppedElements[id];
443 size_t min_elements = elements / 100;
444 if (min_elements < kMinPrune) {
445 min_elements = kMinPrune;
446 }
447 *prune_rows = elements * size_over / sizes;
448 if (*prune_rows < min_elements) {
449 *prune_rows = min_elements;
450 }
451 if (*prune_rows > kMaxPrune) {
452 *prune_rows = kMaxPrune;
453 }
454
455 return true;
456}
457
Mark Salyzyn501c3732017-03-10 14:31:54 -0800458std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700459 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800460 return formatLine(android::base::StringPrintf(name.c_str(),
461 android_log_id_to_name(id)),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700462 std::string("Size"),
Mark Salyzyn501c3732017-03-10 14:31:54 -0800463 std::string(isprune ? "+/- Pruned" : "")) +
464 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700465 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800466}
467
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700468// Helper to truncate name, if too long, and add name dressings
Tom Cherry64e90162020-05-07 14:44:43 -0700469void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
470 size_t nameLen) const {
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700471 const char* allocNameTmp = nullptr;
Tom Cherry64e90162020-05-07 14:44:43 -0700472 if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700473 if (nameTmp) {
474 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700475 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
476 lenSpace - 2;
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700477 size_t lenNameTmp = strlen(nameTmp);
478 while ((len < lenNameTmp) && (lenSpace > 1)) {
479 ++len;
480 --lenSpace;
481 }
482 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
483 if (len < lenNameTmp) {
484 name += "...";
485 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
486 }
487 name += nameTmp;
488 free(const_cast<char*>(allocNameTmp));
489 }
490}
491
Tom Cherry4596b782020-06-03 13:49:24 -0700492std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
493 REQUIRES(stat.lock_) {
494 std::string name = android::base::StringPrintf("%u", uid);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700495 std::string size = android::base::StringPrintf("%zu", getSizes());
496
Tom Cherry4596b782020-06-03 13:49:24 -0700497 stat.FormatTmp(nullptr, uid, name, size, 6);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700498
Mark Salyzyn758058f2015-08-21 16:44:30 -0700499 std::string pruned = "";
Mark Salyzync723df82015-08-24 11:08:00 -0700500 if (worstUidEnabledForLogid(id)) {
501 size_t totalDropped = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800502 for (LogStatistics::uidTable_t::const_iterator it =
503 stat.uidTable[id].begin();
504 it != stat.uidTable[id].end(); ++it) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700505 totalDropped += it->second.dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700506 }
Tom Cherry64e90162020-05-07 14:44:43 -0700507 size_t sizes = stat.mSizes[id];
508 size_t totalSize = stat.mSizesTotal[id];
509 size_t totalElements = stat.mElementsTotal[id];
Mark Salyzyn501c3732017-03-10 14:31:54 -0800510 float totalVirtualSize =
511 (float)sizes + (float)totalDropped * totalSize / totalElements;
Mark Salyzync723df82015-08-24 11:08:00 -0700512 size_t entrySize = getSizes();
513 float virtualEntrySize = entrySize;
514 int realPermille = virtualEntrySize * 1000.0 / sizes;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700515 size_t dropped = dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700516 if (dropped) {
517 pruned = android::base::StringPrintf("%zu", dropped);
518 virtualEntrySize += (float)dropped * totalSize / totalElements;
519 }
520 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800521 int permille =
522 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
Mark Salyzync723df82015-08-24 11:08:00 -0700523 if ((permille < -1) || (1 < permille)) {
524 std::string change;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800525 const char* units = "%";
526 const char* prefix = (permille > 0) ? "+" : "";
Mark Salyzync723df82015-08-24 11:08:00 -0700527
528 if (permille > 999) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800529 permille = (permille + 1000) / 100; // Now tenths fold
Mark Salyzync723df82015-08-24 11:08:00 -0700530 units = "X";
531 prefix = "";
532 }
533 if ((-99 < permille) && (permille < 99)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800534 change = android::base::StringPrintf(
535 "%s%d.%u%s", prefix, permille / 10,
Mark Salyzync723df82015-08-24 11:08:00 -0700536 ((permille < 0) ? (-permille % 10) : (permille % 10)),
537 units);
538 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800539 change = android::base::StringPrintf(
540 "%s%d%s", prefix, (permille + 5) / 10, units);
Mark Salyzync723df82015-08-24 11:08:00 -0700541 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700542 ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
Mark Salyzync723df82015-08-24 11:08:00 -0700543 if ((spaces <= 0) && pruned.length()) {
544 spaces = 1;
545 }
Mark Salyzynd966e222016-12-19 22:23:03 +0000546 if (spaces > 0) {
Mark Salyzync723df82015-08-24 11:08:00 -0700547 change += android::base::StringPrintf("%*s", (int)spaces, "");
548 }
549 pruned = change + pruned;
550 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700551 }
552
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700553 std::string output = formatLine(name, size, pruned);
554
Tom Cherry4596b782020-06-03 13:49:24 -0700555 if (uid != AID_SYSTEM) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700556 return output;
557 }
558
559 static const size_t maximum_sorted_entries = 32;
Tom Cherry4596b782020-06-03 13:49:24 -0700560 std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
561 std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
562 stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700563
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700564 std::string byPid;
565 size_t index;
566 bool hasDropped = false;
567 for (index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700568 const PidEntry* entry = sorted_entries[index];
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700569 if (!entry) {
570 break;
571 }
572 if (entry->getSizes() <= (getSizes() / 100)) {
573 break;
574 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700575 if (entry->dropped_count()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700576 hasDropped = true;
577 }
Tom Cherry4596b782020-06-03 13:49:24 -0700578 byPid += entry->format(stat, id, *sorted_pids[index]);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700579 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800580 if (index > 1) { // print this only if interesting
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700581 std::string ditto("\" ");
Mark Salyzyn501c3732017-03-10 14:31:54 -0800582 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
583 hasDropped ? ditto : std::string(""));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700584 output += byPid;
585 }
586
587 return output;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700588}
589
Mark Salyzyn501c3732017-03-10 14:31:54 -0800590std::string PidEntry::formatHeader(const std::string& name,
591 log_id_t /* id */) const {
592 return formatLine(name, std::string("Size"), std::string("Pruned")) +
593 formatLine(std::string(" PID/UID COMMAND LINE"),
594 std::string("BYTES"), std::string("NUM"));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700595}
596
Tom Cherry4596b782020-06-03 13:49:24 -0700597std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700598 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700599 std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800600 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700601
Tom Cherry9787f9a2020-05-19 19:01:16 -0700602 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700603
Mark Salyzyn758058f2015-08-21 16:44:30 -0700604 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700605 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700606 if (dropped) {
607 pruned = android::base::StringPrintf("%zu", dropped);
608 }
609
610 return formatLine(name, size, pruned);
611}
612
Mark Salyzyn501c3732017-03-10 14:31:54 -0800613std::string TidEntry::formatHeader(const std::string& name,
614 log_id_t /* id */) const {
615 return formatLine(name, std::string("Size"), std::string("Pruned")) +
616 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700617 std::string("NUM"));
618}
619
Tom Cherry4596b782020-06-03 13:49:24 -0700620std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700621 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700622 std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800623 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700624
Tom Cherry9787f9a2020-05-19 19:01:16 -0700625 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700626
Mark Salyzyn758058f2015-08-21 16:44:30 -0700627 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700628 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700629 if (dropped) {
630 pruned = android::base::StringPrintf("%zu", dropped);
631 }
632
633 return formatLine(name, size, pruned);
634}
635
Mark Salyzyn501c3732017-03-10 14:31:54 -0800636std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700637 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800638 return formatLine(name, std::string("Size"),
639 std::string(isprune ? "Prune" : "")) +
640 formatLine(std::string(" TAG/UID TAGNAME"),
641 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700642}
643
Tom Cherry4596b782020-06-03 13:49:24 -0700644std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700645 std::string name;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700646 if (uid_ == (uid_t)-1) {
647 name = android::base::StringPrintf("%7u", key());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700648 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700649 name = android::base::StringPrintf("%7u/%u", key(), uid_);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700650 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700651 const char* nameTmp = this->name();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700652 if (nameTmp) {
653 name += android::base::StringPrintf(
Mark Salyzyn501c3732017-03-10 14:31:54 -0800654 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700655 }
656
Mark Salyzyn501c3732017-03-10 14:31:54 -0800657 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700658
659 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700660 size_t dropped = dropped_count();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700661 if (dropped) {
662 pruned = android::base::StringPrintf("%zu", dropped);
663 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700664
665 return formatLine(name, size, pruned);
666}
667
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700668std::string TagNameEntry::formatHeader(const std::string& name,
669 log_id_t /* id */) const {
670 return formatLine(name, std::string("Size"), std::string("")) +
671 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
672 std::string("BYTES"), std::string(""));
673}
674
Tom Cherryb0263af2020-06-03 15:38:32 -0700675std::string TagNameEntry::format(const LogStatistics&, log_id_t,
676 const std::string& key_name) const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700677 std::string name;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700678 std::string pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700679 if (pid_ != (pid_t)-1) {
680 pidstr = android::base::StringPrintf("%u", pid_);
681 if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700682 }
683 int len = 9 - pidstr.length();
684 if (len < 0) len = 0;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700685 if (tid_ == (pid_t)-1 || tid_ == pid_) {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700686 name = android::base::StringPrintf("%*s", len, "");
687 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700688 name = android::base::StringPrintf("%*u", len, tid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700689 }
690 name += pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700691 if (uid_ != (uid_t)-1) {
692 name += android::base::StringPrintf("/%u", uid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700693 }
694
695 std::string size = android::base::StringPrintf("%zu", getSizes());
696
Tom Cherry4596b782020-06-03 13:49:24 -0700697 const char* nameTmp = key_name.data();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700698 if (nameTmp) {
699 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700700 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
701 lenSpace - 2;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700702 size_t lenNameTmp = strlen(nameTmp);
703 while ((len < lenNameTmp) && (lenSpace > 1)) {
704 ++len;
705 --lenSpace;
706 }
707 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
708 if (len < lenNameTmp) {
709 name += "...";
710 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
711 }
712 name += nameTmp;
713 }
714
715 std::string pruned = "";
716
717 return formatLine(name, size, pruned);
718}
719
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700720static std::string formatMsec(uint64_t val) {
721 static const unsigned subsecDigits = 3;
722 static const uint64_t sec = MS_PER_SEC;
723
724 static const uint64_t minute = 60 * sec;
725 static const uint64_t hour = 60 * minute;
726 static const uint64_t day = 24 * hour;
727
728 std::string output;
729 if (val < sec) return output;
730
731 if (val >= day) {
732 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
733 val = (val % day) + day;
734 }
735 if (val >= minute) {
736 if (val >= hour) {
737 output += android::base::StringPrintf("%" PRIu64 ":",
738 (val / hour) % (day / hour));
739 }
740 output += android::base::StringPrintf(
741 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
742 (val / minute) % (hour / minute));
743 }
744 output +=
745 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
746 (val / sec) % (minute / sec));
747 val %= sec;
748 unsigned digits = subsecDigits;
749 while (digits && ((val % 10) == 0)) {
750 val /= 10;
751 --digits;
752 }
753 if (digits) {
754 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
755 }
756 return output;
757}
758
Tom Cherry64e90162020-05-07 14:44:43 -0700759template <typename TKey, typename TEntry>
760std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
761 pid_t pid, const std::string& name, log_id_t id) const
762 REQUIRES(lock_) {
763 static const size_t maximum_sorted_entries = 32;
764 std::string output;
Tom Cherry4596b782020-06-03 13:49:24 -0700765 std::array<const TKey*, maximum_sorted_entries> sorted_keys;
766 std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
767 table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
Tom Cherry64e90162020-05-07 14:44:43 -0700768 bool header_printed = false;
769 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700770 const TEntry* entry = sorted_entries[index];
Tom Cherry64e90162020-05-07 14:44:43 -0700771 if (!entry) {
772 break;
773 }
Tom Cherry4596b782020-06-03 13:49:24 -0700774 if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
Tom Cherry64e90162020-05-07 14:44:43 -0700775 break;
776 }
777 if (!header_printed) {
778 output += "\n\n";
779 output += entry->formatHeader(name, id);
780 header_printed = true;
781 }
Tom Cherry4596b782020-06-03 13:49:24 -0700782 output += entry->format(*this, id, *sorted_keys[index]);
Tom Cherry64e90162020-05-07 14:44:43 -0700783 }
784 return output;
785}
786
787std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
788 auto lock = std::lock_guard{lock_};
789
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700790 static const uint16_t spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800791
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700792 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800793
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700794 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700795 size_t oldLength;
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700796 int16_t spaces = 1;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700797
798 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700799 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700800 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700801 if (spaces < 0) spaces = 0;
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700802 output += android::base::StringPrintf("%*s%s", spaces, "",
803 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700804 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800805 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700806 if (spaces < 0) spaces = 0;
807 output += android::base::StringPrintf("%*sTotal", spaces, "");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800808
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700809 static const char TotalStr[] = "\nTotal";
810 spaces = 10 - strlen(TotalStr);
811 output += TotalStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800812
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700813 size_t totalSize = 0;
814 size_t totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700815 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700816 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700817 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700818 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700819 size_t szs = mSizesTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700820 totalSize += szs;
Tom Cherry64e90162020-05-07 14:44:43 -0700821 size_t els = mElementsTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700822 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800823 output +=
824 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700825 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800826 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700827 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800828 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
829 totalEls);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800830
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700831 static const char NowStr[] = "\nNow";
832 spaces = 10 - strlen(NowStr);
833 output += NowStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800834
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700835 totalSize = 0;
836 totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700837 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700838 if (!(logMask & (1 << id))) continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800839
Tom Cherry64e90162020-05-07 14:44:43 -0700840 size_t els = mElements[id];
Mark Salyzyn34facab2014-02-06 14:48:50 -0800841 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700842 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700843 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700844 size_t szs = mSizes[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700845 totalSize += szs;
846 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800847 output +=
848 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700849 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800850 }
851 spaces += spaces_total;
852 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700853 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800854 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
855 totalEls);
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700856
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700857 static const char SpanStr[] = "\nLogspan";
858 spaces = 10 - strlen(SpanStr);
859 output += SpanStr;
860
861 // Total reports the greater of the individual maximum time span, or the
862 // validated minimum start and maximum end time span if it makes sense.
863 uint64_t minTime = UINT64_MAX;
864 uint64_t maxTime = 0;
865 uint64_t maxSpan = 0;
866 totalSize = 0;
867
868 log_id_for_each(id) {
869 if (!(logMask & (1 << id))) continue;
870
871 // validity checking
872 uint64_t oldest = mOldest[id].msec();
873 uint64_t newest = mNewest[id].msec();
874 if (newest <= oldest) {
875 spaces += spaces_total;
876 continue;
877 }
878
879 uint64_t span = newest - oldest;
880 if (span > (monthSec * MS_PER_SEC)) {
881 spaces += spaces_total;
882 continue;
883 }
884
885 // total span
886 if (minTime > oldest) minTime = oldest;
887 if (maxTime < newest) maxTime = newest;
888 if (span > maxSpan) maxSpan = span;
889 totalSize += span;
890
891 uint64_t dropped = mNewestDropped[id].msec();
892 if (dropped < oldest) dropped = oldest;
893 if (dropped > newest) dropped = newest;
894
895 oldLength = output.length();
896 output += android::base::StringPrintf("%*s%s", spaces, "",
897 formatMsec(span).c_str());
898 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
899 if ((permille > 1) && (permille < 999)) {
900 output += android::base::StringPrintf("(%u", permille / 10);
901 permille %= 10;
902 if (permille) {
903 output += android::base::StringPrintf(".%u", permille);
904 }
905 output += android::base::StringPrintf("%%)");
906 }
907 spaces -= output.length() - oldLength;
908 spaces += spaces_total;
909 }
910 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
911 (maxTime > maxSpan)) {
912 maxSpan = maxTime;
913 }
914 if (spaces < 0) spaces = 0;
915 output += android::base::StringPrintf("%*s%s", spaces, "",
916 formatMsec(maxSpan).c_str());
917
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700918 static const char OverheadStr[] = "\nOverhead";
919 spaces = 10 - strlen(OverheadStr);
920 output += OverheadStr;
921
922 totalSize = 0;
923 log_id_for_each(id) {
924 if (!(logMask & (1 << id))) continue;
925
Tom Cherry64e90162020-05-07 14:44:43 -0700926 size_t els = mElements[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700927 if (els) {
928 oldLength = output.length();
929 if (spaces < 0) spaces = 0;
Tom Cherryf74503d2020-06-19 12:21:21 -0700930 size_t szs = 0;
931 if (overhead_[id]) {
932 szs = *overhead_[id];
933 } else if (track_total_size_) {
934 szs = mSizes[id];
935 } else {
936 // Legacy fallback for Chatty without track_total_size_
937 // Estimate the size of this element in the parent std::list<> by adding two void*'s
938 // corresponding to the next/prev pointers and aligning to 64 bit.
939 static const size_t overhead =
940 (sizeof(LogBufferElement) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) &
941 -sizeof(uint64_t);
942 szs = mSizes[id] + els * overhead;
943 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700944 totalSize += szs;
945 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
946 spaces -= output.length() - oldLength;
947 }
948 spaces += spaces_total;
949 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700950 totalSize += sizeOf();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700951 if (spaces < 0) spaces = 0;
952 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800953
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700954 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700955
Mark Salyzyn758058f2015-08-21 16:44:30 -0700956 std::string name;
957
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700958 // Chattiest by application (UID)
959 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700960 if (!(logMask & (1 << id))) continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700961
Mark Salyzyn501c3732017-03-10 14:31:54 -0800962 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
963 : "Logging for your UID in %s log buffer:";
Tom Cherry64e90162020-05-07 14:44:43 -0700964 output += FormatTable(uidTable[id], uid, pid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700965 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700966
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700967 if (enable) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800968 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
969 : "Logging for this PID:";
Tom Cherry64e90162020-05-07 14:44:43 -0700970 output += FormatTable(pidTable, uid, pid, name);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800971 name = "Chattiest TIDs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700972 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800973 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700974 output += FormatTable(tidTable, uid, pid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700975 }
976
Mark Salyzyn344bff42015-04-13 14:24:45 -0700977 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800978 name = "Chattiest events log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700979 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800980 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700981 output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700982 }
983
Mark Salyzyn083b0372015-12-04 10:59:45 -0800984 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800985 name = "Chattiest security log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700986 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800987 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700988 output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800989 }
990
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700991 if (enable) {
992 name = "Chattiest TAGs";
993 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
994 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700995 output += FormatTable(tagNameTable, uid, pid, name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700996 }
997
Mark Salyzyn73160ac2015-08-20 10:01:44 -0700998 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800999}
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001000
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001001namespace android {
1002
1003uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001004 char buffer[512];
1005 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
Tom Cherry9b4246d2020-06-17 11:40:55 -07001006 FILE* fp = fopen(buffer, "re");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001007 if (fp) {
1008 while (fgets(buffer, sizeof(buffer), fp)) {
Mark Salyzync4e48232017-05-04 13:54:46 -07001009 int uid = AID_LOGD;
1010 char space = 0;
1011 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
1012 isspace(space)) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001013 fclose(fp);
1014 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001015 }
1016 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001017 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001018 }
Mark Salyzyn501c3732017-03-10 14:31:54 -08001019 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001020}
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001021}
1022
Tom Cherry64e90162020-05-07 14:44:43 -07001023uid_t LogStatistics::PidToUid(pid_t pid) {
1024 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -07001025 return pidTable.Add(pid)->second.uid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001026}
1027
1028// caller must free character string
Tom Cherry64e90162020-05-07 14:44:43 -07001029const char* LogStatistics::PidToName(pid_t pid) const {
1030 auto lock = std::lock_guard{lock_};
Mark Salyzyn758058f2015-08-21 16:44:30 -07001031 // An inconvenient truth ... getName() can alter the object
Mark Salyzyn501c3732017-03-10 14:31:54 -08001032 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
Tom Cherry9787f9a2020-05-19 19:01:16 -07001033 const char* name = writablePidTable.Add(pid)->second.name();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -07001034 if (!name) {
Yi Kongc8d09dd2018-07-13 17:39:22 -07001035 return nullptr;
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001036 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -07001037 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001038}