blob: 0b6b28cf8c1247ff6262beed9dd221db8d34fc18 [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
Mark Salyzyn9a038632014-04-07 07:05:40 -070017#include <fcntl.h>
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070018#include <inttypes.h>
Mark Salyzynb8a95bd2016-04-07 11:06:31 -070019#include <pwd.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070020#include <stdio.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070021#include <string.h>
Mark Salyzynb8a95bd2016-04-07 11:06:31 -070022#include <sys/types.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070023#include <unistd.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080024
Mark Salyzyn9af33ee2016-10-05 12:34:37 -070025#include <list>
26
Mark Salyzyn03bb7592017-04-14 09:46:57 -070027#include <private/android_logger.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080028
29#include "LogStatistics.h"
30
Mark Salyzyn03bb7592017-04-14 09:46:57 -070031static const uint64_t hourSec = 60 * 60;
32static const uint64_t monthSec = 31 * 24 * hourSec;
33
Mark Salyzyn32962912016-09-12 10:29:17 -070034size_t LogStatistics::SizesTotal;
35
Mark Salyzyn77187782015-05-12 15:21:31 -070036LogStatistics::LogStatistics() : enable(false) {
Mark Salyzyn03bb7592017-04-14 09:46:57 -070037 log_time now(CLOCK_REALTIME);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070038 log_id_for_each(id) {
39 mSizes[id] = 0;
40 mElements[id] = 0;
Mark Salyzyn58b8be82015-09-30 07:40:09 -070041 mDroppedElements[id] = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070042 mSizesTotal[id] = 0;
43 mElementsTotal[id] = 0;
Mark Salyzyn03bb7592017-04-14 09:46:57 -070044 mOldest[id] = now;
45 mNewest[id] = now;
46 mNewestDropped[id] = now;
Mark Salyzyn34facab2014-02-06 14:48:50 -080047 }
48}
49
Mark Salyzyn720f6d12015-03-16 08:26:05 -070050namespace android {
51
Mark Salyzyn501c3732017-03-10 14:31:54 -080052size_t sizesTotal() {
53 return LogStatistics::sizesTotal();
54}
Mark Salyzyn32962912016-09-12 10:29:17 -070055
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070056// caller must own and free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -080057char* pidToName(pid_t pid) {
58 char* retval = NULL;
59 if (pid == 0) { // special case from auditd/klogd for kernel
Mark Salyzynae4d9282014-10-15 08:49:39 -070060 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070061 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070062 char buffer[512];
63 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
64 int fd = open(buffer, O_RDONLY);
65 if (fd >= 0) {
66 ssize_t ret = read(fd, buffer, sizeof(buffer));
67 if (ret > 0) {
Mark Salyzyn501c3732017-03-10 14:31:54 -080068 buffer[sizeof(buffer) - 1] = '\0';
Mark Salyzyn9a038632014-04-07 07:05:40 -070069 // frameworks intermediate state
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -080070 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070071 retval = strdup(buffer);
72 }
73 }
74 close(fd);
75 }
76 }
77 return retval;
78}
Mark Salyzyn720f6d12015-03-16 08:26:05 -070079}
80
Mark Salyzyn02dd2f42017-04-14 09:46:57 -070081void LogStatistics::addTotal(LogBufferElement* element) {
82 if (element->getDropped()) return;
83
84 log_id_t log_id = element->getLogId();
85 unsigned short size = element->getMsgLen();
86 mSizesTotal[log_id] += size;
87 SizesTotal += size;
88 ++mElementsTotal[log_id];
89}
90
Mark Salyzyn501c3732017-03-10 14:31:54 -080091void LogStatistics::add(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -070092 log_id_t log_id = element->getLogId();
93 unsigned short size = element->getMsgLen();
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.
Mark Salyzyna2c02222016-12-13 10:31:29 -0800102 if (element->getDropped()) {
103 ++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
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700110 log_time stamp(element->getRealTime());
111 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
Mark Salyzyn758058f2015-08-21 16:44:30 -0700135 uidTable[log_id].add(element->getUid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700136 if (element->getUid() == AID_SYSTEM) {
137 pidSystemTable[log_id].add(element->getPid(), element);
138 }
Mark Salyzynae4d9282014-10-15 08:49:39 -0700139
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700140 if (!enable) {
141 return;
142 }
143
Mark Salyzyn758058f2015-08-21 16:44:30 -0700144 pidTable.add(element->getPid(), element);
145 tidTable.add(element->getTid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700146
Mark Salyzyn758058f2015-08-21 16:44:30 -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) {
150 securityTagTable.add(tag, element);
151 } else {
152 tagTable.add(tag, element);
153 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700154 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800155}
156
Mark Salyzyn501c3732017-03-10 14:31:54 -0800157void LogStatistics::subtract(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700158 log_id_t log_id = element->getLogId();
159 unsigned short size = element->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800160 mSizes[log_id] -= size;
161 --mElements[log_id];
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700162 if (element->getDropped()) {
163 --mDroppedElements[log_id];
164 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700165
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700166 if (mOldest[log_id] < element->getRealTime()) {
167 mOldest[log_id] = element->getRealTime();
168 }
169
Mark Salyzynae4d9282014-10-15 08:49:39 -0700170 if (log_id == LOG_ID_KERNEL) {
171 return;
172 }
173
Mark Salyzyn758058f2015-08-21 16:44:30 -0700174 uidTable[log_id].subtract(element->getUid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700175 if (element->getUid() == AID_SYSTEM) {
176 pidSystemTable[log_id].subtract(element->getPid(), element);
177 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800178
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700179 if (!enable) {
180 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800181 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700182
Mark Salyzyn758058f2015-08-21 16:44:30 -0700183 pidTable.subtract(element->getPid(), element);
184 tidTable.subtract(element->getTid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700185
Mark Salyzyn758058f2015-08-21 16:44:30 -0700186 uint32_t tag = element->getTag();
Mark Salyzyn344bff42015-04-13 14:24:45 -0700187 if (tag) {
Mark Salyzyn083b0372015-12-04 10:59:45 -0800188 if (log_id == LOG_ID_SECURITY) {
189 securityTagTable.subtract(tag, element);
190 } else {
191 tagTable.subtract(tag, element);
192 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700193 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800194}
195
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700196// Atomically set an entry to drop
197// entry->setDropped(1) must follow this call, caller should do this explicitly.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800198void LogStatistics::drop(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700199 log_id_t log_id = element->getLogId();
200 unsigned short size = element->getMsgLen();
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700201 mSizes[log_id] -= size;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700202 ++mDroppedElements[log_id];
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700203
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700204 if (mNewestDropped[log_id] < element->getRealTime()) {
205 mNewestDropped[log_id] = element->getRealTime();
206 }
207
Mark Salyzyn758058f2015-08-21 16:44:30 -0700208 uidTable[log_id].drop(element->getUid(), element);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700209 if (element->getUid() == AID_SYSTEM) {
210 pidSystemTable[log_id].drop(element->getPid(), element);
211 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700212
213 if (!enable) {
214 return;
215 }
216
Mark Salyzyn758058f2015-08-21 16:44:30 -0700217 pidTable.drop(element->getPid(), element);
218 tidTable.drop(element->getTid(), element);
Mark Salyzyn6a066942016-07-14 15:34:30 -0700219
220 uint32_t tag = element->getTag();
221 if (tag) {
222 if (log_id == LOG_ID_SECURITY) {
223 securityTagTable.drop(tag, element);
224 } else {
225 tagTable.drop(tag, element);
226 }
227 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700228}
229
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700230// caller must own and free character string
Mark Salyzyn3c501b52017-04-18 14:09:45 -0700231// Requires parent LogBuffer::wrlock() to be held
Mark Salyzyn501c3732017-03-10 14:31:54 -0800232const char* LogStatistics::uidToName(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700233 // Local hard coded favourites
234 if (uid == AID_LOGD) {
235 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800236 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700237
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700238 // Android system
239 if (uid < AID_APP) {
240 // in bionic, thread safe as long as we copy the results
Mark Salyzyn501c3732017-03-10 14:31:54 -0800241 struct passwd* pwd = getpwuid(uid);
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700242 if (pwd) {
243 return strdup(pwd->pw_name);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700244 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800245 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700246
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700247 // Parse /data/system/packages.list
Jeff Sharkeydff44702016-12-13 11:55:19 -0700248 uid_t userId = uid % AID_USER_OFFSET;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800249 const char* name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700250 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
251 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
252 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700253 if (name) {
254 return name;
255 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700256
Mark Salyzynb8a95bd2016-04-07 11:06:31 -0700257 // Android application
258 if (uid >= AID_APP) {
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);
262 }
263 }
264
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700265 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn501c3732017-03-10 14:31:54 -0800266 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
267 ++it) {
268 const PidEntry& entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700269
270 if (entry.getUid() == uid) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800271 const char* nameTmp = entry.getName();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700272
Mark Salyzyn758058f2015-08-21 16:44:30 -0700273 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700274 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700275 name = strdup(nameTmp);
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800276 } else if (fastcmp<strcmp>(name, nameTmp)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800277 free(const_cast<char*>(name));
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700278 name = NULL;
279 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700280 }
281 }
282 }
283 }
284
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700285 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700286 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800287}
288
Mark Salyzyn501c3732017-03-10 14:31:54 -0800289std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700290 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800291 return formatLine(android::base::StringPrintf(name.c_str(),
292 android_log_id_to_name(id)),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700293 std::string("Size"),
Mark Salyzyn501c3732017-03-10 14:31:54 -0800294 std::string(isprune ? "+/- Pruned" : "")) +
295 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700296 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800297}
298
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700299// Helper to truncate name, if too long, and add name dressings
300static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
301 std::string& name, std::string& size, size_t nameLen) {
302 const char* allocNameTmp = nullptr;
303 if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
304 if (nameTmp) {
305 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
306 size_t len = EntryBaseConstants::total_len -
307 EntryBaseConstants::pruned_len - size.length() -
308 name.length() - lenSpace - 2;
309 size_t lenNameTmp = strlen(nameTmp);
310 while ((len < lenNameTmp) && (lenSpace > 1)) {
311 ++len;
312 --lenSpace;
313 }
314 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
315 if (len < lenNameTmp) {
316 name += "...";
317 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
318 }
319 name += nameTmp;
320 free(const_cast<char*>(allocNameTmp));
321 }
322}
323
Mark Salyzyn501c3732017-03-10 14:31:54 -0800324std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800325 uid_t uid = getUid();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700326 std::string name = android::base::StringPrintf("%u", uid);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700327 std::string size = android::base::StringPrintf("%zu", getSizes());
328
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700329 formatTmp(stat, nullptr, uid, name, size, 6);
330
Mark Salyzyn758058f2015-08-21 16:44:30 -0700331 std::string pruned = "";
Mark Salyzync723df82015-08-24 11:08:00 -0700332 if (worstUidEnabledForLogid(id)) {
333 size_t totalDropped = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800334 for (LogStatistics::uidTable_t::const_iterator it =
335 stat.uidTable[id].begin();
336 it != stat.uidTable[id].end(); ++it) {
Mark Salyzync723df82015-08-24 11:08:00 -0700337 totalDropped += it->second.getDropped();
338 }
339 size_t sizes = stat.sizes(id);
340 size_t totalSize = stat.sizesTotal(id);
341 size_t totalElements = stat.elementsTotal(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800342 float totalVirtualSize =
343 (float)sizes + (float)totalDropped * totalSize / totalElements;
Mark Salyzync723df82015-08-24 11:08:00 -0700344 size_t entrySize = getSizes();
345 float virtualEntrySize = entrySize;
346 int realPermille = virtualEntrySize * 1000.0 / sizes;
347 size_t dropped = getDropped();
348 if (dropped) {
349 pruned = android::base::StringPrintf("%zu", dropped);
350 virtualEntrySize += (float)dropped * totalSize / totalElements;
351 }
352 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800353 int permille =
354 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
Mark Salyzync723df82015-08-24 11:08:00 -0700355 if ((permille < -1) || (1 < permille)) {
356 std::string change;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800357 const char* units = "%";
358 const char* prefix = (permille > 0) ? "+" : "";
Mark Salyzync723df82015-08-24 11:08:00 -0700359
360 if (permille > 999) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800361 permille = (permille + 1000) / 100; // Now tenths fold
Mark Salyzync723df82015-08-24 11:08:00 -0700362 units = "X";
363 prefix = "";
364 }
365 if ((-99 < permille) && (permille < 99)) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800366 change = android::base::StringPrintf(
367 "%s%d.%u%s", prefix, permille / 10,
Mark Salyzync723df82015-08-24 11:08:00 -0700368 ((permille < 0) ? (-permille % 10) : (permille % 10)),
369 units);
370 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800371 change = android::base::StringPrintf(
372 "%s%d%s", prefix, (permille + 5) / 10, units);
Mark Salyzync723df82015-08-24 11:08:00 -0700373 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800374 ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
375 pruned.length() - change.length();
Mark Salyzync723df82015-08-24 11:08:00 -0700376 if ((spaces <= 0) && pruned.length()) {
377 spaces = 1;
378 }
Mark Salyzynd966e222016-12-19 22:23:03 +0000379 if (spaces > 0) {
Mark Salyzync723df82015-08-24 11:08:00 -0700380 change += android::base::StringPrintf("%*s", (int)spaces, "");
381 }
382 pruned = change + pruned;
383 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700384 }
385
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700386 std::string output = formatLine(name, size, pruned);
387
388 if (uid != AID_SYSTEM) {
389 return output;
390 }
391
392 static const size_t maximum_sorted_entries = 32;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800393 std::unique_ptr<const PidEntry* []> sorted =
394 stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700395
396 if (!sorted.get()) {
397 return output;
398 }
399 std::string byPid;
400 size_t index;
401 bool hasDropped = false;
402 for (index = 0; index < maximum_sorted_entries; ++index) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800403 const PidEntry* entry = sorted[index];
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700404 if (!entry) {
405 break;
406 }
407 if (entry->getSizes() <= (getSizes() / 100)) {
408 break;
409 }
410 if (entry->getDropped()) {
411 hasDropped = true;
412 }
413 byPid += entry->format(stat, id);
414 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800415 if (index > 1) { // print this only if interesting
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700416 std::string ditto("\" ");
Mark Salyzyn501c3732017-03-10 14:31:54 -0800417 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
418 hasDropped ? ditto : std::string(""));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700419 output += byPid;
420 }
421
422 return output;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700423}
424
Mark Salyzyn501c3732017-03-10 14:31:54 -0800425std::string PidEntry::formatHeader(const std::string& name,
426 log_id_t /* id */) const {
427 return formatLine(name, std::string("Size"), std::string("Pruned")) +
428 formatLine(std::string(" PID/UID COMMAND LINE"),
429 std::string("BYTES"), std::string("NUM"));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700430}
431
Mark Salyzyn501c3732017-03-10 14:31:54 -0800432std::string PidEntry::format(const LogStatistics& stat,
433 log_id_t /* id */) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700434 uid_t uid = getUid();
Mark Salyzynee3b8382015-12-17 09:58:43 -0800435 pid_t pid = getPid();
436 std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800437 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700438
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700439 formatTmp(stat, getName(), uid, name, size, 12);
440
Mark Salyzyn758058f2015-08-21 16:44:30 -0700441 std::string pruned = "";
442 size_t dropped = getDropped();
443 if (dropped) {
444 pruned = android::base::StringPrintf("%zu", dropped);
445 }
446
447 return formatLine(name, size, pruned);
448}
449
Mark Salyzyn501c3732017-03-10 14:31:54 -0800450std::string TidEntry::formatHeader(const std::string& name,
451 log_id_t /* id */) const {
452 return formatLine(name, std::string("Size"), std::string("Pruned")) +
453 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
Mark Salyzyn758058f2015-08-21 16:44:30 -0700454 std::string("NUM"));
455}
456
Mark Salyzyn501c3732017-03-10 14:31:54 -0800457std::string TidEntry::format(const LogStatistics& stat,
458 log_id_t /* id */) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700459 uid_t uid = getUid();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800460 std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800461 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700462
Mark Salyzynf31ae3d2017-04-13 15:35:22 -0700463 formatTmp(stat, getName(), uid, name, size, 12);
464
Mark Salyzyn758058f2015-08-21 16:44:30 -0700465 std::string pruned = "";
466 size_t dropped = getDropped();
467 if (dropped) {
468 pruned = android::base::StringPrintf("%zu", dropped);
469 }
470
471 return formatLine(name, size, pruned);
472}
473
Mark Salyzyn501c3732017-03-10 14:31:54 -0800474std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700475 bool isprune = worstUidEnabledForLogid(id);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800476 return formatLine(name, std::string("Size"),
477 std::string(isprune ? "Prune" : "")) +
478 formatLine(std::string(" TAG/UID TAGNAME"),
479 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700480}
481
Mark Salyzyn501c3732017-03-10 14:31:54 -0800482std::string TagEntry::format(const LogStatistics& /* stat */,
483 log_id_t /* id */) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700484 std::string name;
485 uid_t uid = getUid();
486 if (uid == (uid_t)-1) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800487 name = android::base::StringPrintf("%7u", getKey());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700488 } else {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800489 name = android::base::StringPrintf("%7u/%u", getKey(), uid);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700490 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800491 const char* nameTmp = getName();
Mark Salyzyn758058f2015-08-21 16:44:30 -0700492 if (nameTmp) {
493 name += android::base::StringPrintf(
Mark Salyzyn501c3732017-03-10 14:31:54 -0800494 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700495 }
496
Mark Salyzyn501c3732017-03-10 14:31:54 -0800497 std::string size = android::base::StringPrintf("%zu", getSizes());
Mark Salyzyn758058f2015-08-21 16:44:30 -0700498
499 std::string pruned = "";
Mark Salyzyn6a066942016-07-14 15:34:30 -0700500 size_t dropped = getDropped();
501 if (dropped) {
502 pruned = android::base::StringPrintf("%zu", dropped);
503 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700504
505 return formatLine(name, size, pruned);
506}
507
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700508static std::string formatMsec(uint64_t val) {
509 static const unsigned subsecDigits = 3;
510 static const uint64_t sec = MS_PER_SEC;
511
512 static const uint64_t minute = 60 * sec;
513 static const uint64_t hour = 60 * minute;
514 static const uint64_t day = 24 * hour;
515
516 std::string output;
517 if (val < sec) return output;
518
519 if (val >= day) {
520 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
521 val = (val % day) + day;
522 }
523 if (val >= minute) {
524 if (val >= hour) {
525 output += android::base::StringPrintf("%" PRIu64 ":",
526 (val / hour) % (day / hour));
527 }
528 output += android::base::StringPrintf(
529 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
530 (val / minute) % (hour / minute));
531 }
532 output +=
533 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
534 (val / sec) % (minute / sec));
535 val %= sec;
536 unsigned digits = subsecDigits;
537 while (digits && ((val % 10) == 0)) {
538 val /= 10;
539 --digits;
540 }
541 if (digits) {
542 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
543 }
544 return output;
545}
546
Mark Salyzynee3b8382015-12-17 09:58:43 -0800547std::string LogStatistics::format(uid_t uid, pid_t pid,
548 unsigned int logMask) const {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700549 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800550
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700551 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800552
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700553 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700554 size_t oldLength;
555 short spaces = 1;
556
557 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700558 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700559 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700560 if (spaces < 0) spaces = 0;
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700561 output += android::base::StringPrintf("%*s%s", spaces, "",
562 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700563 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800564 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700565 if (spaces < 0) spaces = 0;
566 output += android::base::StringPrintf("%*sTotal", spaces, "");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800567
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700568 static const char TotalStr[] = "\nTotal";
569 spaces = 10 - strlen(TotalStr);
570 output += TotalStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800571
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700572 size_t totalSize = 0;
573 size_t totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700574 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700575 if (!(logMask & (1 << id))) continue;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700576 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700577 if (spaces < 0) spaces = 0;
578 size_t szs = sizesTotal(id);
579 totalSize += szs;
580 size_t els = elementsTotal(id);
581 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800582 output +=
583 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700584 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800585 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700586 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800587 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
588 totalEls);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800589
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700590 static const char NowStr[] = "\nNow";
591 spaces = 10 - strlen(NowStr);
592 output += NowStr;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800593
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700594 totalSize = 0;
595 totalEls = 0;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700596 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700597 if (!(logMask & (1 << id))) continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800598
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700599 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800600 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700601 oldLength = output.length();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700602 if (spaces < 0) spaces = 0;
603 size_t szs = sizes(id);
604 totalSize += szs;
605 totalEls += els;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800606 output +=
607 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700608 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800609 }
610 spaces += spaces_total;
611 }
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700612 if (spaces < 0) spaces = 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800613 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
614 totalEls);
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700615
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700616 static const char SpanStr[] = "\nLogspan";
617 spaces = 10 - strlen(SpanStr);
618 output += SpanStr;
619
620 // Total reports the greater of the individual maximum time span, or the
621 // validated minimum start and maximum end time span if it makes sense.
622 uint64_t minTime = UINT64_MAX;
623 uint64_t maxTime = 0;
624 uint64_t maxSpan = 0;
625 totalSize = 0;
626
627 log_id_for_each(id) {
628 if (!(logMask & (1 << id))) continue;
629
630 // validity checking
631 uint64_t oldest = mOldest[id].msec();
632 uint64_t newest = mNewest[id].msec();
633 if (newest <= oldest) {
634 spaces += spaces_total;
635 continue;
636 }
637
638 uint64_t span = newest - oldest;
639 if (span > (monthSec * MS_PER_SEC)) {
640 spaces += spaces_total;
641 continue;
642 }
643
644 // total span
645 if (minTime > oldest) minTime = oldest;
646 if (maxTime < newest) maxTime = newest;
647 if (span > maxSpan) maxSpan = span;
648 totalSize += span;
649
650 uint64_t dropped = mNewestDropped[id].msec();
651 if (dropped < oldest) dropped = oldest;
652 if (dropped > newest) dropped = newest;
653
654 oldLength = output.length();
655 output += android::base::StringPrintf("%*s%s", spaces, "",
656 formatMsec(span).c_str());
657 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
658 if ((permille > 1) && (permille < 999)) {
659 output += android::base::StringPrintf("(%u", permille / 10);
660 permille %= 10;
661 if (permille) {
662 output += android::base::StringPrintf(".%u", permille);
663 }
664 output += android::base::StringPrintf("%%)");
665 }
666 spaces -= output.length() - oldLength;
667 spaces += spaces_total;
668 }
669 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
670 (maxTime > maxSpan)) {
671 maxSpan = maxTime;
672 }
673 if (spaces < 0) spaces = 0;
674 output += android::base::StringPrintf("%*s%s", spaces, "",
675 formatMsec(maxSpan).c_str());
676
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700677 static const char OverheadStr[] = "\nOverhead";
678 spaces = 10 - strlen(OverheadStr);
679 output += OverheadStr;
680
681 totalSize = 0;
682 log_id_for_each(id) {
683 if (!(logMask & (1 << id))) continue;
684
685 size_t els = elements(id);
686 if (els) {
687 oldLength = output.length();
688 if (spaces < 0) spaces = 0;
689 // estimate the std::list overhead.
690 static const size_t overhead =
691 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
Mark Salyzyn501c3732017-03-10 14:31:54 -0800692 -sizeof(uint64_t)) +
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700693 sizeof(std::list<LogBufferElement*>);
694 size_t szs = sizes(id) + els * overhead;
695 totalSize += szs;
696 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
697 spaces -= output.length() - oldLength;
698 }
699 spaces += spaces_total;
700 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700701 totalSize += sizeOf();
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700702 if (spaces < 0) spaces = 0;
703 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800704
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700705 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700706
Mark Salyzyn758058f2015-08-21 16:44:30 -0700707 std::string name;
708
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700709 // Chattiest by application (UID)
710 log_id_for_each(id) {
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700711 if (!(logMask & (1 << id))) continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700712
Mark Salyzyn501c3732017-03-10 14:31:54 -0800713 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
714 : "Logging for your UID in %s log buffer:";
Mark Salyzynee3b8382015-12-17 09:58:43 -0800715 output += uidTable[id].format(*this, uid, pid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700716 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700717
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700718 if (enable) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800719 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
720 : "Logging for this PID:";
Mark Salyzynee3b8382015-12-17 09:58:43 -0800721 output += pidTable.format(*this, uid, pid, name);
722 name = "Chattiest TIDs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700723 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800724 name += ":";
725 output += tidTable.format(*this, uid, pid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700726 }
727
Mark Salyzyn344bff42015-04-13 14:24:45 -0700728 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800729 name = "Chattiest events log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700730 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800731 name += ":";
732 output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700733 }
734
Mark Salyzyn083b0372015-12-04 10:59:45 -0800735 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800736 name = "Chattiest security log buffer TAGs";
Mark Salyzyn9af33ee2016-10-05 12:34:37 -0700737 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800738 name += ":";
Mark Salyzyn501c3732017-03-10 14:31:54 -0800739 output +=
740 securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800741 }
742
Mark Salyzyn73160ac2015-08-20 10:01:44 -0700743 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800744}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700745
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700746namespace android {
747
748uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700749 char buffer[512];
750 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800751 FILE* fp = fopen(buffer, "r");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700752 if (fp) {
753 while (fgets(buffer, sizeof(buffer), fp)) {
754 int uid;
Mark Salyzync32afdf2015-04-14 13:07:29 -0700755 if (sscanf(buffer, "Uid: %d", &uid) == 1) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700756 fclose(fp);
757 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700758 }
759 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700760 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700761 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800762 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700763}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700764}
765
766uid_t LogStatistics::pidToUid(pid_t pid) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700767 return pidTable.add(pid)->second.getUid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700768}
769
770// caller must free character string
Mark Salyzyn501c3732017-03-10 14:31:54 -0800771const char* LogStatistics::pidToName(pid_t pid) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700772 // An inconvenient truth ... getName() can alter the object
Mark Salyzyn501c3732017-03-10 14:31:54 -0800773 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
774 const char* name = writablePidTable.add(pid)->second.getName();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700775 if (!name) {
776 return NULL;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700777 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700778 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700779}