blob: ac3cf9af2372c5e7cd3f6721d344e1ce519d2161 [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
17#ifndef _LOGD_LOG_STATISTICS_H__
18#define _LOGD_LOG_STATISTICS_H__
19
Mark Salyzynb545e1c2016-12-19 14:51:15 -080020#include <ctype.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070021#include <inttypes.h>
22#include <stdint.h>
Mark Salyzyn720f6d12015-03-16 08:26:05 -070023#include <stdlib.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070024#include <string.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080025#include <sys/types.h>
26
Mark Salyzyn501c3732017-03-10 14:31:54 -080027#include <algorithm> // std::max
Mark Salyzynb545e1c2016-12-19 14:51:15 -080028#include <memory>
Elliott Hughese8058832017-11-30 16:31:35 -080029#include <string>
30#include <string_view>
Mark Salyzyn511338d2015-05-19 09:12:30 -070031#include <unordered_map>
32
Elliott Hughes4f713192015-12-04 22:00:26 -080033#include <android-base/stringprintf.h>
Mark Salyzyn501c3732017-03-10 14:31:54 -080034#include <android/log.h>
Mark Salyzyn03bb7592017-04-14 09:46:57 -070035#include <log/log_time.h>
Mark Salyzyn758058f2015-08-21 16:44:30 -070036#include <private/android_filesystem_config.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070037#include <utils/FastStrcmp.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070038
39#include "LogBufferElement.h"
Mark Salyzyn5ac5c6b2015-08-28 08:02:59 -070040#include "LogUtils.h"
Mark Salyzyn34facab2014-02-06 14:48:50 -080041
42#define log_id_for_each(i) \
Mark Salyzyn501c3732017-03-10 14:31:54 -080043 for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
Mark Salyzyn34facab2014-02-06 14:48:50 -080044
Mark Salyzyn758058f2015-08-21 16:44:30 -070045class LogStatistics;
46
Mark Salyzyn720f6d12015-03-16 08:26:05 -070047template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070048class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070049 std::unordered_map<TKey, TEntry> map;
50
Mark Salyzyn6d981af2016-10-06 09:55:21 -070051 size_t bucket_size() const {
52 size_t count = 0;
53 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
54 size_t bucket_size = map.bucket_size(idx);
55 if (bucket_size == 0) bucket_size = 1;
56 count += bucket_size;
57 }
58 float load_factor = map.max_load_factor();
59 if (load_factor < 1.0) return count;
60 return count * load_factor;
61 }
62
63 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
64 static const size_t unordered_map_bucket_overhead = sizeof(void*);
65
Mark Salyzyn501c3732017-03-10 14:31:54 -080066 public:
67 size_t size() const {
68 return map.size();
69 }
Mark Salyzynb0672292016-10-06 10:09:24 -070070
Mark Salyzyn6d981af2016-10-06 09:55:21 -070071 // Estimate unordered_map memory usage.
72 size_t sizeOf() const {
73 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070074 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070075 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
76 }
77
Mark Salyzyn511338d2015-05-19 09:12:30 -070078 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080079 typedef
80 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070081
Mark Salyzyn501c3732017-03-10 14:31:54 -080082 std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
Mark Salyzynee3b8382015-12-17 09:58:43 -080083 size_t len) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -070084 if (!len) {
Mark Salyzynf99a7d62017-04-19 14:39:21 -070085 std::unique_ptr<const TEntry* []> sorted(nullptr);
Mark Salyzyn720f6d12015-03-16 08:26:05 -070086 return sorted;
87 }
88
Mark Salyzyn501c3732017-03-10 14:31:54 -080089 const TEntry** retval = new const TEntry*[len];
Mark Salyzyn758058f2015-08-21 16:44:30 -070090 memset(retval, 0, sizeof(*retval) * len);
Mark Salyzyn720f6d12015-03-16 08:26:05 -070091
Mark Salyzyn501c3732017-03-10 14:31:54 -080092 for (const_iterator it = map.begin(); it != map.end(); ++it) {
93 const TEntry& entry = it->second;
Mark Salyzynee3b8382015-12-17 09:58:43 -080094
95 if ((uid != AID_ROOT) && (uid != entry.getUid())) {
96 continue;
97 }
98 if (pid && entry.getPid() && (pid != entry.getPid())) {
99 continue;
100 }
101
Mark Salyzyn758058f2015-08-21 16:44:30 -0700102 size_t sizes = entry.getSizes();
103 ssize_t index = len - 1;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800104 while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
105 (--index >= 0))
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700106 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700107 if (++index < (ssize_t)len) {
108 size_t num = len - index - 1;
109 if (num) {
110 memmove(&retval[index + 1], &retval[index],
111 num * sizeof(retval[0]));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700112 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700113 retval[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700114 }
115 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800116 std::unique_ptr<const TEntry* []> sorted(retval);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700117 return sorted;
118 }
119
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700120 inline iterator add(const TKey& key, const LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700121 iterator it = map.find(key);
122 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700123 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700124 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700125 it->second.add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700126 }
127 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700128 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700129
Mark Salyzyn511338d2015-05-19 09:12:30 -0700130 inline iterator add(TKey key) {
131 iterator it = map.find(key);
132 if (it == map.end()) {
133 it = map.insert(std::make_pair(key, TEntry(key))).first;
134 } else {
135 it->second.add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700136 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700137 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700138 }
139
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700140 void subtract(TKey&& key, const LogBufferElement* element) {
141 iterator it = map.find(std::move(key));
142 if ((it != map.end()) && it->second.subtract(element)) {
143 map.erase(it);
144 }
145 }
146
147 void subtract(const TKey& key, const LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700148 iterator it = map.find(key);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700149 if ((it != map.end()) && it->second.subtract(element)) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700150 map.erase(it);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700151 }
152 }
153
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700154 inline void drop(TKey key, const LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700155 iterator it = map.find(key);
156 if (it != map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700157 it->second.drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700158 }
159 }
160
Mark Salyzyn501c3732017-03-10 14:31:54 -0800161 inline iterator begin() {
162 return map.begin();
163 }
164 inline const_iterator begin() const {
165 return map.begin();
166 }
167 inline iterator end() {
168 return map.end();
169 }
170 inline const_iterator end() const {
171 return map.end();
172 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700173
Mark Salyzyn501c3732017-03-10 14:31:54 -0800174 std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
175 const std::string& name = std::string(""),
176 log_id_t id = LOG_ID_MAX) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700177 static const size_t maximum_sorted_entries = 32;
178 std::string output;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800179 std::unique_ptr<const TEntry* []> sorted =
180 sort(uid, pid, maximum_sorted_entries);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700181 if (!sorted.get()) {
182 return output;
183 }
184 bool headerPrinted = false;
185 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800186 const TEntry* entry = sorted[index];
Mark Salyzyn758058f2015-08-21 16:44:30 -0700187 if (!entry) {
188 break;
189 }
190 if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
191 break;
192 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700193 if (!headerPrinted) {
194 output += "\n\n";
195 output += entry->formatHeader(name, id);
196 headerPrinted = true;
197 }
198 output += entry->format(stat, id);
199 }
200 return output;
201 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700202};
203
Mark Salyzyn758058f2015-08-21 16:44:30 -0700204namespace EntryBaseConstants {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800205static constexpr size_t pruned_len = 14;
206static constexpr size_t total_len = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700207}
208
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700209struct EntryBase {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700210 size_t size;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700211
Mark Salyzyn501c3732017-03-10 14:31:54 -0800212 EntryBase() : size(0) {
213 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700214 explicit EntryBase(const LogBufferElement* element)
215 : size(element->getMsgLen()) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800216 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700217
Mark Salyzyn501c3732017-03-10 14:31:54 -0800218 size_t getSizes() const {
219 return size;
220 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700221
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700222 inline void add(const LogBufferElement* element) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800223 size += element->getMsgLen();
224 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700225 inline bool subtract(const LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700226 size -= element->getMsgLen();
227 return !size;
228 }
229
Mark Salyzyn501c3732017-03-10 14:31:54 -0800230 static std::string formatLine(const std::string& name,
231 const std::string& size,
232 const std::string& pruned) {
233 ssize_t drop_len =
234 std::max(pruned.length() + 1, EntryBaseConstants::pruned_len);
235 ssize_t size_len =
236 std::max(size.length() + 1, EntryBaseConstants::total_len -
237 name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700238
Mark Salyzyn501c3732017-03-10 14:31:54 -0800239 std::string ret = android::base::StringPrintf(
240 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
241 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800242 // remove any trailing spaces
243 size_t pos = ret.size();
244 size_t len = 0;
245 while (pos && isspace(ret[--pos])) ++len;
246 if (len) ret.erase(pos + 1, len);
247 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700248 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700249};
250
251struct EntryBaseDropped : public EntryBase {
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700252 size_t dropped;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800253
Mark Salyzyn501c3732017-03-10 14:31:54 -0800254 EntryBaseDropped() : dropped(0) {
255 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700256 explicit EntryBaseDropped(const LogBufferElement* element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800257 : EntryBase(element), dropped(element->getDropped()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700258 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800259
Mark Salyzyn501c3732017-03-10 14:31:54 -0800260 size_t getDropped() const {
261 return dropped;
262 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700263
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700264 inline void add(const LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700265 dropped += element->getDropped();
266 EntryBase::add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700267 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700268 inline bool subtract(const LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700269 dropped -= element->getDropped();
270 return EntryBase::subtract(element) && !dropped;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700271 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700272 inline void drop(const LogBufferElement* element) {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700273 dropped += 1;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700274 EntryBase::subtract(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700275 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800276};
277
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700278struct UidEntry : public EntryBaseDropped {
279 const uid_t uid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800280 pid_t pid;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700281
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700282 explicit UidEntry(const LogBufferElement* element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800283 : EntryBaseDropped(element),
284 uid(element->getUid()),
285 pid(element->getPid()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700286 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700287
Mark Salyzyn501c3732017-03-10 14:31:54 -0800288 inline const uid_t& getKey() const {
289 return uid;
290 }
291 inline const uid_t& getUid() const {
292 return getKey();
293 }
294 inline const pid_t& getPid() const {
295 return pid;
296 }
Mark Salyzynee3b8382015-12-17 09:58:43 -0800297
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700298 inline void add(const LogBufferElement* element) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800299 if (pid != element->getPid()) {
300 pid = -1;
301 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800302 EntryBaseDropped::add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800303 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700304
Mark Salyzyn501c3732017-03-10 14:31:54 -0800305 std::string formatHeader(const std::string& name, log_id_t id) const;
306 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700307};
308
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700309struct PidEntry : public EntryBaseDropped {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700310 const pid_t pid;
311 uid_t uid;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800312 char* name;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700313
Mark Salyzyn501c3732017-03-10 14:31:54 -0800314 explicit PidEntry(pid_t pid)
315 : EntryBaseDropped(),
316 pid(pid),
317 uid(android::pidToUid(pid)),
318 name(android::pidToName(pid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700319 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700320 explicit PidEntry(const LogBufferElement* element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800321 : EntryBaseDropped(element),
322 pid(element->getPid()),
323 uid(element->getUid()),
324 name(android::pidToName(pid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700325 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800326 PidEntry(const PidEntry& element)
327 : EntryBaseDropped(element),
328 pid(element.pid),
329 uid(element.uid),
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700330 name(element.name ? strdup(element.name) : nullptr) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700331 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800332 ~PidEntry() {
333 free(name);
334 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700335
Mark Salyzyn501c3732017-03-10 14:31:54 -0800336 const pid_t& getKey() const {
337 return pid;
338 }
339 const pid_t& getPid() const {
340 return getKey();
341 }
342 const uid_t& getUid() const {
343 return uid;
344 }
345 const char* getName() const {
346 return name;
347 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700348
Mark Salyzyn758058f2015-08-21 16:44:30 -0700349 inline void add(pid_t newPid) {
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800350 if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700351 free(name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700352 name = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700353 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700354 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700355 name = android::pidToName(newPid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700356 }
357 }
358
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700359 inline void add(const LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700360 uid_t incomingUid = element->getUid();
361 if (getUid() != incomingUid) {
362 uid = incomingUid;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700363 free(name);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700364 name = android::pidToName(element->getPid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700365 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700366 add(element->getPid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700367 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700368 EntryBaseDropped::add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700369 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700370
Mark Salyzyn501c3732017-03-10 14:31:54 -0800371 std::string formatHeader(const std::string& name, log_id_t id) const;
372 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700373};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700374
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700375struct TidEntry : public EntryBaseDropped {
376 const pid_t tid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800377 pid_t pid;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700378 uid_t uid;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800379 char* name;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700380
Mark Salyzyn501c3732017-03-10 14:31:54 -0800381 TidEntry(pid_t tid, pid_t pid)
382 : EntryBaseDropped(),
383 tid(tid),
384 pid(pid),
385 uid(android::pidToUid(tid)),
386 name(android::tidToName(tid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700387 }
Mark Salyzync4e48232017-05-04 13:54:46 -0700388 TidEntry(pid_t tid)
389 : EntryBaseDropped(),
390 tid(tid),
391 pid(android::tidToPid(tid)),
392 uid(android::pidToUid(tid)),
393 name(android::tidToName(tid)) {
394 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700395 explicit TidEntry(const LogBufferElement* element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800396 : EntryBaseDropped(element),
397 tid(element->getTid()),
398 pid(element->getPid()),
399 uid(element->getUid()),
400 name(android::tidToName(tid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700401 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800402 TidEntry(const TidEntry& element)
403 : EntryBaseDropped(element),
404 tid(element.tid),
405 pid(element.pid),
406 uid(element.uid),
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700407 name(element.name ? strdup(element.name) : nullptr) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700408 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800409 ~TidEntry() {
410 free(name);
411 }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700412
Mark Salyzyn501c3732017-03-10 14:31:54 -0800413 const pid_t& getKey() const {
414 return tid;
415 }
416 const pid_t& getTid() const {
417 return getKey();
418 }
419 const pid_t& getPid() const {
420 return pid;
421 }
422 const uid_t& getUid() const {
423 return uid;
424 }
425 const char* getName() const {
426 return name;
427 }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700428
Mark Salyzyn758058f2015-08-21 16:44:30 -0700429 inline void add(pid_t incomingTid) {
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800430 if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700431 free(name);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700432 name = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700433 }
434 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700435 name = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700436 }
437 }
438
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700439 inline void add(const LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700440 uid_t incomingUid = element->getUid();
Mark Salyzynee3b8382015-12-17 09:58:43 -0800441 pid_t incomingPid = element->getPid();
442 if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700443 uid = incomingUid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800444 pid = incomingPid;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700445 free(name);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700446 name = android::tidToName(element->getTid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700447 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700448 add(element->getTid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700449 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700450 EntryBaseDropped::add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700451 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700452
Mark Salyzyn501c3732017-03-10 14:31:54 -0800453 std::string formatHeader(const std::string& name, log_id_t id) const;
454 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700455};
456
Mark Salyzyn6a066942016-07-14 15:34:30 -0700457struct TagEntry : public EntryBaseDropped {
Mark Salyzyn344bff42015-04-13 14:24:45 -0700458 const uint32_t tag;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800459 pid_t pid;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700460 uid_t uid;
461
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700462 explicit TagEntry(const LogBufferElement* element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800463 : EntryBaseDropped(element),
464 tag(element->getTag()),
465 pid(element->getPid()),
466 uid(element->getUid()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700467 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700468
Mark Salyzyn501c3732017-03-10 14:31:54 -0800469 const uint32_t& getKey() const {
470 return tag;
471 }
472 const pid_t& getPid() const {
473 return pid;
474 }
475 const uid_t& getUid() const {
476 return uid;
477 }
478 const char* getName() const {
479 return android::tagToName(tag);
480 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700481
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700482 inline void add(const LogBufferElement* element) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800483 if (uid != element->getUid()) {
Mark Salyzyn344bff42015-04-13 14:24:45 -0700484 uid = -1;
485 }
Mark Salyzynee3b8382015-12-17 09:58:43 -0800486 if (pid != element->getPid()) {
487 pid = -1;
488 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800489 EntryBaseDropped::add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700490 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700491
Mark Salyzyn501c3732017-03-10 14:31:54 -0800492 std::string formatHeader(const std::string& name, log_id_t id) const;
493 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700494};
495
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700496struct TagNameKey {
497 std::string* alloc;
Elliott Hughese8058832017-11-30 16:31:35 -0800498 std::string_view name; // Saves space if const char*
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700499
500 explicit TagNameKey(const LogBufferElement* element)
501 : alloc(nullptr), name("", strlen("")) {
502 if (element->isBinary()) {
503 uint32_t tag = element->getTag();
504 if (tag) {
505 const char* cp = android::tagToName(tag);
506 if (cp) {
Elliott Hughese8058832017-11-30 16:31:35 -0800507 name = std::string_view(cp, strlen(cp));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700508 return;
509 }
510 }
511 alloc = new std::string(
512 android::base::StringPrintf("[%" PRIu32 "]", tag));
513 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800514 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700515 return;
516 }
517 const char* msg = element->getMsg();
518 if (!msg) {
Elliott Hughese8058832017-11-30 16:31:35 -0800519 name = std::string_view("chatty", strlen("chatty"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700520 return;
521 }
522 ++msg;
523 unsigned short len = element->getMsgLen();
524 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
525 if (!len) {
Elliott Hughese8058832017-11-30 16:31:35 -0800526 name = std::string_view("<NULL>", strlen("<NULL>"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700527 return;
528 }
529 alloc = new std::string(msg, len);
530 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800531 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700532 }
533
534 explicit TagNameKey(TagNameKey&& rval)
535 : alloc(rval.alloc), name(rval.name.data(), rval.name.length()) {
536 rval.alloc = nullptr;
537 }
538
539 explicit TagNameKey(const TagNameKey& rval)
540 : alloc(rval.alloc ? new std::string(*rval.alloc) : nullptr),
541 name(alloc ? alloc->data() : rval.name.data(), rval.name.length()) {
542 }
543
544 ~TagNameKey() {
545 if (alloc) delete alloc;
546 }
547
Elliott Hughese8058832017-11-30 16:31:35 -0800548 operator const std::string_view() const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700549 return name;
550 }
551
552 const char* data() const {
553 return name.data();
554 }
555 size_t length() const {
556 return name.length();
557 }
558
559 bool operator==(const TagNameKey& rval) const {
560 if (length() != rval.length()) return false;
561 if (length() == 0) return true;
562 return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
563 }
564 bool operator!=(const TagNameKey& rval) const {
565 return !(*this == rval);
566 }
567
568 size_t getAllocLength() const {
569 return alloc ? alloc->length() + 1 + sizeof(std::string) : 0;
570 }
571};
572
573// Hash for TagNameKey
574template <>
575struct std::hash<TagNameKey>
576 : public std::unary_function<const TagNameKey&, size_t> {
577 size_t operator()(const TagNameKey& __t) const noexcept {
578 if (!__t.length()) return 0;
Elliott Hughese8058832017-11-30 16:31:35 -0800579 return std::hash<std::string_view>()(std::string_view(__t));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700580 }
581};
582
583struct TagNameEntry : public EntryBase {
584 pid_t tid;
585 pid_t pid;
586 uid_t uid;
587 TagNameKey name;
588
589 explicit TagNameEntry(const LogBufferElement* element)
590 : EntryBase(element),
591 tid(element->getTid()),
592 pid(element->getPid()),
593 uid(element->getUid()),
594 name(element) {
595 }
596
597 const TagNameKey& getKey() const {
598 return name;
599 }
600 const pid_t& getTid() const {
601 return tid;
602 }
603 const pid_t& getPid() const {
604 return pid;
605 }
606 const uid_t& getUid() const {
607 return uid;
608 }
609 const char* getName() const {
610 return name.data();
611 }
612 size_t getNameAllocLength() const {
613 return name.getAllocLength();
614 }
615
616 inline void add(const LogBufferElement* element) {
617 if (uid != element->getUid()) {
618 uid = -1;
619 }
620 if (pid != element->getPid()) {
621 pid = -1;
622 }
623 if (tid != element->getTid()) {
624 tid = -1;
625 }
626 EntryBase::add(element);
627 }
628
629 std::string formatHeader(const std::string& name, log_id_t id) const;
630 std::string format(const LogStatistics& stat, log_id_t id) const;
631};
632
Mark Salyzyn6a066942016-07-14 15:34:30 -0700633template <typename TEntry>
634class LogFindWorst {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800635 std::unique_ptr<const TEntry* []> sorted;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700636
Mark Salyzyn501c3732017-03-10 14:31:54 -0800637 public:
638 explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
639 : sorted(std::move(sorted)) {
640 }
Mark Salyzyn6a066942016-07-14 15:34:30 -0700641
Mark Salyzyn501c3732017-03-10 14:31:54 -0800642 void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
643 size_t threshold) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700644 if (sorted.get() && sorted[0] && sorted[1]) {
645 worst_sizes = sorted[0]->getSizes();
646 if ((worst_sizes > threshold)
647 // Allow time horizon to extend roughly tenfold, assume
648 // average entry length is 100 characters.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800649 && (worst_sizes > (10 * sorted[0]->getDropped()))) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700650 worst = sorted[0]->getKey();
651 second_worst_sizes = sorted[1]->getSizes();
652 if (second_worst_sizes < threshold) {
653 second_worst_sizes = threshold;
654 }
655 }
656 }
657 }
658
Mark Salyzyn501c3732017-03-10 14:31:54 -0800659 void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700660 if (sorted.get() && sorted[0] && sorted[1]) {
661 worst = sorted[0]->getKey();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800662 second_worst_sizes =
663 worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700664 }
665 }
666};
667
Mark Salyzyn34facab2014-02-06 14:48:50 -0800668// Log Statistics
669class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700670 friend UidEntry;
671
Mark Salyzyn34facab2014-02-06 14:48:50 -0800672 size_t mSizes[LOG_ID_MAX];
673 size_t mElements[LOG_ID_MAX];
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700674 size_t mDroppedElements[LOG_ID_MAX];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700675 size_t mSizesTotal[LOG_ID_MAX];
676 size_t mElementsTotal[LOG_ID_MAX];
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700677 log_time mOldest[LOG_ID_MAX];
678 log_time mNewest[LOG_ID_MAX];
679 log_time mNewestDropped[LOG_ID_MAX];
Mark Salyzyn32962912016-09-12 10:29:17 -0700680 static size_t SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700681 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800682
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700683 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700684 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700685 uidTable_t uidTable[LOG_ID_MAX];
Mark Salyzyne457b742014-02-19 17:18:31 -0800686
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700687 // pid of system to size list
688 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
689 pidSystemTable_t pidSystemTable[LOG_ID_MAX];
690
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700691 // pid to uid list
692 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
693 pidTable_t pidTable;
694
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700695 // tid to uid list
696 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
697 tidTable_t tidTable;
698
Mark Salyzyn344bff42015-04-13 14:24:45 -0700699 // tag list
700 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
701 tagTable_t tagTable;
702
Mark Salyzyn083b0372015-12-04 10:59:45 -0800703 // security tag list
704 tagTable_t securityTagTable;
705
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700706 // global tag list
707 typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
708 tagNameTable_t tagNameTable;
709
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700710 size_t sizeOf() const {
711 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700712 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700713 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700714 (pidTable.size() * sizeof(pidTable_t::iterator)) +
715 (tagTable.size() * sizeof(tagTable_t::iterator));
Mark Salyzyn501c3732017-03-10 14:31:54 -0800716 for (auto it : pidTable) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700717 const char* name = it.second.getName();
718 if (name) size += strlen(name) + 1;
719 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800720 for (auto it : tidTable) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700721 const char* name = it.second.getName();
722 if (name) size += strlen(name) + 1;
723 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700724 for (auto it : tagNameTable) size += it.second.getNameAllocLength();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700725 log_id_for_each(id) {
726 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700727 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700728 size += pidSystemTable[id].sizeOf();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800729 size +=
730 pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700731 }
732 return size;
733 }
734
Mark Salyzyn501c3732017-03-10 14:31:54 -0800735 public:
Mark Salyzyn34facab2014-02-06 14:48:50 -0800736 LogStatistics();
737
Mark Salyzyn501c3732017-03-10 14:31:54 -0800738 void enableStatistics() {
739 enable = true;
740 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800741
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700742 void addTotal(LogBufferElement* entry);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800743 void add(LogBufferElement* entry);
744 void subtract(LogBufferElement* entry);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700745 // entry->setDropped(1) must follow this call
Mark Salyzyn501c3732017-03-10 14:31:54 -0800746 void drop(LogBufferElement* entry);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700747 // Correct for coalescing two entries referencing dropped content
Mark Salyzyn501c3732017-03-10 14:31:54 -0800748 void erase(LogBufferElement* element) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700749 log_id_t log_id = element->getLogId();
750 --mElements[log_id];
751 --mDroppedElements[log_id];
752 }
Mark Salyzyne457b742014-02-19 17:18:31 -0800753
Mark Salyzyn6a066942016-07-14 15:34:30 -0700754 LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
755 return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700756 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800757 LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
758 log_id id) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700759 return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
760 }
761 LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
762 return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700763 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800764
765 // fast track current value by id only
Mark Salyzyn501c3732017-03-10 14:31:54 -0800766 size_t sizes(log_id_t id) const {
767 return mSizes[id];
768 }
769 size_t elements(log_id_t id) const {
770 return mElements[id];
771 }
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700772 size_t realElements(log_id_t id) const {
773 return mElements[id] - mDroppedElements[id];
774 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800775 size_t sizesTotal(log_id_t id) const {
776 return mSizesTotal[id];
777 }
778 size_t elementsTotal(log_id_t id) const {
779 return mElementsTotal[id];
780 }
781 static size_t sizesTotal() {
782 return SizesTotal;
783 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800784
Mark Salyzynee3b8382015-12-17 09:58:43 -0800785 std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
Mark Salyzyn9a038632014-04-07 07:05:40 -0700786
Mark Salyzyned777e92015-06-24 16:22:54 -0700787 // helper (must be locked directly or implicitly by mLogElementsLock)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800788 const char* pidToName(pid_t pid) const;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700789 uid_t pidToUid(pid_t pid);
Mark Salyzync4e48232017-05-04 13:54:46 -0700790 pid_t tidToPid(pid_t tid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800791 const char* uidToName(uid_t uid) const;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800792};
793
Mark Salyzyn501c3732017-03-10 14:31:54 -0800794#endif // _LOGD_LOG_STATISTICS_H__