blob: 625cbdec4302e82077bba70767e03b5f8ae03afc [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
Tom Cherry3dd3ec32020-06-02 15:39:21 -070032#include "LogBufferElement.h"
33
Mark Salyzyn03bb7592017-04-14 09:46:57 -070034static const uint64_t hourSec = 60 * 60;
35static const uint64_t monthSec = 31 * 24 * hourSec;
36
Tom Cherry64e90162020-05-07 14:44:43 -070037std::atomic<size_t> LogStatistics::SizesTotal;
Mark Salyzyn32962912016-09-12 10:29:17 -070038
Tom Cherry64e90162020-05-07 14:44:43 -070039LogStatistics::LogStatistics(bool enable_statistics) : enable(enable_statistics) {
Mark Salyzyn03bb7592017-04-14 09:46:57 -070040 log_time now(CLOCK_REALTIME);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070041 log_id_for_each(id) {
42 mSizes[id] = 0;
43 mElements[id] = 0;
Mark Salyzyn58b8be82015-09-30 07:40:09 -070044 mDroppedElements[id] = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070045 mSizesTotal[id] = 0;
46 mElementsTotal[id] = 0;
Mark Salyzyn03bb7592017-04-14 09:46:57 -070047 mOldest[id] = now;
48 mNewest[id] = now;
49 mNewestDropped[id] = now;
Mark Salyzyn34facab2014-02-06 14:48:50 -080050 }
51}
52
Mark Salyzyn720f6d12015-03-16 08:26:05 -070053namespace android {
54
Mark Salyzyn501c3732017-03-10 14:31:54 -080055size_t sizesTotal() {
56 return LogStatistics::sizesTotal();
57}
Mark Salyzyn32962912016-09-12 10:29:17 -070058
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070059// caller must own and free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -080060char* pidToName(pid_t pid) {
Yi Kongc8d09dd2018-07-13 17:39:22 -070061 char* retval = nullptr;
Mark Salyzyn501c3732017-03-10 14:31:54 -080062 if (pid == 0) { // special case from auditd/klogd for kernel
Mark Salyzynae4d9282014-10-15 08:49:39 -070063 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070064 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070065 char buffer[512];
66 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
67 int fd = open(buffer, O_RDONLY);
68 if (fd >= 0) {
69 ssize_t ret = read(fd, buffer, sizeof(buffer));
70 if (ret > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -080071 buffer[sizeof(buffer) - 1] = '\0';
Mark Salyzyn9a038632014-04-07 07:05:40 -070072 // frameworks intermediate state
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -080073 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070074 retval = strdup(buffer);
75 }
76 }
77 close(fd);
78 }
79 }
80 return retval;
81}
Mark Salyzyn720f6d12015-03-16 08:26:05 -070082}
83
Tom Cherrya26f7df2020-05-19 17:48:42 -070084void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
Tom Cherry64e90162020-05-07 14:44:43 -070085 auto lock = std::lock_guard{lock_};
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070086
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070087 mSizesTotal[log_id] += size;
88 SizesTotal += size;
89 ++mElementsTotal[log_id];
90}
91
Tom Cherry3dd3ec32020-06-02 15:39:21 -070092void LogStatistics::Add(const LogStatisticsElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -070093 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -070094 log_id_t log_id = element.log_id;
95 uint16_t size = element.msg_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -080096 mSizes[log_id] += size;
97 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070098
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070099 // When caller adding a chatty entry, they will have already
100 // called add() and subtract() for each entry as they are
101 // evaluated and trimmed, thus recording size and number of
102 // elements, but we must recognize the manufactured dropped
103 // entry as not contributing to the lifetime totals.
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700104 if (element.dropped_count) {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800105 ++mDroppedElements[log_id];
106 } else {
Mark Salyzyna2c02222016-12-13 10:31:29 -0800107 mSizesTotal[log_id] += size;
Mark Salyzyn32962912016-09-12 10:29:17 -0700108 SizesTotal += size;
Mark Salyzyna2c02222016-12-13 10:31:29 -0800109 ++mElementsTotal[log_id];
110 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700111
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700112 log_time stamp(element.realtime);
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700113 if (mNewest[log_id] < stamp) {
114 // A major time update invalidates the statistics :-(
115 log_time diff = stamp - mNewest[log_id];
116 mNewest[log_id] = stamp;
117
118 if (diff.tv_sec > hourSec) {
119 // approximate Do-Your-Best fixup
120 diff += mOldest[log_id];
121 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
122 diff = stamp;
123 }
124 if (diff <= stamp) {
125 mOldest[log_id] = diff;
126 if (mNewestDropped[log_id] < diff) {
127 mNewestDropped[log_id] = diff;
128 }
129 }
130 }
131 }
132
Mark Salyzynae4d9282014-10-15 08:49:39 -0700133 if (log_id == LOG_ID_KERNEL) {
134 return;
135 }
136
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700137 uidTable[log_id].Add(element.uid, element);
138 if (element.uid == AID_SYSTEM) {
139 pidSystemTable[log_id].Add(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700140 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700141
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700142 if (!enable) {
143 return;
144 }
145
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700146 pidTable.Add(element.pid, element);
147 tidTable.Add(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700148
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700149 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700150 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800151 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700152 securityTagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800153 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700154 tagTable.Add(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800155 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700156 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700157
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700158 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700159 tagNameTable.Add(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700160 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800161}
162
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700163void LogStatistics::Subtract(const LogStatisticsElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700164 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700165 log_id_t log_id = element.log_id;
166 uint16_t size = element.msg_len;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800167 mSizes[log_id] -= size;
168 --mElements[log_id];
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700169 if (element.dropped_count) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700170 --mDroppedElements[log_id];
171 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700172
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700173 if (mOldest[log_id] < element.realtime) {
174 mOldest[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700175 }
176
Mark Salyzynae4d9282014-10-15 08:49:39 -0700177 if (log_id == LOG_ID_KERNEL) {
178 return;
179 }
180
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700181 uidTable[log_id].Subtract(element.uid, element);
182 if (element.uid == AID_SYSTEM) {
183 pidSystemTable[log_id].Subtract(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700184 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800185
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700186 if (!enable) {
187 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800188 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700189
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700190 pidTable.Subtract(element.pid, element);
191 tidTable.Subtract(element.tid, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700192
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700193 uint32_t tag = element.tag;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700194 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800195 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700196 securityTagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800197 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700198 tagTable.Subtract(tag, element);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800199 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700200 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700201
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700202 if (!element.dropped_count) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700203 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700204 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800205}
206
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700207// Atomically set an entry to drop
208// entry->setDropped(1) must follow this call, caller should do this explicitly.
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700209void LogStatistics::Drop(const LogStatisticsElement& element) {
Tom Cherry64e90162020-05-07 14:44:43 -0700210 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700211 log_id_t log_id = element.log_id;
212 uint16_t size = element.msg_len;
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700213 mSizes[log_id] -= size;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700214 ++mDroppedElements[log_id];
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700215
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700216 if (mNewestDropped[log_id] < element.realtime) {
217 mNewestDropped[log_id] = element.realtime;
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700218 }
219
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700220 uidTable[log_id].Drop(element.uid, element);
221 if (element.uid == AID_SYSTEM) {
222 pidSystemTable[log_id].Drop(element.pid, element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700223 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700224
225 if (!enable) {
226 return;
227 }
228
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700229 pidTable.Drop(element.pid, element);
230 tidTable.Drop(element.tid, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700231
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700232 uint32_t tag = element.tag;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700233 if (tag) {
234 if (log_id == LOG_ID_SECURITY) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700235 securityTagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700236 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700237 tagTable.Drop(tag, element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700238 }
239 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700240
Tom Cherry9787f9a2020-05-19 19:01:16 -0700241 tagNameTable.Subtract(TagNameKey(element), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700242}
243
Tom Cherry64e90162020-05-07 14:44:43 -0700244const char* LogStatistics::UidToName(uid_t uid) const {
245 auto lock = std::lock_guard{lock_};
246 return UidToNameLocked(uid);
247}
248
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700249// caller must own and free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700250const char* LogStatistics::UidToNameLocked(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700251 // Local hard coded favourites
252 if (uid == AID_LOGD) {
253 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800254 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700255
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700256 // Android system
257 if (uid < AID_APP) {
258 // in bionic, thread safe as long as we copy the results
Mark Salyzyn501c3732017-03-10 14:31:54 -0800259 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700260 if (pwd) {
261 return strdup(pwd->pw_name);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700262 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800263 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700264
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700265 // Parse /data/system/packages.list
Jeff Sharkeydff44702016-12-13 11:55:19 -0700266 uid_t userId = uid % AID_USER_OFFSET;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800267 const char* name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700268 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
269 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
270 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700271 if (name) {
272 return name;
273 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700274
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700275 // Android application
276 if (uid >= AID_APP) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800277 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700278 if (pwd) {
279 return strdup(pwd->pw_name);
280 }
281 }
282
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700283 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn501c3732017-03-10 14:31:54 -0800284 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
285 ++it) {
286 const PidEntry& entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700287
Tom Cherry9787f9a2020-05-19 19:01:16 -0700288 if (entry.uid() == uid) {
289 const char* nameTmp = entry.name();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700290
Mark Salyzyn758058f2015-08-21 16:44:30 -0700291 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700292 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700293 name = strdup(nameTmp);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800294 } else if (fastcmp<strcmp>(name, nameTmp)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800295 free(const_cast<char*>(name));
Yi Kongc8d09dd2018-07-13 17:39:22 -0700296 name = nullptr;
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700297 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700298 }
299 }
300 }
301 }
302
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700303 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700304 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800305}
306
Tom Cherryb6b78e92020-05-07 09:13:12 -0700307template <typename TKey, typename TEntry>
308void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
309 int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700310 size_t* second_worst_sizes) const {
Tom Cherry4596b782020-06-03 13:49:24 -0700311 std::array<const TKey*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700312 std::array<const TEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700313 table.MaxEntries(AID_ROOT, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700314 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
315 return;
316 }
317 *worst_sizes = max_entries[0]->getSizes();
318 // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
319 // 100 characters.
Tom Cherry9787f9a2020-05-19 19:01:16 -0700320 if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
Tom Cherry4596b782020-06-03 13:49:24 -0700321 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700322 *second_worst_sizes = max_entries[1]->getSizes();
323 if (*second_worst_sizes < threshold) {
324 *second_worst_sizes = threshold;
325 }
326 }
327}
328
329void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700330 size_t* second_worst_sizes) const {
331 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700332 WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
333}
334
335void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700336 size_t* second_worst_sizes) const {
337 auto lock = std::lock_guard{lock_};
Tom Cherryb6b78e92020-05-07 09:13:12 -0700338 WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
339}
340
341void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700342 size_t* second_worst_sizes) const {
343 auto lock = std::lock_guard{lock_};
Tom Cherry4596b782020-06-03 13:49:24 -0700344 std::array<const pid_t*, 2> max_keys;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700345 std::array<const PidEntry*, 2> max_entries;
Tom Cherry4596b782020-06-03 13:49:24 -0700346 pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700347 if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
348 return;
349 }
350
Tom Cherry4596b782020-06-03 13:49:24 -0700351 *worst = *max_keys[0];
Tom Cherryb6b78e92020-05-07 09:13:12 -0700352 *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
353}
354
Tom Cherry64e90162020-05-07 14:44:43 -0700355// Prune at most 10% of the log entries or maxPrune, whichever is less.
356bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
357 unsigned long* prune_rows) const {
358 static constexpr size_t kMinPrune = 4;
359 static constexpr size_t kMaxPrune = 256;
360
361 auto lock = std::lock_guard{lock_};
362 size_t sizes = mSizes[id];
363 if (sizes <= max_size) {
364 return false;
365 }
366 size_t size_over = sizes - ((max_size * 9) / 10);
367 size_t elements = mElements[id] - mDroppedElements[id];
368 size_t min_elements = elements / 100;
369 if (min_elements < kMinPrune) {
370 min_elements = kMinPrune;
371 }
372 *prune_rows = elements * size_over / sizes;
373 if (*prune_rows < min_elements) {
374 *prune_rows = min_elements;
375 }
376 if (*prune_rows > kMaxPrune) {
377 *prune_rows = kMaxPrune;
378 }
379
380 return true;
381}
382
Mark Salyzyn501c3732017-03-10 14:31:54 -0800383std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700384 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800385 return formatLine(android::base::StringPrintf(name.c_str(),
386 android_log_id_to_name(id)),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700387 std::string("Size"),
Mark Salyzyn501c3732017-03-10 14:31:54 -0800388 std::string(isprune ? "+/- Pruned" : "")) +
389 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700390 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800391}
392
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700393// Helper to truncate name, if too long, and add name dressings
Tom Cherry64e90162020-05-07 14:44:43 -0700394void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
395 size_t nameLen) const {
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700396 const char* allocNameTmp = nullptr;
Tom Cherry64e90162020-05-07 14:44:43 -0700397 if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700398 if (nameTmp) {
399 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700400 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
401 lenSpace - 2;
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700402 size_t lenNameTmp = strlen(nameTmp);
403 while ((len < lenNameTmp) && (lenSpace > 1)) {
404 ++len;
405 --lenSpace;
406 }
407 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
408 if (len < lenNameTmp) {
409 name += "...";
410 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
411 }
412 name += nameTmp;
413 free(const_cast<char*>(allocNameTmp));
414 }
415}
416
Tom Cherry4596b782020-06-03 13:49:24 -0700417std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
418 REQUIRES(stat.lock_) {
419 std::string name = android::base::StringPrintf("%u", uid);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700420 std::string size = android::base::StringPrintf("%zu", getSizes());
421
Tom Cherry4596b782020-06-03 13:49:24 -0700422 stat.FormatTmp(nullptr, uid, name, size, 6);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700423
Mark Salyzyn758058f2015-08-21 16:44:30 -0700424 std::string pruned = "";
Mark Salyzync723df82015-08-24 11:08:00 -0700425 if (worstUidEnabledForLogid(id)) {
426 size_t totalDropped = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800427 for (LogStatistics::uidTable_t::const_iterator it =
428 stat.uidTable[id].begin();
429 it != stat.uidTable[id].end(); ++it) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700430 totalDropped += it->second.dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700431 }
Tom Cherry64e90162020-05-07 14:44:43 -0700432 size_t sizes = stat.mSizes[id];
433 size_t totalSize = stat.mSizesTotal[id];
434 size_t totalElements = stat.mElementsTotal[id];
Mark Salyzyn501c3732017-03-10 14:31:54 -0800435 float totalVirtualSize =
436 (float)sizes + (float)totalDropped * totalSize / totalElements;
Mark Salyzync723df82015-08-24 11:08:00 -0700437 size_t entrySize = getSizes();
438 float virtualEntrySize = entrySize;
439 int realPermille = virtualEntrySize * 1000.0 / sizes;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700440 size_t dropped = dropped_count();
Mark Salyzync723df82015-08-24 11:08:00 -0700441 if (dropped) {
442 pruned = android::base::StringPrintf("%zu", dropped);
443 virtualEntrySize += (float)dropped * totalSize / totalElements;
444 }
445 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800446 int permille =
447 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
Mark Salyzync723df82015-08-24 11:08:00 -0700448 if ((permille < -1) || (1 < permille)) {
449 std::string change;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800450 const char* units = "%";
451 const char* prefix = (permille > 0) ? "+" : "";
Mark Salyzync723df82015-08-24 11:08:00 -0700452
453 if (permille > 999) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800454 permille = (permille + 1000) / 100; // Now tenths fold
Mark Salyzync723df82015-08-24 11:08:00 -0700455 units = "X";
456 prefix = "";
457 }
458 if ((-99 < permille) && (permille < 99)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800459 change = android::base::StringPrintf(
460 "%s%d.%u%s", prefix, permille / 10,
Mark Salyzync723df82015-08-24 11:08:00 -0700461 ((permille < 0) ? (-permille % 10) : (permille % 10)),
462 units);
463 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800464 change = android::base::StringPrintf(
465 "%s%d%s", prefix, (permille + 5) / 10, units);
Mark Salyzync723df82015-08-24 11:08:00 -0700466 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700467 ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
Mark Salyzync723df82015-08-24 11:08:00 -0700468 if ((spaces <= 0) && pruned.length()) {
469 spaces = 1;
470 }
Mark Salyzynd966e222016-12-19 22:23:03 +0000471 if (spaces > 0) {
Mark Salyzync723df82015-08-24 11:08:00 -0700472 change += android::base::StringPrintf("%*s", (int)spaces, "");
473 }
474 pruned = change + pruned;
475 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700476 }
477
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700478 std::string output = formatLine(name, size, pruned);
479
Tom Cherry4596b782020-06-03 13:49:24 -0700480 if (uid != AID_SYSTEM) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700481 return output;
482 }
483
484 static const size_t maximum_sorted_entries = 32;
Tom Cherry4596b782020-06-03 13:49:24 -0700485 std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
486 std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
487 stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700488
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700489 std::string byPid;
490 size_t index;
491 bool hasDropped = false;
492 for (index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700493 const PidEntry* entry = sorted_entries[index];
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700494 if (!entry) {
495 break;
496 }
497 if (entry->getSizes() <= (getSizes() / 100)) {
498 break;
499 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700500 if (entry->dropped_count()) {
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700501 hasDropped = true;
502 }
Tom Cherry4596b782020-06-03 13:49:24 -0700503 byPid += entry->format(stat, id, *sorted_pids[index]);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700504 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800505 if (index > 1) { // print this only if interesting
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700506 std::string ditto("\" ");
Mark Salyzyn501c3732017-03-10 14:31:54 -0800507 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
508 hasDropped ? ditto : std::string(""));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700509 output += byPid;
510 }
511
512 return output;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700513}
514
Mark Salyzyn501c3732017-03-10 14:31:54 -0800515std::string PidEntry::formatHeader(const std::string& name,
516 log_id_t /* id */) const {
517 return formatLine(name, std::string("Size"), std::string("Pruned")) +
518 formatLine(std::string(" PID/UID COMMAND LINE"),
519 std::string("BYTES"), std::string("NUM"));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700520}
521
Tom Cherry4596b782020-06-03 13:49:24 -0700522std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700523 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700524 std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800525 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700526
Tom Cherry9787f9a2020-05-19 19:01:16 -0700527 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700528
Mark Salyzyn758058f2015-08-21 16:44:30 -0700529 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700530 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700531 if (dropped) {
532 pruned = android::base::StringPrintf("%zu", dropped);
533 }
534
535 return formatLine(name, size, pruned);
536}
537
Mark Salyzyn501c3732017-03-10 14:31:54 -0800538std::string TidEntry::formatHeader(const std::string& name,
539 log_id_t /* id */) const {
540 return formatLine(name, std::string("Size"), std::string("Pruned")) +
541 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700542 std::string("NUM"));
543}
544
Tom Cherry4596b782020-06-03 13:49:24 -0700545std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
Tom Cherry64e90162020-05-07 14:44:43 -0700546 REQUIRES(stat.lock_) {
Tom Cherry4596b782020-06-03 13:49:24 -0700547 std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800548 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700549
Tom Cherry9787f9a2020-05-19 19:01:16 -0700550 stat.FormatTmp(name_, uid_, name, size, 12);
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700551
Mark Salyzyn758058f2015-08-21 16:44:30 -0700552 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700553 size_t dropped = dropped_count();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700554 if (dropped) {
555 pruned = android::base::StringPrintf("%zu", dropped);
556 }
557
558 return formatLine(name, size, pruned);
559}
560
Mark Salyzyn501c3732017-03-10 14:31:54 -0800561std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700562 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800563 return formatLine(name, std::string("Size"),
564 std::string(isprune ? "Prune" : "")) +
565 formatLine(std::string(" TAG/UID TAGNAME"),
566 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700567}
568
Tom Cherry4596b782020-06-03 13:49:24 -0700569std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700570 std::string name;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700571 if (uid_ == (uid_t)-1) {
572 name = android::base::StringPrintf("%7u", key());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700573 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700574 name = android::base::StringPrintf("%7u/%u", key(), uid_);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700575 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700576 const char* nameTmp = this->name();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700577 if (nameTmp) {
578 name += android::base::StringPrintf(
Mark Salyzyn501c3732017-03-10 14:31:54 -0800579 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700580 }
581
Mark Salyzyn501c3732017-03-10 14:31:54 -0800582 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700583
584 std::string pruned = "";
Tom Cherry9787f9a2020-05-19 19:01:16 -0700585 size_t dropped = dropped_count();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700586 if (dropped) {
587 pruned = android::base::StringPrintf("%zu", dropped);
588 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700589
590 return formatLine(name, size, pruned);
591}
592
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700593std::string TagNameEntry::formatHeader(const std::string& name,
594 log_id_t /* id */) const {
595 return formatLine(name, std::string("Size"), std::string("")) +
596 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
597 std::string("BYTES"), std::string(""));
598}
599
Tom Cherry4596b782020-06-03 13:49:24 -0700600std::string TagNameEntry::format(const LogStatistics&, log_id_t, const TagNameKey& key_name) const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700601 std::string name;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700602 std::string pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700603 if (pid_ != (pid_t)-1) {
604 pidstr = android::base::StringPrintf("%u", pid_);
605 if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700606 }
607 int len = 9 - pidstr.length();
608 if (len < 0) len = 0;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700609 if (tid_ == (pid_t)-1 || tid_ == pid_) {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700610 name = android::base::StringPrintf("%*s", len, "");
611 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700612 name = android::base::StringPrintf("%*u", len, tid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700613 }
614 name += pidstr;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700615 if (uid_ != (uid_t)-1) {
616 name += android::base::StringPrintf("/%u", uid_);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700617 }
618
619 std::string size = android::base::StringPrintf("%zu", getSizes());
620
Tom Cherry4596b782020-06-03 13:49:24 -0700621 const char* nameTmp = key_name.data();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700622 if (nameTmp) {
623 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700624 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
625 lenSpace - 2;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700626 size_t lenNameTmp = strlen(nameTmp);
627 while ((len < lenNameTmp) && (lenSpace > 1)) {
628 ++len;
629 --lenSpace;
630 }
631 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
632 if (len < lenNameTmp) {
633 name += "...";
634 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
635 }
636 name += nameTmp;
637 }
638
639 std::string pruned = "";
640
641 return formatLine(name, size, pruned);
642}
643
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700644static std::string formatMsec(uint64_t val) {
645 static const unsigned subsecDigits = 3;
646 static const uint64_t sec = MS_PER_SEC;
647
648 static const uint64_t minute = 60 * sec;
649 static const uint64_t hour = 60 * minute;
650 static const uint64_t day = 24 * hour;
651
652 std::string output;
653 if (val < sec) return output;
654
655 if (val >= day) {
656 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
657 val = (val % day) + day;
658 }
659 if (val >= minute) {
660 if (val >= hour) {
661 output += android::base::StringPrintf("%" PRIu64 ":",
662 (val / hour) % (day / hour));
663 }
664 output += android::base::StringPrintf(
665 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
666 (val / minute) % (hour / minute));
667 }
668 output +=
669 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
670 (val / sec) % (minute / sec));
671 val %= sec;
672 unsigned digits = subsecDigits;
673 while (digits && ((val % 10) == 0)) {
674 val /= 10;
675 --digits;
676 }
677 if (digits) {
678 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
679 }
680 return output;
681}
682
Tom Cherry64e90162020-05-07 14:44:43 -0700683template <typename TKey, typename TEntry>
684std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
685 pid_t pid, const std::string& name, log_id_t id) const
686 REQUIRES(lock_) {
687 static const size_t maximum_sorted_entries = 32;
688 std::string output;
Tom Cherry4596b782020-06-03 13:49:24 -0700689 std::array<const TKey*, maximum_sorted_entries> sorted_keys;
690 std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
691 table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
Tom Cherry64e90162020-05-07 14:44:43 -0700692 bool header_printed = false;
693 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
Tom Cherry4596b782020-06-03 13:49:24 -0700694 const TEntry* entry = sorted_entries[index];
Tom Cherry64e90162020-05-07 14:44:43 -0700695 if (!entry) {
696 break;
697 }
Tom Cherry4596b782020-06-03 13:49:24 -0700698 if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
Tom Cherry64e90162020-05-07 14:44:43 -0700699 break;
700 }
701 if (!header_printed) {
702 output += "\n\n";
703 output += entry->formatHeader(name, id);
704 header_printed = true;
705 }
Tom Cherry4596b782020-06-03 13:49:24 -0700706 output += entry->format(*this, id, *sorted_keys[index]);
Tom Cherry64e90162020-05-07 14:44:43 -0700707 }
708 return output;
709}
710
711std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
712 auto lock = std::lock_guard{lock_};
713
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700714 static const uint16_t spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800715
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700716 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800717
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700718 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700719 size_t oldLength;
Chih-Hung Hsieh08d470b2018-08-13 14:22:56 -0700720 int16_t spaces = 1;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700721
722 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700723 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700724 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700725 if (spaces < 0) spaces = 0;
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700726 output += android::base::StringPrintf("%*s%s", spaces, "",
727 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700728 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800729 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700730 if (spaces < 0) spaces = 0;
731 output += android::base::StringPrintf("%*sTotal", spaces, "");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800732
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700733 static const char TotalStr[] = "\nTotal";
734 spaces = 10 - strlen(TotalStr);
735 output += TotalStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800736
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700737 size_t totalSize = 0;
738 size_t totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700739 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700740 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700741 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700742 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700743 size_t szs = mSizesTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700744 totalSize += szs;
Tom Cherry64e90162020-05-07 14:44:43 -0700745 size_t els = mElementsTotal[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700746 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800747 output +=
748 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700749 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800750 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700751 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800752 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
753 totalEls);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800754
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700755 static const char NowStr[] = "\nNow";
756 spaces = 10 - strlen(NowStr);
757 output += NowStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800758
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700759 totalSize = 0;
760 totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700761 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700762 if (!(logMask & (1 << id))) continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800763
Tom Cherry64e90162020-05-07 14:44:43 -0700764 size_t els = mElements[id];
Mark Salyzyn34facab2014-02-06 14:48:50 -0800765 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700766 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700767 if (spaces < 0) spaces = 0;
Tom Cherry64e90162020-05-07 14:44:43 -0700768 size_t szs = mSizes[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700769 totalSize += szs;
770 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800771 output +=
772 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700773 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800774 }
775 spaces += spaces_total;
776 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700777 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800778 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
779 totalEls);
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700780
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700781 static const char SpanStr[] = "\nLogspan";
782 spaces = 10 - strlen(SpanStr);
783 output += SpanStr;
784
785 // Total reports the greater of the individual maximum time span, or the
786 // validated minimum start and maximum end time span if it makes sense.
787 uint64_t minTime = UINT64_MAX;
788 uint64_t maxTime = 0;
789 uint64_t maxSpan = 0;
790 totalSize = 0;
791
792 log_id_for_each(id) {
793 if (!(logMask & (1 << id))) continue;
794
795 // validity checking
796 uint64_t oldest = mOldest[id].msec();
797 uint64_t newest = mNewest[id].msec();
798 if (newest <= oldest) {
799 spaces += spaces_total;
800 continue;
801 }
802
803 uint64_t span = newest - oldest;
804 if (span > (monthSec * MS_PER_SEC)) {
805 spaces += spaces_total;
806 continue;
807 }
808
809 // total span
810 if (minTime > oldest) minTime = oldest;
811 if (maxTime < newest) maxTime = newest;
812 if (span > maxSpan) maxSpan = span;
813 totalSize += span;
814
815 uint64_t dropped = mNewestDropped[id].msec();
816 if (dropped < oldest) dropped = oldest;
817 if (dropped > newest) dropped = newest;
818
819 oldLength = output.length();
820 output += android::base::StringPrintf("%*s%s", spaces, "",
821 formatMsec(span).c_str());
822 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
823 if ((permille > 1) && (permille < 999)) {
824 output += android::base::StringPrintf("(%u", permille / 10);
825 permille %= 10;
826 if (permille) {
827 output += android::base::StringPrintf(".%u", permille);
828 }
829 output += android::base::StringPrintf("%%)");
830 }
831 spaces -= output.length() - oldLength;
832 spaces += spaces_total;
833 }
834 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
835 (maxTime > maxSpan)) {
836 maxSpan = maxTime;
837 }
838 if (spaces < 0) spaces = 0;
839 output += android::base::StringPrintf("%*s%s", spaces, "",
840 formatMsec(maxSpan).c_str());
841
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700842 static const char OverheadStr[] = "\nOverhead";
843 spaces = 10 - strlen(OverheadStr);
844 output += OverheadStr;
845
846 totalSize = 0;
847 log_id_for_each(id) {
848 if (!(logMask & (1 << id))) continue;
849
Tom Cherry64e90162020-05-07 14:44:43 -0700850 size_t els = mElements[id];
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700851 if (els) {
852 oldLength = output.length();
853 if (spaces < 0) spaces = 0;
854 // estimate the std::list overhead.
855 static const size_t overhead =
856 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
Mark Salyzyn501c3732017-03-10 14:31:54 -0800857 -sizeof(uint64_t)) +
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700858 sizeof(std::list<LogBufferElement*>);
Tom Cherry64e90162020-05-07 14:44:43 -0700859 size_t szs = mSizes[id] + els * overhead;
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700860 totalSize += szs;
861 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
862 spaces -= output.length() - oldLength;
863 }
864 spaces += spaces_total;
865 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700866 totalSize += sizeOf();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700867 if (spaces < 0) spaces = 0;
868 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800869
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700870 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700871
Mark Salyzyn758058f2015-08-21 16:44:30 -0700872 std::string name;
873
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700874 // Chattiest by application (UID)
875 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700876 if (!(logMask & (1 << id))) continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700877
Mark Salyzyn501c3732017-03-10 14:31:54 -0800878 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
879 : "Logging for your UID in %s log buffer:";
Tom Cherry64e90162020-05-07 14:44:43 -0700880 output += FormatTable(uidTable[id], uid, pid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700881 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700882
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700883 if (enable) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800884 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
885 : "Logging for this PID:";
Tom Cherry64e90162020-05-07 14:44:43 -0700886 output += FormatTable(pidTable, uid, pid, name);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800887 name = "Chattiest TIDs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700888 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800889 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700890 output += FormatTable(tidTable, uid, pid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700891 }
892
Mark Salyzyn344bff42015-04-13 14:24:45 -0700893 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800894 name = "Chattiest events log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700895 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800896 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700897 output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700898 }
899
Mark Salyzyn083b0372015-12-04 10:59:45 -0800900 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800901 name = "Chattiest security log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700902 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800903 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700904 output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800905 }
906
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700907 if (enable) {
908 name = "Chattiest TAGs";
909 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
910 name += ":";
Tom Cherry64e90162020-05-07 14:44:43 -0700911 output += FormatTable(tagNameTable, uid, pid, name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700912 }
913
Mark Salyzyn73160ac2015-08-20 10:01:44 -0700914 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800915}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700916
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700917namespace android {
918
919uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700920 char buffer[512];
921 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800922 FILE* fp = fopen(buffer, "r");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700923 if (fp) {
924 while (fgets(buffer, sizeof(buffer), fp)) {
Mark Salyzync4e48232017-05-04 13:54:46 -0700925 int uid = AID_LOGD;
926 char space = 0;
927 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
928 isspace(space)) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700929 fclose(fp);
930 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700931 }
932 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700933 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700934 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800935 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700936}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700937}
938
Tom Cherry64e90162020-05-07 14:44:43 -0700939uid_t LogStatistics::PidToUid(pid_t pid) {
940 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -0700941 return pidTable.Add(pid)->second.uid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700942}
943
944// caller must free character string
Tom Cherry64e90162020-05-07 14:44:43 -0700945const char* LogStatistics::PidToName(pid_t pid) const {
946 auto lock = std::lock_guard{lock_};
Mark Salyzyn758058f2015-08-21 16:44:30 -0700947 // An inconvenient truth ... getName() can alter the object
Mark Salyzyn501c3732017-03-10 14:31:54 -0800948 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700949 const char* name = writablePidTable.Add(pid)->second.name();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700950 if (!name) {
Yi Kongc8d09dd2018-07-13 17:39:22 -0700951 return nullptr;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700952 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700953 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700954}