blob: a2acab7aafec4cbec467a15b4905fcad5ffe3c8c [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
Mark Salyzyn03bb7592017-04-14 09:46:57 -070030#include <private/android_logger.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080031
Mark Salyzyn03bb7592017-04-14 09:46:57 -070032static const uint64_t hourSec = 60 * 60;
33static const uint64_t monthSec = 31 * 24 * hourSec;
34
Tom Cherry64e90162020-05-07 14:44:43 -070035std::atomic<size_t> LogStatistics::SizesTotal;
Mark Salyzyn32962912016-09-12 10:29:17 -070036
Tom Cherry64e90162020-05-07 14:44:43 -070037LogStatistics::LogStatistics(bool enable_statistics) : enable(enable_statistics) {
Mark Salyzyn03bb7592017-04-14 09:46:57 -070038 log_time now(CLOCK_REALTIME);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070039 log_id_for_each(id) {
40 mSizes[id] = 0;
41 mElements[id] = 0;
Mark Salyzyn58b8be82015-09-30 07:40:09 -070042 mDroppedElements[id] = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070043 mSizesTotal[id] = 0;
44 mElementsTotal[id] = 0;
Mark Salyzyn03bb7592017-04-14 09:46:57 -070045 mOldest[id] = now;
46 mNewest[id] = now;
47 mNewestDropped[id] = now;
Mark Salyzyn34facab2014-02-06 14:48:50 -080048 }
49}
50
Mark Salyzyn720f6d12015-03-16 08:26:05 -070051namespace android {
52
Mark Salyzyn501c3732017-03-10 14:31:54 -080053size_t sizesTotal() {
54 return LogStatistics::sizesTotal();
55}
Mark Salyzyn32962912016-09-12 10:29:17 -070056
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070057// caller must own and free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -080058char* pidToName(pid_t pid) {
Yi Kongc8d09dd2018-07-13 17:39:22 -070059 char* retval = nullptr;
Mark Salyzyn501c3732017-03-10 14:31:54 -080060 if (pid == 0) { // special case from auditd/klogd for kernel
Mark Salyzynae4d9282014-10-15 08:49:39 -070061 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070062 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070063 char buffer[512];
64 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
65 int fd = open(buffer, O_RDONLY);
66 if (fd >= 0) {
67 ssize_t ret = read(fd, buffer, sizeof(buffer));
68 if (ret > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -080069 buffer[sizeof(buffer) - 1] = '\0';
Mark Salyzyn9a038632014-04-07 07:05:40 -070070 // frameworks intermediate state
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -080071 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070072 retval = strdup(buffer);
73 }
74 }
75 close(fd);
76 }
77 }
78 return retval;
79}
Mark Salyzyn720f6d12015-03-16 08:26:05 -070080}
81
Tom Cherrya26f7df2020-05-19 17:48:42 -070082void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
Tom Cherry64e90162020-05-07 14:44:43 -070083 auto lock = std::lock_guard{lock_};
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070084
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070085 mSizesTotal[log_id] += size;
86 SizesTotal += size;
87 ++mElementsTotal[log_id];
88}
89
Tom Cherry9787f9a2020-05-19 19:01:16 -070090void LogStatistics::Add(const LogBufferElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -070091 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -070092 log_id_t log_id = element.log_id();
93 uint16_t size = element.msg_len();
Mark Salyzyn34facab2014-02-06 14:48:50 -080094 mSizes[log_id] += size;
95 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070096
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070097 // When caller adding a chatty entry, they will have already
98 // called add() and subtract() for each entry as they are
99 // evaluated and trimmed, thus recording size and number of
100 // elements, but we must recognize the manufactured dropped
101 // entry as not contributing to the lifetime totals.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700102 if (element.dropped_count()) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800103 ++mDroppedElements[log_id];
104 } else {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800105 mSizesTotal[log_id] += size;
Mark Salyzyn32962912016-09-12 10:29:17 -0700106 SizesTotal += size;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800107 ++mElementsTotal[log_id];
108 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700109
Tom Cherry9787f9a2020-05-19 19:01:16 -0700110 log_time stamp(element.realtime());
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700111 if (mNewest[log_id] < stamp) {
112 // A major time update invalidates the statistics :-(
113 log_time diff = stamp - mNewest[log_id];
114 mNewest[log_id] = stamp;
115
116 if (diff.tv_sec > hourSec) {
117 // approximate Do-Your-Best fixup
118 diff += mOldest[log_id];
119 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
120 diff = stamp;
121 }
122 if (diff <= stamp) {
123 mOldest[log_id] = diff;
124 if (mNewestDropped[log_id] < diff) {
125 mNewestDropped[log_id] = diff;
126 }
127 }
128 }
129 }
130
Mark Salyzynae4d9282014-10-15 08:49:39 -0700131 if (log_id == LOG_ID_KERNEL) {
132 return;
133 }
134
Tom Cherry9787f9a2020-05-19 19:01:16 -0700135 uidTable[log_id].Add(element.uid(), element);
136 if (element.uid() == AID_SYSTEM) {
137 pidSystemTable[log_id].Add(element.pid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700138 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700139
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700140 if (!enable) {
141 return;
142 }
143
Tom Cherry9787f9a2020-05-19 19:01:16 -0700144 pidTable.Add(element.pid(), element);
145 tidTable.Add(element.tid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700146
Tom Cherry9787f9a2020-05-19 19:01:16 -0700147 uint32_t tag = element.GetTag();
Mark Salyzyn344bff42015-04-13 14:24:45 -0700148 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800149 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700150 securityTagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800151 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700152 tagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800153 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700154 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700155
Tom Cherry9787f9a2020-05-19 19:01:16 -0700156 if (!element.dropped_count()) {
157 tagNameTable.Add(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700158 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800159}
160
Tom Cherry9787f9a2020-05-19 19:01:16 -0700161void LogStatistics::Subtract(const LogBufferElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700162 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -0700163 log_id_t log_id = element.log_id();
164 uint16_t size = element.msg_len();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800165 mSizes[log_id] -= size;
166 --mElements[log_id];
Tom Cherry9787f9a2020-05-19 19:01:16 -0700167 if (element.dropped_count()) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700168 --mDroppedElements[log_id];
169 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700170
Tom Cherry9787f9a2020-05-19 19:01:16 -0700171 if (mOldest[log_id] < element.realtime()) {
172 mOldest[log_id] = element.realtime();
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700173 }
174
Mark Salyzynae4d9282014-10-15 08:49:39 -0700175 if (log_id == LOG_ID_KERNEL) {
176 return;
177 }
178
Tom Cherry9787f9a2020-05-19 19:01:16 -0700179 uidTable[log_id].Subtract(element.uid(), element);
180 if (element.uid() == AID_SYSTEM) {
181 pidSystemTable[log_id].Subtract(element.pid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700182 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800183
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700184 if (!enable) {
185 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800186 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700187
Tom Cherry9787f9a2020-05-19 19:01:16 -0700188 pidTable.Subtract(element.pid(), element);
189 tidTable.Subtract(element.tid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700190
Tom Cherry9787f9a2020-05-19 19:01:16 -0700191 uint32_t tag = element.GetTag();
Mark Salyzyn344bff42015-04-13 14:24:45 -0700192 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800193 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700194 securityTagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800195 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700196 tagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800197 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700198 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700199
Tom Cherry9787f9a2020-05-19 19:01:16 -0700200 if (!element.dropped_count()) {
201 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700202 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800203}
204
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700205// Atomically set an entry to drop
206// entry->setDropped(1) must follow this call, caller should do this explicitly.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700207void LogStatistics::Drop(const LogBufferElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700208 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -0700209 log_id_t log_id = element.log_id();
210 uint16_t size = element.msg_len();
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700211 mSizes[log_id] -= size;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700212 ++mDroppedElements[log_id];
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700213
Tom Cherry9787f9a2020-05-19 19:01:16 -0700214 if (mNewestDropped[log_id] < element.realtime()) {
215 mNewestDropped[log_id] = element.realtime();
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700216 }
217
Tom Cherry9787f9a2020-05-19 19:01:16 -0700218 uidTable[log_id].Drop(element.uid(), element);
219 if (element.uid() == AID_SYSTEM) {
220 pidSystemTable[log_id].Drop(element.pid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700221 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700222
223 if (!enable) {
224 return;
225 }
226
Tom Cherry9787f9a2020-05-19 19:01:16 -0700227 pidTable.Drop(element.pid(), element);
228 tidTable.Drop(element.tid(), element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700229
Tom Cherry9787f9a2020-05-19 19:01:16 -0700230 uint32_t tag = element.GetTag();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700231 if (tag) {
232 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700233 securityTagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700234 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700235 tagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700236 }
237 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700238
Tom Cherry9787f9a2020-05-19 19:01:16 -0700239 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700240}
241
Tom Cherry64e90162020-05-07 14:44:43 -0700242const char* LogStatistics::UidToName(uid_t uid) const {
243 auto lock = std::lock_guard{lock_};
244 return UidToNameLocked(uid);
245}
246
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700247// caller must own and free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700248const char* LogStatistics::UidToNameLocked(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700249 // Local hard coded favourites
250 if (uid == AID_LOGD) {
251 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800252 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700253
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700254 // Android system
255 if (uid < AID_APP) {
256 // in bionic, thread safe as long as we copy the results
Mark Salyzyn501c3732017-03-10 14:31:54 -0800257 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700258 if (pwd) {
259 return strdup(pwd->pw_name);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700260 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800261 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700262
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700263 // Parse /data/system/packages.list
Jeff Sharkeydff44702016-12-13 11:55:19 -0700264 uid_t userId = uid % AID_USER_OFFSET;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800265 const char* name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700266 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
267 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
268 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700269 if (name) {
270 return name;
271 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700272
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700273 // Android application
274 if (uid >= AID_APP) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800275 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700276 if (pwd) {
277 return strdup(pwd->pw_name);
278 }
279 }
280
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700281 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn501c3732017-03-10 14:31:54 -0800282 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
283 ++it) {
284 const PidEntry& entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700285
Tom Cherry9787f9a2020-05-19 19:01:16 -0700286 if (entry.uid() == uid) {
287 const char* nameTmp = entry.name();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700288
Mark Salyzyn758058f2015-08-21 16:44:30 -0700289 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700290 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700291 name = strdup(nameTmp);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800292 } else if (fastcmp<strcmp>(name, nameTmp)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800293 free(const_cast<char*>(name));
Yi Kongc8d09dd2018-07-13 17:39:22 -0700294 name = nullptr;
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700295 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700296 }
297 }
298 }
299 }
300
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700301 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700302 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800303}
304
Tom Cherryb6b78e92020-05-07 09:13:12 -0700305template <typename TKey, typename TEntry>
306void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
307 int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700308 size_t* second_worst_sizes) const {
Tom Cherryb6b78e92020-05-07 09:13:12 -0700309 std::array<const TEntry*, 2> max_entries;
310 table.MaxEntries(AID_ROOT, 0, &max_entries);
311 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
312 return;
313 }
314 *worst_sizes = max_entries[0]->getSizes();
315 // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
316 // 100 characters.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700317 if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
318 *worst = max_entries[0]->key();
Tom Cherryb6b78e92020-05-07 09:13:12 -0700319 *second_worst_sizes = max_entries[1]->getSizes();
320 if (*second_worst_sizes < threshold) {
321 *second_worst_sizes = threshold;
322 }
323 }
324}
325
326void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700327 size_t* second_worst_sizes) const {
328 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700329 WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
330}
331
332void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700333 size_t* second_worst_sizes) const {
334 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700335 WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
336}
337
338void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700339 size_t* second_worst_sizes) const {
340 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700341 std::array<const PidEntry*, 2> max_entries;
342 pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
343 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
344 return;
345 }
346
Tom Cherry9787f9a2020-05-19 19:01:16 -0700347 *worst = max_entries[0]->key();
Tom Cherryb6b78e92020-05-07 09:13:12 -0700348 *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
349}
350
Tom Cherry64e90162020-05-07 14:44:43 -0700351// Prune at most 10% of the log entries or maxPrune, whichever is less.
352bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
353 unsigned long* prune_rows) const {
354 static constexpr size_t kMinPrune = 4;
355 static constexpr size_t kMaxPrune = 256;
356
357 auto lock = std::lock_guard{lock_};
358 size_t sizes = mSizes[id];
359 if (sizes <= max_size) {
360 return false;
361 }
362 size_t size_over = sizes - ((max_size * 9) / 10);
363 size_t elements = mElements[id] - mDroppedElements[id];
364 size_t min_elements = elements / 100;
365 if (min_elements < kMinPrune) {
366 min_elements = kMinPrune;
367 }
368 *prune_rows = elements * size_over / sizes;
369 if (*prune_rows < min_elements) {
370 *prune_rows = min_elements;
371 }
372 if (*prune_rows > kMaxPrune) {
373 *prune_rows = kMaxPrune;
374 }
375
376 return true;
377}
378
Mark Salyzyn501c3732017-03-10 14:31:54 -0800379std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700380 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800381 return formatLine(android::base::StringPrintf(name.c_str(),
382 android_log_id_to_name(id)),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700383 std::string("Size"),
Mark Salyzyn501c3732017-03-10 14:31:54 -0800384 std::string(isprune ? "+/- Pruned" : "")) +
385 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700386 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800387}
388
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700389// Helper to truncate name, if too long, and add name dressings
Tom Cherry64e90162020-05-07 14:44:43 -0700390void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
391 size_t nameLen) const {
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700392 const char* allocNameTmp = nullptr;
Tom Cherry64e90162020-05-07 14:44:43 -0700393 if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700394 if (nameTmp) {
395 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700396 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
397 lenSpace - 2;
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700398 size_t lenNameTmp = strlen(nameTmp);
399 while ((len < lenNameTmp) && (lenSpace > 1)) {
400 ++len;
401 --lenSpace;
402 }
403 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
404 if (len < lenNameTmp) {
405 name += "...";
406 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
407 }
408 name += nameTmp;
409 free(const_cast<char*>(allocNameTmp));
410 }
411}
412
Tom Cherry64e90162020-05-07 14:44:43 -0700413std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const REQUIRES(stat.lock_) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700414 std::string name = android::base::StringPrintf("%u", uid_);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700415 std::string size = android::base::StringPrintf("%zu", getSizes());
416
Tom Cherry9787f9a2020-05-19 19:01:16 -0700417 stat.FormatTmp(nullptr, uid_, name, size, 6);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700418
Mark Salyzyn758058f2015-08-21 16:44:30 -0700419 std::string pruned = "";
Mark Salyzync723df82015-08-24 11:08:00 -0700420 if (worstUidEnabledForLogid(id)) {
421 size_t totalDropped = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800422 for (LogStatistics::uidTable_t::const_iterator it =
423 stat.uidTable[id].begin();
424 it != stat.uidTable[id].end(); ++it) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700425 totalDropped += it->second.dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700426 }
Tom Cherry64e90162020-05-07 14:44:43 -0700427 size_t sizes = stat.mSizes[id];
428 size_t totalSize = stat.mSizesTotal[id];
429 size_t totalElements = stat.mElementsTotal[id];
Mark Salyzyn501c3732017-03-10 14:31:54 -0800430 float totalVirtualSize =
431 (float)sizes + (float)totalDropped * totalSize / totalElements;
Mark Salyzync723df82015-08-24 11:08:00 -0700432 size_t entrySize = getSizes();
433 float virtualEntrySize = entrySize;
434 int realPermille = virtualEntrySize * 1000.0 / sizes;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700435 size_t dropped = dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700436 if (dropped) {
437 pruned = android::base::StringPrintf("%zu", dropped);
438 virtualEntrySize += (float)dropped * totalSize / totalElements;
439 }
440 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800441 int permille =
442 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
Mark Salyzync723df82015-08-24 11:08:00 -0700443 if ((permille < -1) || (1 < permille)) {
444 std::string change;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800445 const char* units = "%";
446 const char* prefix = (permille > 0) ? "+" : "";
Mark Salyzync723df82015-08-24 11:08:00 -0700447
448 if (permille > 999) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800449 permille = (permille + 1000) / 100; // Now tenths fold
Mark Salyzync723df82015-08-24 11:08:00 -0700450 units = "X";
451 prefix = "";
452 }
453 if ((-99 < permille) && (permille < 99)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800454 change = android::base::StringPrintf(
455 "%s%d.%u%s", prefix, permille / 10,
Mark Salyzync723df82015-08-24 11:08:00 -0700456 ((permille < 0) ? (-permille % 10) : (permille % 10)),
457 units);
458 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800459 change = android::base::StringPrintf(
460 "%s%d%s", prefix, (permille + 5) / 10, units);
Mark Salyzync723df82015-08-24 11:08:00 -0700461 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700462 ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
Mark Salyzync723df82015-08-24 11:08:00 -0700463 if ((spaces <= 0) && pruned.length()) {
464 spaces = 1;
465 }
Mark Salyzynd966e222016-12-19 22:23:03 +0000466 if (spaces > 0) {
Mark Salyzync723df82015-08-24 11:08:00 -0700467 change += android::base::StringPrintf("%*s", (int)spaces, "");
468 }
469 pruned = change + pruned;
470 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700471 }
472
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700473 std::string output = formatLine(name, size, pruned);
474
Tom Cherry9787f9a2020-05-19 19:01:16 -0700475 if (uid_ != AID_SYSTEM) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700476 return output;
477 }
478
479 static const size_t maximum_sorted_entries = 32;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700480 std::array<const PidEntry*, maximum_sorted_entries> sorted;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700481 stat.pidSystemTable[id].MaxEntries(uid_, 0, &sorted);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700482
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700483 std::string byPid;
484 size_t index;
485 bool hasDropped = false;
486 for (index = 0; index < maximum_sorted_entries; ++index) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800487 const PidEntry* entry = sorted[index];
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700488 if (!entry) {
489 break;
490 }
491 if (entry->getSizes() <= (getSizes() / 100)) {
492 break;
493 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700494 if (entry->dropped_count()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700495 hasDropped = true;
496 }
497 byPid += entry->format(stat, id);
498 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800499 if (index > 1) { // print this only if interesting
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700500 std::string ditto("\" ");
Mark Salyzyn501c3732017-03-10 14:31:54 -0800501 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
502 hasDropped ? ditto : std::string(""));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700503 output += byPid;
504 }
505
506 return output;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700507}
508
Mark Salyzyn501c3732017-03-10 14:31:54 -0800509std::string PidEntry::formatHeader(const std::string& name,
510 log_id_t /* id */) const {
511 return formatLine(name, std::string("Size"), std::string("Pruned")) +
512 formatLine(std::string(" PID/UID COMMAND LINE"),
513 std::string("BYTES"), std::string("NUM"));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700514}
515
Tom Cherry64e90162020-05-07 14:44:43 -0700516std::string PidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
517 REQUIRES(stat.lock_) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700518 std::string name = android::base::StringPrintf("%5u/%u", pid_, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800519 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700520
Tom Cherry9787f9a2020-05-19 19:01:16 -0700521 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700522
Mark Salyzyn758058f2015-08-21 16:44:30 -0700523 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700524 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700525 if (dropped) {
526 pruned = android::base::StringPrintf("%zu", dropped);
527 }
528
529 return formatLine(name, size, pruned);
530}
531
Mark Salyzyn501c3732017-03-10 14:31:54 -0800532std::string TidEntry::formatHeader(const std::string& name,
533 log_id_t /* id */) const {
534 return formatLine(name, std::string("Size"), std::string("Pruned")) +
535 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700536 std::string("NUM"));
537}
538
Tom Cherry64e90162020-05-07 14:44:43 -0700539std::string TidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
540 REQUIRES(stat.lock_) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700541 std::string name = android::base::StringPrintf("%5u/%u", tid(), uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800542 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700543
Tom Cherry9787f9a2020-05-19 19:01:16 -0700544 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700545
Mark Salyzyn758058f2015-08-21 16:44:30 -0700546 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700547 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700548 if (dropped) {
549 pruned = android::base::StringPrintf("%zu", dropped);
550 }
551
552 return formatLine(name, size, pruned);
553}
554
Mark Salyzyn501c3732017-03-10 14:31:54 -0800555std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700556 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800557 return formatLine(name, std::string("Size"),
558 std::string(isprune ? "Prune" : "")) +
559 formatLine(std::string(" TAG/UID TAGNAME"),
560 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700561}
562
Mark Salyzyn501c3732017-03-10 14:31:54 -0800563std::string TagEntry::format(const LogStatistics& /* stat */,
564 log_id_t /* id */) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700565 std::string name;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700566 if (uid_ == (uid_t)-1) {
567 name = android::base::StringPrintf("%7u", key());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700568 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700569 name = android::base::StringPrintf("%7u/%u", key(), uid_);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700570 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700571 const char* nameTmp = this->name();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700572 if (nameTmp) {
573 name += android::base::StringPrintf(
Mark Salyzyn501c3732017-03-10 14:31:54 -0800574 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700575 }
576
Mark Salyzyn501c3732017-03-10 14:31:54 -0800577 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700578
579 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700580 size_t dropped = dropped_count();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700581 if (dropped) {
582 pruned = android::base::StringPrintf("%zu", dropped);
583 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700584
585 return formatLine(name, size, pruned);
586}
587
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700588std::string TagNameEntry::formatHeader(const std::string& name,
589 log_id_t /* id */) const {
590 return formatLine(name, std::string("Size"), std::string("")) +
591 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
592 std::string("BYTES"), std::string(""));
593}
594
595std::string TagNameEntry::format(const LogStatistics& /* stat */,
596 log_id_t /* id */) const {
597 std::string name;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700598 std::string pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700599 if (pid_ != (pid_t)-1) {
600 pidstr = android::base::StringPrintf("%u", pid_);
601 if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700602 }
603 int len = 9 - pidstr.length();
604 if (len < 0) len = 0;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700605 if (tid_ == (pid_t)-1 || tid_ == pid_) {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700606 name = android::base::StringPrintf("%*s", len, "");
607 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700608 name = android::base::StringPrintf("%*u", len, tid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700609 }
610 name += pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700611 if (uid_ != (uid_t)-1) {
612 name += android::base::StringPrintf("/%u", uid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700613 }
614
615 std::string size = android::base::StringPrintf("%zu", getSizes());
616
Tom Cherry9787f9a2020-05-19 19:01:16 -0700617 const char* nameTmp = this->name();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700618 if (nameTmp) {
619 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700620 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
621 lenSpace - 2;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700622 size_t lenNameTmp = strlen(nameTmp);
623 while ((len < lenNameTmp) && (lenSpace > 1)) {
624 ++len;
625 --lenSpace;
626 }
627 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
628 if (len < lenNameTmp) {
629 name += "...";
630 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
631 }
632 name += nameTmp;
633 }
634
635 std::string pruned = "";
636
637 return formatLine(name, size, pruned);
638}
639
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700640static std::string formatMsec(uint64_t val) {
641 static const unsigned subsecDigits = 3;
642 static const uint64_t sec = MS_PER_SEC;
643
644 static const uint64_t minute = 60 * sec;
645 static const uint64_t hour = 60 * minute;
646 static const uint64_t day = 24 * hour;
647
648 std::string output;
649 if (val < sec) return output;
650
651 if (val >= day) {
652 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
653 val = (val % day) + day;
654 }
655 if (val >= minute) {
656 if (val >= hour) {
657 output += android::base::StringPrintf("%" PRIu64 ":",
658 (val / hour) % (day / hour));
659 }
660 output += android::base::StringPrintf(
661 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
662 (val / minute) % (hour / minute));
663 }
664 output +=
665 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
666 (val / sec) % (minute / sec));
667 val %= sec;
668 unsigned digits = subsecDigits;
669 while (digits && ((val % 10) == 0)) {
670 val /= 10;
671 --digits;
672 }
673 if (digits) {
674 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
675 }
676 return output;
677}
678
Tom Cherry64e90162020-05-07 14:44:43 -0700679template <typename TKey, typename TEntry>
680std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
681 pid_t pid, const std::string& name, log_id_t id) const
682 REQUIRES(lock_) {
683 static const size_t maximum_sorted_entries = 32;
684 std::string output;
685 std::array<const TEntry*, maximum_sorted_entries> sorted;
686 table.MaxEntries(uid, pid, &sorted);
687 bool header_printed = false;
688 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
689 const TEntry* entry = sorted[index];
690 if (!entry) {
691 break;
692 }
693 if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
694 break;
695 }
696 if (!header_printed) {
697 output += "\n\n";
698 output += entry->formatHeader(name, id);
699 header_printed = true;
700 }
701 output += entry->format(*this, id);
702 }
703 return output;
704}
705
706std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
707 auto lock = std::lock_guard{lock_};
708
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700709 static const uint16_t spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800710
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700711 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800712
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700713 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700714 size_t oldLength;
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700715 int16_t spaces = 1;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700716
717 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700718 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700719 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700720 if (spaces < 0) spaces = 0;
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700721 output += android::base::StringPrintf("%*s%s", spaces, "",
722 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700723 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800724 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700725 if (spaces < 0) spaces = 0;
726 output += android::base::StringPrintf("%*sTotal", spaces, "");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800727
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700728 static const char TotalStr[] = "\nTotal";
729 spaces = 10 - strlen(TotalStr);
730 output += TotalStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800731
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700732 size_t totalSize = 0;
733 size_t totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700734 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700735 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700736 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700737 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700738 size_t szs = mSizesTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700739 totalSize += szs;
Tom Cherry64e90162020-05-07 14:44:43 -0700740 size_t els = mElementsTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700741 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800742 output +=
743 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700744 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800745 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700746 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800747 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
748 totalEls);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800749
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700750 static const char NowStr[] = "\nNow";
751 spaces = 10 - strlen(NowStr);
752 output += NowStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800753
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700754 totalSize = 0;
755 totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700756 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700757 if (!(logMask & (1 << id))) continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800758
Tom Cherry64e90162020-05-07 14:44:43 -0700759 size_t els = mElements[id];
Mark Salyzyn34facab2014-02-06 14:48:50 -0800760 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700761 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700762 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700763 size_t szs = mSizes[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700764 totalSize += szs;
765 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800766 output +=
767 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700768 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800769 }
770 spaces += spaces_total;
771 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700772 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800773 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
774 totalEls);
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700775
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700776 static const char SpanStr[] = "\nLogspan";
777 spaces = 10 - strlen(SpanStr);
778 output += SpanStr;
779
780 // Total reports the greater of the individual maximum time span, or the
781 // validated minimum start and maximum end time span if it makes sense.
782 uint64_t minTime = UINT64_MAX;
783 uint64_t maxTime = 0;
784 uint64_t maxSpan = 0;
785 totalSize = 0;
786
787 log_id_for_each(id) {
788 if (!(logMask & (1 << id))) continue;
789
790 // validity checking
791 uint64_t oldest = mOldest[id].msec();
792 uint64_t newest = mNewest[id].msec();
793 if (newest <= oldest) {
794 spaces += spaces_total;
795 continue;
796 }
797
798 uint64_t span = newest - oldest;
799 if (span > (monthSec * MS_PER_SEC)) {
800 spaces += spaces_total;
801 continue;
802 }
803
804 // total span
805 if (minTime > oldest) minTime = oldest;
806 if (maxTime < newest) maxTime = newest;
807 if (span > maxSpan) maxSpan = span;
808 totalSize += span;
809
810 uint64_t dropped = mNewestDropped[id].msec();
811 if (dropped < oldest) dropped = oldest;
812 if (dropped > newest) dropped = newest;
813
814 oldLength = output.length();
815 output += android::base::StringPrintf("%*s%s", spaces, "",
816 formatMsec(span).c_str());
817 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
818 if ((permille > 1) && (permille < 999)) {
819 output += android::base::StringPrintf("(%u", permille / 10);
820 permille %= 10;
821 if (permille) {
822 output += android::base::StringPrintf(".%u", permille);
823 }
824 output += android::base::StringPrintf("%%)");
825 }
826 spaces -= output.length() - oldLength;
827 spaces += spaces_total;
828 }
829 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
830 (maxTime > maxSpan)) {
831 maxSpan = maxTime;
832 }
833 if (spaces < 0) spaces = 0;
834 output += android::base::StringPrintf("%*s%s", spaces, "",
835 formatMsec(maxSpan).c_str());
836
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700837 static const char OverheadStr[] = "\nOverhead";
838 spaces = 10 - strlen(OverheadStr);
839 output += OverheadStr;
840
841 totalSize = 0;
842 log_id_for_each(id) {
843 if (!(logMask & (1 << id))) continue;
844
Tom Cherry64e90162020-05-07 14:44:43 -0700845 size_t els = mElements[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700846 if (els) {
847 oldLength = output.length();
848 if (spaces < 0) spaces = 0;
849 // estimate the std::list overhead.
850 static const size_t overhead =
851 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
Mark Salyzyn501c3732017-03-10 14:31:54 -0800852 -sizeof(uint64_t)) +
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700853 sizeof(std::list<LogBufferElement*>);
Tom Cherry64e90162020-05-07 14:44:43 -0700854 size_t szs = mSizes[id] + els * overhead;
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700855 totalSize += szs;
856 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
857 spaces -= output.length() - oldLength;
858 }
859 spaces += spaces_total;
860 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700861 totalSize += sizeOf();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700862 if (spaces < 0) spaces = 0;
863 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800864
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700865 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700866
Mark Salyzyn758058f2015-08-21 16:44:30 -0700867 std::string name;
868
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700869 // Chattiest by application (UID)
870 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700871 if (!(logMask & (1 << id))) continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700872
Mark Salyzyn501c3732017-03-10 14:31:54 -0800873 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
874 : "Logging for your UID in %s log buffer:";
Tom Cherry64e90162020-05-07 14:44:43 -0700875 output += FormatTable(uidTable[id], uid, pid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700876 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700877
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700878 if (enable) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800879 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
880 : "Logging for this PID:";
Tom Cherry64e90162020-05-07 14:44:43 -0700881 output += FormatTable(pidTable, uid, pid, name);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800882 name = "Chattiest TIDs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700883 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800884 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700885 output += FormatTable(tidTable, uid, pid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700886 }
887
Mark Salyzyn344bff42015-04-13 14:24:45 -0700888 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800889 name = "Chattiest events log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700890 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800891 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700892 output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700893 }
894
Mark Salyzyn083b0372015-12-04 10:59:45 -0800895 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800896 name = "Chattiest security log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700897 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800898 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700899 output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800900 }
901
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700902 if (enable) {
903 name = "Chattiest TAGs";
904 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
905 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700906 output += FormatTable(tagNameTable, uid, pid, name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700907 }
908
Mark Salyzyn73160ac2015-08-20 10:01:44 -0700909 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800910}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700911
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700912namespace android {
913
914uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700915 char buffer[512];
916 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800917 FILE* fp = fopen(buffer, "r");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700918 if (fp) {
919 while (fgets(buffer, sizeof(buffer), fp)) {
Mark Salyzync4e48232017-05-04 13:54:46 -0700920 int uid = AID_LOGD;
921 char space = 0;
922 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
923 isspace(space)) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700924 fclose(fp);
925 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700926 }
927 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700928 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700929 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800930 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700931}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700932}
933
Tom Cherry64e90162020-05-07 14:44:43 -0700934uid_t LogStatistics::PidToUid(pid_t pid) {
935 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -0700936 return pidTable.Add(pid)->second.uid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700937}
938
939// caller must free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700940const char* LogStatistics::PidToName(pid_t pid) const {
941 auto lock = std::lock_guard{lock_};
Mark Salyzyn758058f2015-08-21 16:44:30 -0700942 // An inconvenient truth ... getName() can alter the object
Mark Salyzyn501c3732017-03-10 14:31:54 -0800943 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700944 const char* name = writablePidTable.Add(pid)->second.name();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700945 if (!name) {
Yi Kongc8d09dd2018-07-13 17:39:22 -0700946 return nullptr;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700947 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700948 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700949}