blob: 87069b3ed2ac164bb9ef2a4a153407716688673b [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>
Tom Cherryec39a3f2020-07-09 09:51:16 -070029#include <vector>
Mark Salyzyn9af33ee2016-10-05 12:34:37 -070030
Tom Cherryf74503d2020-06-19 12:21:21 -070031#include <android-base/logging.h>
Tom Cherryec39a3f2020-07-09 09:51:16 -070032#include <android-base/strings.h>
Mark Salyzyn03bb7592017-04-14 09:46:57 -070033#include <private/android_logger.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080034
Tom Cherry3dd3ec32020-06-02 15:39:21 -070035#include "LogBufferElement.h"
36
Mark Salyzyn03bb7592017-04-14 09:46:57 -070037static const uint64_t hourSec = 60 * 60;
38static const uint64_t monthSec = 31 * 24 * hourSec;
39
Tom Cherry64e90162020-05-07 14:44:43 -070040std::atomic<size_t> LogStatistics::SizesTotal;
Mark Salyzyn32962912016-09-12 10:29:17 -070041
Tom Cherryb0263af2020-06-03 15:38:32 -070042static std::string TagNameKey(const LogStatisticsElement& element) {
43 if (IsBinary(element.log_id)) {
44 uint32_t tag = element.tag;
45 if (tag) {
46 const char* cp = android::tagToName(tag);
47 if (cp) {
48 return std::string(cp);
49 }
50 }
51 return android::base::StringPrintf("[%" PRIu32 "]", tag);
52 }
53 const char* msg = element.msg;
54 if (!msg) {
55 return "chatty";
56 }
57 ++msg;
58 uint16_t len = element.msg_len;
59 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
60 if (!len) {
61 return "<NULL>";
62 }
63 return std::string(msg, len);
64}
65
Tom Cherryec39a3f2020-07-09 09:51:16 -070066LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
67 std::optional<log_time> start_time)
Tom Cherryf74503d2020-06-19 12:21:21 -070068 : enable(enable_statistics), track_total_size_(track_total_size) {
Mark Salyzyn03bb7592017-04-14 09:46:57 -070069 log_time now(CLOCK_REALTIME);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070070 log_id_for_each(id) {
71 mSizes[id] = 0;
72 mElements[id] = 0;
Mark Salyzyn58b8be82015-09-30 07:40:09 -070073 mDroppedElements[id] = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070074 mSizesTotal[id] = 0;
75 mElementsTotal[id] = 0;
Tom Cherryec39a3f2020-07-09 09:51:16 -070076 if (start_time) {
77 mOldest[id] = *start_time;
78 mNewest[id] = *start_time;
79 } else {
80 mOldest[id] = now;
81 mNewest[id] = now;
82 }
Mark Salyzyn03bb7592017-04-14 09:46:57 -070083 mNewestDropped[id] = now;
Mark Salyzyn34facab2014-02-06 14:48:50 -080084 }
85}
86
Mark Salyzyn720f6d12015-03-16 08:26:05 -070087namespace android {
88
Mark Salyzyn501c3732017-03-10 14:31:54 -080089size_t sizesTotal() {
90 return LogStatistics::sizesTotal();
91}
Mark Salyzyn32962912016-09-12 10:29:17 -070092
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070093// caller must own and free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -080094char* pidToName(pid_t pid) {
Yi Kongc8d09dd2018-07-13 17:39:22 -070095 char* retval = nullptr;
Mark Salyzyn501c3732017-03-10 14:31:54 -080096 if (pid == 0) { // special case from auditd/klogd for kernel
Mark Salyzynae4d9282014-10-15 08:49:39 -070097 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070098 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070099 char buffer[512];
100 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
Tom Cherry9b4246d2020-06-17 11:40:55 -0700101 int fd = open(buffer, O_RDONLY | O_CLOEXEC);
Mark Salyzyn9a038632014-04-07 07:05:40 -0700102 if (fd >= 0) {
103 ssize_t ret = read(fd, buffer, sizeof(buffer));
104 if (ret > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800105 buffer[sizeof(buffer) - 1] = '\0';
Mark Salyzyn9a038632014-04-07 07:05:40 -0700106 // frameworks intermediate state
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800107 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700108 retval = strdup(buffer);
109 }
110 }
111 close(fd);
112 }
113 }
114 return retval;
115}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700116}
117
Tom Cherrya26f7df2020-05-19 17:48:42 -0700118void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
Tom Cherry64e90162020-05-07 14:44:43 -0700119 auto lock = std::lock_guard{lock_};
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700120
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700121 mSizesTotal[log_id] += size;
122 SizesTotal += size;
123 ++mElementsTotal[log_id];
124}
125
Tom Cherryf74503d2020-06-19 12:21:21 -0700126void LogStatistics::Add(LogStatisticsElement element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700127 auto lock = std::lock_guard{lock_};
Tom Cherryf74503d2020-06-19 12:21:21 -0700128
129 if (!track_total_size_) {
130 element.total_len = element.msg_len;
131 }
132
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700133 log_id_t log_id = element.log_id;
Tom Cherryf74503d2020-06-19 12:21:21 -0700134 uint16_t size = element.total_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800135 mSizes[log_id] += size;
136 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700137
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700138 // When caller adding a chatty entry, they will have already
139 // called add() and subtract() for each entry as they are
140 // evaluated and trimmed, thus recording size and number of
141 // elements, but we must recognize the manufactured dropped
142 // entry as not contributing to the lifetime totals.
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700143 if (element.dropped_count) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800144 ++mDroppedElements[log_id];
145 } else {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800146 mSizesTotal[log_id] += size;
Mark Salyzyn32962912016-09-12 10:29:17 -0700147 SizesTotal += size;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800148 ++mElementsTotal[log_id];
149 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700150
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700151 log_time stamp(element.realtime);
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700152 if (mNewest[log_id] < stamp) {
153 // A major time update invalidates the statistics :-(
154 log_time diff = stamp - mNewest[log_id];
155 mNewest[log_id] = stamp;
156
157 if (diff.tv_sec > hourSec) {
158 // approximate Do-Your-Best fixup
159 diff += mOldest[log_id];
160 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
161 diff = stamp;
162 }
163 if (diff <= stamp) {
164 mOldest[log_id] = diff;
165 if (mNewestDropped[log_id] < diff) {
166 mNewestDropped[log_id] = diff;
167 }
168 }
169 }
170 }
171
Mark Salyzynae4d9282014-10-15 08:49:39 -0700172 if (log_id == LOG_ID_KERNEL) {
173 return;
174 }
175
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700176 uidTable[log_id].Add(element.uid, element);
177 if (element.uid == AID_SYSTEM) {
178 pidSystemTable[log_id].Add(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700179 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700180
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700181 if (!enable) {
182 return;
183 }
184
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700185 pidTable.Add(element.pid, element);
186 tidTable.Add(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700187
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700188 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700189 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800190 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700191 securityTagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800192 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700193 tagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800194 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700195 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700196
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700197 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700198 tagNameTable.Add(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700199 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800200}
201
Tom Cherryf74503d2020-06-19 12:21:21 -0700202void LogStatistics::Subtract(LogStatisticsElement element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700203 auto lock = std::lock_guard{lock_};
Tom Cherryf74503d2020-06-19 12:21:21 -0700204
205 if (!track_total_size_) {
206 element.total_len = element.msg_len;
207 }
208
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700209 log_id_t log_id = element.log_id;
Tom Cherryf74503d2020-06-19 12:21:21 -0700210 uint16_t size = element.total_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800211 mSizes[log_id] -= size;
212 --mElements[log_id];
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700213 if (element.dropped_count) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700214 --mDroppedElements[log_id];
215 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700216
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700217 if (mOldest[log_id] < element.realtime) {
218 mOldest[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700219 }
220
Mark Salyzynae4d9282014-10-15 08:49:39 -0700221 if (log_id == LOG_ID_KERNEL) {
222 return;
223 }
224
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700225 uidTable[log_id].Subtract(element.uid, element);
226 if (element.uid == AID_SYSTEM) {
227 pidSystemTable[log_id].Subtract(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700228 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800229
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700230 if (!enable) {
231 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800232 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700233
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700234 pidTable.Subtract(element.pid, element);
235 tidTable.Subtract(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700236
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700237 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700238 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800239 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700240 securityTagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800241 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700242 tagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800243 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700244 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700245
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700246 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700247 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700248 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800249}
250
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700251// Atomically set an entry to drop
252// entry->setDropped(1) must follow this call, caller should do this explicitly.
Tom Cherryf74503d2020-06-19 12:21:21 -0700253void LogStatistics::Drop(LogStatisticsElement element) {
254 CHECK_EQ(element.dropped_count, 0U);
255
Tom Cherry64e90162020-05-07 14:44:43 -0700256 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700257 log_id_t log_id = element.log_id;
258 uint16_t size = element.msg_len;
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700259 mSizes[log_id] -= size;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700260 ++mDroppedElements[log_id];
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700261
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700262 if (mNewestDropped[log_id] < element.realtime) {
263 mNewestDropped[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700264 }
265
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700266 uidTable[log_id].Drop(element.uid, element);
267 if (element.uid == AID_SYSTEM) {
268 pidSystemTable[log_id].Drop(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700269 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700270
271 if (!enable) {
272 return;
273 }
274
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700275 pidTable.Drop(element.pid, element);
276 tidTable.Drop(element.tid, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700277
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700278 uint32_t tag = element.tag;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700279 if (tag) {
280 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700281 securityTagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700282 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700283 tagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700284 }
285 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700286
Tom Cherry9787f9a2020-05-19 19:01:16 -0700287 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700288}
289
Tom Cherryf74503d2020-06-19 12:21:21 -0700290void LogStatistics::Erase(LogStatisticsElement element) {
291 CHECK_GT(element.dropped_count, 0U);
292 CHECK_EQ(element.msg_len, 0U);
293
294 auto lock = std::lock_guard{lock_};
295
296 if (!track_total_size_) {
297 element.total_len = 0;
298 }
299
300 log_id_t log_id = element.log_id;
301 --mElements[log_id];
302 --mDroppedElements[log_id];
303 mSizes[log_id] -= element.total_len;
304
305 uidTable[log_id].Erase(element.uid, element);
306 if (element.uid == AID_SYSTEM) {
307 pidSystemTable[log_id].Erase(element.pid, element);
308 }
309
310 if (!enable) {
311 return;
312 }
313
314 pidTable.Erase(element.pid, element);
315 tidTable.Erase(element.tid, element);
316
317 uint32_t tag = element.tag;
318 if (tag) {
319 if (log_id == LOG_ID_SECURITY) {
320 securityTagTable.Erase(tag, element);
321 } else {
322 tagTable.Erase(tag, element);
323 }
324 }
325}
326
Tom Cherry64e90162020-05-07 14:44:43 -0700327const char* LogStatistics::UidToName(uid_t uid) const {
328 auto lock = std::lock_guard{lock_};
329 return UidToNameLocked(uid);
330}
331
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700332// caller must own and free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700333const char* LogStatistics::UidToNameLocked(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700334 // Local hard coded favourites
335 if (uid == AID_LOGD) {
336 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800337 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700338
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700339 // Android system
340 if (uid < AID_APP) {
341 // in bionic, thread safe as long as we copy the results
Mark Salyzyn501c3732017-03-10 14:31:54 -0800342 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700343 if (pwd) {
344 return strdup(pwd->pw_name);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700345 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800346 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700347
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700348 // Parse /data/system/packages.list
Jeff Sharkeydff44702016-12-13 11:55:19 -0700349 uid_t userId = uid % AID_USER_OFFSET;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800350 const char* name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700351 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
352 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
353 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700354 if (name) {
355 return name;
356 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700357
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700358 // Android application
359 if (uid >= AID_APP) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800360 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700361 if (pwd) {
362 return strdup(pwd->pw_name);
363 }
364 }
365
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700366 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn501c3732017-03-10 14:31:54 -0800367 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
368 ++it) {
369 const PidEntry& entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700370
Tom Cherry9787f9a2020-05-19 19:01:16 -0700371 if (entry.uid() == uid) {
372 const char* nameTmp = entry.name();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700373
Mark Salyzyn758058f2015-08-21 16:44:30 -0700374 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700375 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700376 name = strdup(nameTmp);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800377 } else if (fastcmp<strcmp>(name, nameTmp)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800378 free(const_cast<char*>(name));
Yi Kongc8d09dd2018-07-13 17:39:22 -0700379 name = nullptr;
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700380 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700381 }
382 }
383 }
384 }
385
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700386 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700387 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800388}
389
Tom Cherryb6b78e92020-05-07 09:13:12 -0700390template <typename TKey, typename TEntry>
391void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
392 int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700393 size_t* second_worst_sizes) const {
Tom Cherry4596b782020-06-03 13:49:24 -0700394 std::array<const TKey*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700395 std::array<const TEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700396 table.MaxEntries(AID_ROOT, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700397 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
398 return;
399 }
400 *worst_sizes = max_entries[0]->getSizes();
401 // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
402 // 100 characters.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700403 if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
Tom Cherry4596b782020-06-03 13:49:24 -0700404 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700405 *second_worst_sizes = max_entries[1]->getSizes();
406 if (*second_worst_sizes < threshold) {
407 *second_worst_sizes = threshold;
408 }
409 }
410}
411
412void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700413 size_t* second_worst_sizes) const {
414 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700415 WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
416}
417
418void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700419 size_t* second_worst_sizes) const {
420 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700421 WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
422}
423
424void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700425 size_t* second_worst_sizes) const {
426 auto lock = std::lock_guard{lock_};
Tom Cherry4596b782020-06-03 13:49:24 -0700427 std::array<const pid_t*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700428 std::array<const PidEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700429 pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700430 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
431 return;
432 }
433
Tom Cherry4596b782020-06-03 13:49:24 -0700434 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700435 *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
436}
437
Tom Cherry64e90162020-05-07 14:44:43 -0700438// Prune at most 10% of the log entries or maxPrune, whichever is less.
439bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
440 unsigned long* prune_rows) const {
441 static constexpr size_t kMinPrune = 4;
442 static constexpr size_t kMaxPrune = 256;
443
444 auto lock = std::lock_guard{lock_};
445 size_t sizes = mSizes[id];
446 if (sizes <= max_size) {
447 return false;
448 }
449 size_t size_over = sizes - ((max_size * 9) / 10);
450 size_t elements = mElements[id] - mDroppedElements[id];
451 size_t min_elements = elements / 100;
452 if (min_elements < kMinPrune) {
453 min_elements = kMinPrune;
454 }
455 *prune_rows = elements * size_over / sizes;
456 if (*prune_rows < min_elements) {
457 *prune_rows = min_elements;
458 }
459 if (*prune_rows > kMaxPrune) {
460 *prune_rows = kMaxPrune;
461 }
462
463 return true;
464}
465
Mark Salyzyn501c3732017-03-10 14:31:54 -0800466std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700467 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800468 return formatLine(android::base::StringPrintf(name.c_str(),
469 android_log_id_to_name(id)),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700470 std::string("Size"),
Mark Salyzyn501c3732017-03-10 14:31:54 -0800471 std::string(isprune ? "+/- Pruned" : "")) +
472 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700473 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800474}
475
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700476// Helper to truncate name, if too long, and add name dressings
Tom Cherry64e90162020-05-07 14:44:43 -0700477void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
478 size_t nameLen) const {
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700479 const char* allocNameTmp = nullptr;
Tom Cherry64e90162020-05-07 14:44:43 -0700480 if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700481 if (nameTmp) {
482 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700483 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
484 lenSpace - 2;
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700485 size_t lenNameTmp = strlen(nameTmp);
486 while ((len < lenNameTmp) && (lenSpace > 1)) {
487 ++len;
488 --lenSpace;
489 }
490 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
491 if (len < lenNameTmp) {
492 name += "...";
493 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
494 }
495 name += nameTmp;
496 free(const_cast<char*>(allocNameTmp));
497 }
498}
499
Tom Cherry4596b782020-06-03 13:49:24 -0700500std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
501 REQUIRES(stat.lock_) {
502 std::string name = android::base::StringPrintf("%u", uid);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700503 std::string size = android::base::StringPrintf("%zu", getSizes());
504
Tom Cherry4596b782020-06-03 13:49:24 -0700505 stat.FormatTmp(nullptr, uid, name, size, 6);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700506
Mark Salyzyn758058f2015-08-21 16:44:30 -0700507 std::string pruned = "";
Mark Salyzync723df82015-08-24 11:08:00 -0700508 if (worstUidEnabledForLogid(id)) {
509 size_t totalDropped = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800510 for (LogStatistics::uidTable_t::const_iterator it =
511 stat.uidTable[id].begin();
512 it != stat.uidTable[id].end(); ++it) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700513 totalDropped += it->second.dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700514 }
Tom Cherry64e90162020-05-07 14:44:43 -0700515 size_t sizes = stat.mSizes[id];
516 size_t totalSize = stat.mSizesTotal[id];
517 size_t totalElements = stat.mElementsTotal[id];
Mark Salyzyn501c3732017-03-10 14:31:54 -0800518 float totalVirtualSize =
519 (float)sizes + (float)totalDropped * totalSize / totalElements;
Mark Salyzync723df82015-08-24 11:08:00 -0700520 size_t entrySize = getSizes();
521 float virtualEntrySize = entrySize;
522 int realPermille = virtualEntrySize * 1000.0 / sizes;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700523 size_t dropped = dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700524 if (dropped) {
525 pruned = android::base::StringPrintf("%zu", dropped);
526 virtualEntrySize += (float)dropped * totalSize / totalElements;
527 }
528 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800529 int permille =
530 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
Mark Salyzync723df82015-08-24 11:08:00 -0700531 if ((permille < -1) || (1 < permille)) {
532 std::string change;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800533 const char* units = "%";
534 const char* prefix = (permille > 0) ? "+" : "";
Mark Salyzync723df82015-08-24 11:08:00 -0700535
536 if (permille > 999) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800537 permille = (permille + 1000) / 100; // Now tenths fold
Mark Salyzync723df82015-08-24 11:08:00 -0700538 units = "X";
539 prefix = "";
540 }
541 if ((-99 < permille) && (permille < 99)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800542 change = android::base::StringPrintf(
543 "%s%d.%u%s", prefix, permille / 10,
Mark Salyzync723df82015-08-24 11:08:00 -0700544 ((permille < 0) ? (-permille % 10) : (permille % 10)),
545 units);
546 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800547 change = android::base::StringPrintf(
548 "%s%d%s", prefix, (permille + 5) / 10, units);
Mark Salyzync723df82015-08-24 11:08:00 -0700549 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700550 ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
Mark Salyzync723df82015-08-24 11:08:00 -0700551 if ((spaces <= 0) && pruned.length()) {
552 spaces = 1;
553 }
Mark Salyzynd966e222016-12-19 22:23:03 +0000554 if (spaces > 0) {
Mark Salyzync723df82015-08-24 11:08:00 -0700555 change += android::base::StringPrintf("%*s", (int)spaces, "");
556 }
557 pruned = change + pruned;
558 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700559 }
560
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700561 std::string output = formatLine(name, size, pruned);
562
Tom Cherry4596b782020-06-03 13:49:24 -0700563 if (uid != AID_SYSTEM) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700564 return output;
565 }
566
567 static const size_t maximum_sorted_entries = 32;
Tom Cherry4596b782020-06-03 13:49:24 -0700568 std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
569 std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
570 stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700571
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700572 std::string byPid;
573 size_t index;
574 bool hasDropped = false;
575 for (index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700576 const PidEntry* entry = sorted_entries[index];
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700577 if (!entry) {
578 break;
579 }
580 if (entry->getSizes() <= (getSizes() / 100)) {
581 break;
582 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700583 if (entry->dropped_count()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700584 hasDropped = true;
585 }
Tom Cherry4596b782020-06-03 13:49:24 -0700586 byPid += entry->format(stat, id, *sorted_pids[index]);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700587 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800588 if (index > 1) { // print this only if interesting
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700589 std::string ditto("\" ");
Mark Salyzyn501c3732017-03-10 14:31:54 -0800590 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
591 hasDropped ? ditto : std::string(""));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700592 output += byPid;
593 }
594
595 return output;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700596}
597
Mark Salyzyn501c3732017-03-10 14:31:54 -0800598std::string PidEntry::formatHeader(const std::string& name,
599 log_id_t /* id */) const {
600 return formatLine(name, std::string("Size"), std::string("Pruned")) +
601 formatLine(std::string(" PID/UID COMMAND LINE"),
602 std::string("BYTES"), std::string("NUM"));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700603}
604
Tom Cherry4596b782020-06-03 13:49:24 -0700605std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700606 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700607 std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800608 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700609
Tom Cherry9787f9a2020-05-19 19:01:16 -0700610 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700611
Mark Salyzyn758058f2015-08-21 16:44:30 -0700612 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700613 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700614 if (dropped) {
615 pruned = android::base::StringPrintf("%zu", dropped);
616 }
617
618 return formatLine(name, size, pruned);
619}
620
Mark Salyzyn501c3732017-03-10 14:31:54 -0800621std::string TidEntry::formatHeader(const std::string& name,
622 log_id_t /* id */) const {
623 return formatLine(name, std::string("Size"), std::string("Pruned")) +
624 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700625 std::string("NUM"));
626}
627
Tom Cherry4596b782020-06-03 13:49:24 -0700628std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700629 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700630 std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800631 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700632
Tom Cherry9787f9a2020-05-19 19:01:16 -0700633 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700634
Mark Salyzyn758058f2015-08-21 16:44:30 -0700635 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700636 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700637 if (dropped) {
638 pruned = android::base::StringPrintf("%zu", dropped);
639 }
640
641 return formatLine(name, size, pruned);
642}
643
Mark Salyzyn501c3732017-03-10 14:31:54 -0800644std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700645 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800646 return formatLine(name, std::string("Size"),
647 std::string(isprune ? "Prune" : "")) +
648 formatLine(std::string(" TAG/UID TAGNAME"),
649 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700650}
651
Tom Cherry4596b782020-06-03 13:49:24 -0700652std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700653 std::string name;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700654 if (uid_ == (uid_t)-1) {
655 name = android::base::StringPrintf("%7u", key());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700656 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700657 name = android::base::StringPrintf("%7u/%u", key(), uid_);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700658 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700659 const char* nameTmp = this->name();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700660 if (nameTmp) {
661 name += android::base::StringPrintf(
Mark Salyzyn501c3732017-03-10 14:31:54 -0800662 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700663 }
664
Mark Salyzyn501c3732017-03-10 14:31:54 -0800665 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700666
667 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700668 size_t dropped = dropped_count();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700669 if (dropped) {
670 pruned = android::base::StringPrintf("%zu", dropped);
671 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700672
673 return formatLine(name, size, pruned);
674}
675
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700676std::string TagNameEntry::formatHeader(const std::string& name,
677 log_id_t /* id */) const {
678 return formatLine(name, std::string("Size"), std::string("")) +
679 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
680 std::string("BYTES"), std::string(""));
681}
682
Tom Cherryb0263af2020-06-03 15:38:32 -0700683std::string TagNameEntry::format(const LogStatistics&, log_id_t,
684 const std::string& key_name) const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700685 std::string name;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700686 std::string pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700687 if (pid_ != (pid_t)-1) {
688 pidstr = android::base::StringPrintf("%u", pid_);
689 if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700690 }
691 int len = 9 - pidstr.length();
692 if (len < 0) len = 0;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700693 if (tid_ == (pid_t)-1 || tid_ == pid_) {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700694 name = android::base::StringPrintf("%*s", len, "");
695 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700696 name = android::base::StringPrintf("%*u", len, tid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700697 }
698 name += pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700699 if (uid_ != (uid_t)-1) {
700 name += android::base::StringPrintf("/%u", uid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700701 }
702
703 std::string size = android::base::StringPrintf("%zu", getSizes());
704
Tom Cherry4596b782020-06-03 13:49:24 -0700705 const char* nameTmp = key_name.data();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700706 if (nameTmp) {
707 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700708 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
709 lenSpace - 2;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700710 size_t lenNameTmp = strlen(nameTmp);
711 while ((len < lenNameTmp) && (lenSpace > 1)) {
712 ++len;
713 --lenSpace;
714 }
715 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
716 if (len < lenNameTmp) {
717 name += "...";
718 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
719 }
720 name += nameTmp;
721 }
722
723 std::string pruned = "";
724
725 return formatLine(name, size, pruned);
726}
727
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700728static std::string formatMsec(uint64_t val) {
729 static const unsigned subsecDigits = 3;
730 static const uint64_t sec = MS_PER_SEC;
731
732 static const uint64_t minute = 60 * sec;
733 static const uint64_t hour = 60 * minute;
734 static const uint64_t day = 24 * hour;
735
736 std::string output;
737 if (val < sec) return output;
738
739 if (val >= day) {
740 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
741 val = (val % day) + day;
742 }
743 if (val >= minute) {
744 if (val >= hour) {
745 output += android::base::StringPrintf("%" PRIu64 ":",
746 (val / hour) % (day / hour));
747 }
748 output += android::base::StringPrintf(
749 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
750 (val / minute) % (hour / minute));
751 }
752 output +=
753 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
754 (val / sec) % (minute / sec));
755 val %= sec;
756 unsigned digits = subsecDigits;
757 while (digits && ((val % 10) == 0)) {
758 val /= 10;
759 --digits;
760 }
761 if (digits) {
762 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
763 }
764 return output;
765}
766
Tom Cherry64e90162020-05-07 14:44:43 -0700767template <typename TKey, typename TEntry>
768std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
769 pid_t pid, const std::string& name, log_id_t id) const
770 REQUIRES(lock_) {
771 static const size_t maximum_sorted_entries = 32;
772 std::string output;
Tom Cherry4596b782020-06-03 13:49:24 -0700773 std::array<const TKey*, maximum_sorted_entries> sorted_keys;
774 std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
775 table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
Tom Cherry64e90162020-05-07 14:44:43 -0700776 bool header_printed = false;
777 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700778 const TEntry* entry = sorted_entries[index];
Tom Cherry64e90162020-05-07 14:44:43 -0700779 if (!entry) {
780 break;
781 }
Tom Cherry4596b782020-06-03 13:49:24 -0700782 if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
Tom Cherry64e90162020-05-07 14:44:43 -0700783 break;
784 }
785 if (!header_printed) {
786 output += "\n\n";
787 output += entry->formatHeader(name, id);
788 header_printed = true;
789 }
Tom Cherry4596b782020-06-03 13:49:24 -0700790 output += entry->format(*this, id, *sorted_keys[index]);
Tom Cherry64e90162020-05-07 14:44:43 -0700791 }
792 return output;
793}
794
Tom Cherryec39a3f2020-07-09 09:51:16 -0700795std::string LogStatistics::ReportInteresting() const {
796 auto lock = std::lock_guard{lock_};
797
798 std::vector<std::string> items;
799
800 log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
801
802 log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
803
804 log_id_for_each(i) {
805 items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
806 }
807
808 log_id_for_each(i) {
809 uint64_t oldest = mOldest[i].msec() / 1000;
810 uint64_t newest = mNewest[i].msec() / 1000;
811
812 int span = newest - oldest;
813
814 items.emplace_back(std::to_string(span));
815 }
816
817 return android::base::Join(items, ",");
818}
819
Tom Cherry64e90162020-05-07 14:44:43 -0700820std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
821 auto lock = std::lock_guard{lock_};
822
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700823 static const uint16_t spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800824
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700825 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800826
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700827 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700828 size_t oldLength;
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700829 int16_t spaces = 1;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700830
831 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700832 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700833 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700834 if (spaces < 0) spaces = 0;
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700835 output += android::base::StringPrintf("%*s%s", spaces, "",
836 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700837 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800838 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700839 if (spaces < 0) spaces = 0;
840 output += android::base::StringPrintf("%*sTotal", spaces, "");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800841
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700842 static const char TotalStr[] = "\nTotal";
843 spaces = 10 - strlen(TotalStr);
844 output += TotalStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800845
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700846 size_t totalSize = 0;
847 size_t totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700848 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700849 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700850 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700851 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700852 size_t szs = mSizesTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700853 totalSize += szs;
Tom Cherry64e90162020-05-07 14:44:43 -0700854 size_t els = mElementsTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700855 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800856 output +=
857 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700858 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800859 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700860 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800861 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
862 totalEls);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800863
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700864 static const char NowStr[] = "\nNow";
865 spaces = 10 - strlen(NowStr);
866 output += NowStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800867
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700868 totalSize = 0;
869 totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700870 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700871 if (!(logMask & (1 << id))) continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800872
Tom Cherry64e90162020-05-07 14:44:43 -0700873 size_t els = mElements[id];
Mark Salyzyn34facab2014-02-06 14:48:50 -0800874 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700875 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700876 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700877 size_t szs = mSizes[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700878 totalSize += szs;
879 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800880 output +=
881 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700882 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800883 }
884 spaces += spaces_total;
885 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700886 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800887 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
888 totalEls);
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700889
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700890 static const char SpanStr[] = "\nLogspan";
891 spaces = 10 - strlen(SpanStr);
892 output += SpanStr;
893
894 // Total reports the greater of the individual maximum time span, or the
895 // validated minimum start and maximum end time span if it makes sense.
896 uint64_t minTime = UINT64_MAX;
897 uint64_t maxTime = 0;
898 uint64_t maxSpan = 0;
899 totalSize = 0;
900
901 log_id_for_each(id) {
902 if (!(logMask & (1 << id))) continue;
903
904 // validity checking
905 uint64_t oldest = mOldest[id].msec();
906 uint64_t newest = mNewest[id].msec();
907 if (newest <= oldest) {
908 spaces += spaces_total;
909 continue;
910 }
911
912 uint64_t span = newest - oldest;
913 if (span > (monthSec * MS_PER_SEC)) {
914 spaces += spaces_total;
915 continue;
916 }
917
918 // total span
919 if (minTime > oldest) minTime = oldest;
920 if (maxTime < newest) maxTime = newest;
921 if (span > maxSpan) maxSpan = span;
922 totalSize += span;
923
924 uint64_t dropped = mNewestDropped[id].msec();
925 if (dropped < oldest) dropped = oldest;
926 if (dropped > newest) dropped = newest;
927
928 oldLength = output.length();
929 output += android::base::StringPrintf("%*s%s", spaces, "",
930 formatMsec(span).c_str());
931 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
932 if ((permille > 1) && (permille < 999)) {
933 output += android::base::StringPrintf("(%u", permille / 10);
934 permille %= 10;
935 if (permille) {
936 output += android::base::StringPrintf(".%u", permille);
937 }
938 output += android::base::StringPrintf("%%)");
939 }
940 spaces -= output.length() - oldLength;
941 spaces += spaces_total;
942 }
943 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
944 (maxTime > maxSpan)) {
945 maxSpan = maxTime;
946 }
947 if (spaces < 0) spaces = 0;
948 output += android::base::StringPrintf("%*s%s", spaces, "",
949 formatMsec(maxSpan).c_str());
950
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700951 static const char OverheadStr[] = "\nOverhead";
952 spaces = 10 - strlen(OverheadStr);
953 output += OverheadStr;
954
955 totalSize = 0;
956 log_id_for_each(id) {
957 if (!(logMask & (1 << id))) continue;
958
Tom Cherry64e90162020-05-07 14:44:43 -0700959 size_t els = mElements[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700960 if (els) {
961 oldLength = output.length();
962 if (spaces < 0) spaces = 0;
Tom Cherryf74503d2020-06-19 12:21:21 -0700963 size_t szs = 0;
964 if (overhead_[id]) {
965 szs = *overhead_[id];
966 } else if (track_total_size_) {
967 szs = mSizes[id];
968 } else {
969 // Legacy fallback for Chatty without track_total_size_
970 // Estimate the size of this element in the parent std::list<> by adding two void*'s
971 // corresponding to the next/prev pointers and aligning to 64 bit.
972 static const size_t overhead =
973 (sizeof(LogBufferElement) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) &
974 -sizeof(uint64_t);
975 szs = mSizes[id] + els * overhead;
976 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700977 totalSize += szs;
978 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
979 spaces -= output.length() - oldLength;
980 }
981 spaces += spaces_total;
982 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700983 totalSize += sizeOf();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700984 if (spaces < 0) spaces = 0;
985 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800986
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700987 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700988
Mark Salyzyn758058f2015-08-21 16:44:30 -0700989 std::string name;
990
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700991 // Chattiest by application (UID)
992 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700993 if (!(logMask & (1 << id))) continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700994
Mark Salyzyn501c3732017-03-10 14:31:54 -0800995 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
996 : "Logging for your UID in %s log buffer:";
Tom Cherry64e90162020-05-07 14:44:43 -0700997 output += FormatTable(uidTable[id], uid, pid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700998 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700999
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001000 if (enable) {
Mark Salyzyn501c3732017-03-10 14:31:54 -08001001 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
1002 : "Logging for this PID:";
Tom Cherry64e90162020-05-07 14:44:43 -07001003 output += FormatTable(pidTable, uid, pid, name);
Mark Salyzynee3b8382015-12-17 09:58:43 -08001004 name = "Chattiest TIDs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -07001005 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -08001006 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -07001007 output += FormatTable(tidTable, uid, pid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -07001008 }
1009
Mark Salyzyn344bff42015-04-13 14:24:45 -07001010 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -08001011 name = "Chattiest events log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -07001012 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -08001013 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -07001014 output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -07001015 }
1016
Mark Salyzyn083b0372015-12-04 10:59:45 -08001017 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -08001018 name = "Chattiest security log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -07001019 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -08001020 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -07001021 output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
Mark Salyzyn083b0372015-12-04 10:59:45 -08001022 }
1023
Mark Salyzynf99a7d62017-04-19 14:39:21 -07001024 if (enable) {
1025 name = "Chattiest TAGs";
1026 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
1027 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -07001028 output += FormatTable(tagNameTable, uid, pid, name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -07001029 }
1030
Mark Salyzyn73160ac2015-08-20 10:01:44 -07001031 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -08001032}
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001033
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001034namespace android {
1035
1036uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001037 char buffer[512];
1038 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
Tom Cherry9b4246d2020-06-17 11:40:55 -07001039 FILE* fp = fopen(buffer, "re");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001040 if (fp) {
1041 while (fgets(buffer, sizeof(buffer), fp)) {
Mark Salyzync4e48232017-05-04 13:54:46 -07001042 int uid = AID_LOGD;
1043 char space = 0;
1044 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
1045 isspace(space)) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001046 fclose(fp);
1047 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001048 }
1049 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -07001050 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001051 }
Mark Salyzyn501c3732017-03-10 14:31:54 -08001052 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -07001053}
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001054}
1055
Tom Cherry64e90162020-05-07 14:44:43 -07001056uid_t LogStatistics::PidToUid(pid_t pid) {
1057 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -07001058 return pidTable.Add(pid)->second.uid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001059}
1060
1061// caller must free character string
Tom Cherry64e90162020-05-07 14:44:43 -07001062const char* LogStatistics::PidToName(pid_t pid) const {
1063 auto lock = std::lock_guard{lock_};
Mark Salyzyn758058f2015-08-21 16:44:30 -07001064 // An inconvenient truth ... getName() can alter the object
Mark Salyzyn501c3732017-03-10 14:31:54 -08001065 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
Tom Cherry9787f9a2020-05-19 19:01:16 -07001066 const char* name = writablePidTable.Add(pid)->second.name();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -07001067 if (!name) {
Yi Kongc8d09dd2018-07-13 17:39:22 -07001068 return nullptr;
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001069 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -07001070 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -07001071}