blob: e222d3f244a03639b0ab62fee0f9f142a5567e24 [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 Cherryb6b78e92020-05-07 09:13:12 -070017#pragma once
Mark Salyzyn34facab2014-02-06 14:48:50 -080018
Mark Salyzynb545e1c2016-12-19 14:51:15 -080019#include <ctype.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070020#include <inttypes.h>
21#include <stdint.h>
Mark Salyzyn720f6d12015-03-16 08:26:05 -070022#include <stdlib.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070023#include <string.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080024#include <sys/types.h>
25
Mark Salyzyn501c3732017-03-10 14:31:54 -080026#include <algorithm> // std::max
Tom Cherryb6b78e92020-05-07 09:13:12 -070027#include <array>
Mark Salyzynb545e1c2016-12-19 14:51:15 -080028#include <memory>
Tom Cherry64e90162020-05-07 14:44:43 -070029#include <mutex>
Elliott Hughese8058832017-11-30 16:31:35 -080030#include <string>
31#include <string_view>
Mark Salyzyn511338d2015-05-19 09:12:30 -070032#include <unordered_map>
33
Elliott Hughes4f713192015-12-04 22:00:26 -080034#include <android-base/stringprintf.h>
Tom Cherry64e90162020-05-07 14:44:43 -070035#include <android-base/thread_annotations.h>
Mark Salyzyn501c3732017-03-10 14:31:54 -080036#include <android/log.h>
Mark Salyzyn03bb7592017-04-14 09:46:57 -070037#include <log/log_time.h>
Mark Salyzyn758058f2015-08-21 16:44:30 -070038#include <private/android_filesystem_config.h>
Mark Salyzynf99a7d62017-04-19 14:39:21 -070039#include <utils/FastStrcmp.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070040
Mark Salyzyn5ac5c6b2015-08-28 08:02:59 -070041#include "LogUtils.h"
Mark Salyzyn34facab2014-02-06 14:48:50 -080042
43#define log_id_for_each(i) \
Mark Salyzyn501c3732017-03-10 14:31:54 -080044 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 -080045
Mark Salyzyn758058f2015-08-21 16:44:30 -070046class LogStatistics;
Tom Cherry4596b782020-06-03 13:49:24 -070047class UidEntry;
48class PidEntry;
Mark Salyzyn758058f2015-08-21 16:44:30 -070049
Tom Cherry3dd3ec32020-06-02 15:39:21 -070050struct LogStatisticsElement {
51 uid_t uid;
52 pid_t pid;
53 pid_t tid;
54 uint32_t tag;
55 log_time realtime;
56 const char* msg;
57 uint16_t msg_len;
58 uint16_t dropped_count;
59 log_id_t log_id;
Tom Cherryf74503d2020-06-19 12:21:21 -070060 uint16_t total_len;
Tom Cherry3dd3ec32020-06-02 15:39:21 -070061};
62
Mark Salyzyn720f6d12015-03-16 08:26:05 -070063template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070064class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070065 std::unordered_map<TKey, TEntry> map;
66
Mark Salyzyn6d981af2016-10-06 09:55:21 -070067 size_t bucket_size() const {
68 size_t count = 0;
69 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
70 size_t bucket_size = map.bucket_size(idx);
71 if (bucket_size == 0) bucket_size = 1;
72 count += bucket_size;
73 }
74 float load_factor = map.max_load_factor();
75 if (load_factor < 1.0) return count;
76 return count * load_factor;
77 }
78
79 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
80 static const size_t unordered_map_bucket_overhead = sizeof(void*);
81
Tom Cherry9787f9a2020-05-19 19:01:16 -070082 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -080083 size_t size() const {
84 return map.size();
85 }
Mark Salyzynb0672292016-10-06 10:09:24 -070086
Mark Salyzyn6d981af2016-10-06 09:55:21 -070087 // Estimate unordered_map memory usage.
88 size_t sizeOf() const {
89 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070090 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070091 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
92 }
93
Mark Salyzyn511338d2015-05-19 09:12:30 -070094 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080095 typedef
96 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070097
Tom Cherryb6b78e92020-05-07 09:13:12 -070098 // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
99 // entries are found, their positions are set to nullptr.
100 template <size_t len>
Tom Cherry4596b782020-06-03 13:49:24 -0700101 void MaxEntries(uid_t uid, pid_t pid, std::array<const TKey*, len>& out_keys,
102 std::array<const TEntry*, len>& out_entries) const {
103 out_keys.fill(nullptr);
104 out_entries.fill(nullptr);
105 for (const auto& [key, entry] : map) {
106 uid_t entry_uid = 0;
107 if constexpr (std::is_same_v<TEntry, UidEntry>) {
108 entry_uid = key;
109 } else {
110 entry_uid = entry.uid();
111 }
112 if (uid != AID_ROOT && uid != entry_uid) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800113 continue;
114 }
Tom Cherry4596b782020-06-03 13:49:24 -0700115 pid_t entry_pid = 0;
116 if constexpr (std::is_same_v<TEntry, PidEntry>) {
117 entry_pid = key;
118 } else {
119 entry_pid = entry.pid();
120 }
121 if (pid && entry_pid && pid != entry_pid) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800122 continue;
123 }
124
Mark Salyzyn758058f2015-08-21 16:44:30 -0700125 size_t sizes = entry.getSizes();
126 ssize_t index = len - 1;
Tom Cherry4596b782020-06-03 13:49:24 -0700127 while ((!out_entries[index] || sizes > out_entries[index]->getSizes()) && --index >= 0)
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700128 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700129 if (++index < (ssize_t)len) {
130 size_t num = len - index - 1;
131 if (num) {
Tom Cherry9b4246d2020-06-17 11:40:55 -0700132 memmove(&out_keys[index + 1], &out_keys[index], num * sizeof(const TKey*));
Tom Cherry4596b782020-06-03 13:49:24 -0700133 memmove(&out_entries[index + 1], &out_entries[index],
Tom Cherry9b4246d2020-06-17 11:40:55 -0700134 num * sizeof(const TEntry*));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700135 }
Tom Cherry4596b782020-06-03 13:49:24 -0700136 out_keys[index] = &key;
137 out_entries[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700138 }
139 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700140 }
141
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700142 iterator Add(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700143 iterator it = map.find(key);
144 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700145 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700146 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700147 it->second.Add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700148 }
149 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700150 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700151
Tom Cherry9787f9a2020-05-19 19:01:16 -0700152 iterator Add(const TKey& key) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700153 iterator it = map.find(key);
154 if (it == map.end()) {
155 it = map.insert(std::make_pair(key, TEntry(key))).first;
156 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700157 it->second.Add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700158 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700159 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700160 }
161
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700162 void Subtract(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700163 iterator it = map.find(key);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700164 if (it != map.end() && it->second.Subtract(element)) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700165 map.erase(it);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700166 }
167 }
168
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700169 void Drop(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700170 iterator it = map.find(key);
171 if (it != map.end()) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700172 it->second.Drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700173 }
174 }
175
Tom Cherryf74503d2020-06-19 12:21:21 -0700176 void Erase(const TKey& key, const LogStatisticsElement& element) {
177 iterator it = map.find(key);
178 if (it != map.end()) {
179 it->second.Erase(element);
180 }
181 }
182
Tom Cherry9787f9a2020-05-19 19:01:16 -0700183 iterator begin() { return map.begin(); }
184 const_iterator begin() const { return map.begin(); }
185 iterator end() { return map.end(); }
186 const_iterator end() const { return map.end(); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700187};
188
Tom Cherry9787f9a2020-05-19 19:01:16 -0700189class EntryBase {
190 public:
191 EntryBase() : size_(0) {}
Tom Cherryf74503d2020-06-19 12:21:21 -0700192 explicit EntryBase(const LogStatisticsElement& element) : size_(element.total_len) {}
Mark Salyzyn758058f2015-08-21 16:44:30 -0700193
Tom Cherry9787f9a2020-05-19 19:01:16 -0700194 size_t getSizes() const { return size_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700195
Tom Cherryf74503d2020-06-19 12:21:21 -0700196 void Add(const LogStatisticsElement& element) { size_ += element.total_len; }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700197 bool Subtract(const LogStatisticsElement& element) {
Tom Cherryf74503d2020-06-19 12:21:21 -0700198 size_ -= element.total_len;
199 return size_ == 0;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800200 }
Tom Cherryf74503d2020-06-19 12:21:21 -0700201 void Drop(const LogStatisticsElement& element) { size_ -= element.msg_len; }
202 void Erase(const LogStatisticsElement& element) { size_ -= element.total_len; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700203
Tom Cherry9787f9a2020-05-19 19:01:16 -0700204 static constexpr size_t PRUNED_LEN = 14;
205 static constexpr size_t TOTAL_LEN = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700206
Mark Salyzyn501c3732017-03-10 14:31:54 -0800207 static std::string formatLine(const std::string& name,
208 const std::string& size,
209 const std::string& pruned) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700210 ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
211 ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700212
Mark Salyzyn501c3732017-03-10 14:31:54 -0800213 std::string ret = android::base::StringPrintf(
214 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
215 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800216 // remove any trailing spaces
217 size_t pos = ret.size();
218 size_t len = 0;
219 while (pos && isspace(ret[--pos])) ++len;
220 if (len) ret.erase(pos + 1, len);
221 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700222 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700223
224 private:
225 size_t size_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700226};
227
Tom Cherry9787f9a2020-05-19 19:01:16 -0700228class EntryBaseDropped : public EntryBase {
229 public:
230 EntryBaseDropped() : dropped_(0) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700231 explicit EntryBaseDropped(const LogStatisticsElement& element)
232 : EntryBase(element), dropped_(element.dropped_count) {}
Mark Salyzyn34facab2014-02-06 14:48:50 -0800233
Tom Cherry9787f9a2020-05-19 19:01:16 -0700234 size_t dropped_count() const { return dropped_; }
235
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700236 void Add(const LogStatisticsElement& element) {
237 dropped_ += element.dropped_count;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700238 EntryBase::Add(element);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800239 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700240 bool Subtract(const LogStatisticsElement& element) {
241 dropped_ -= element.dropped_count;
Tom Cherryf74503d2020-06-19 12:21:21 -0700242 return EntryBase::Subtract(element) && dropped_ == 0;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700243 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700244 void Drop(const LogStatisticsElement& element) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700245 dropped_ += 1;
Tom Cherryf74503d2020-06-19 12:21:21 -0700246 EntryBase::Drop(element);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700247 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800248
Tom Cherry9787f9a2020-05-19 19:01:16 -0700249 private:
250 size_t dropped_;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800251};
252
Tom Cherry9787f9a2020-05-19 19:01:16 -0700253class UidEntry : public EntryBaseDropped {
254 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700255 explicit UidEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700256 : EntryBaseDropped(element), pid_(element.pid) {}
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700257
Tom Cherry9787f9a2020-05-19 19:01:16 -0700258 pid_t pid() const { return pid_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700259
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700260 void Add(const LogStatisticsElement& element) {
261 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700262 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800263 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700264 EntryBaseDropped::Add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800265 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700266
Mark Salyzyn501c3732017-03-10 14:31:54 -0800267 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700268 std::string format(const LogStatistics& stat, log_id_t id, uid_t uid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700269
270 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700271 pid_t pid_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700272};
273
Tom Cherry40da03b2019-06-28 13:21:27 -0700274namespace android {
275uid_t pidToUid(pid_t pid);
276}
277
Tom Cherry9787f9a2020-05-19 19:01:16 -0700278class PidEntry : public EntryBaseDropped {
279 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800280 explicit PidEntry(pid_t pid)
281 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700282 uid_(android::pidToUid(pid)),
283 name_(android::pidToName(pid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700284 explicit PidEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700285 : EntryBaseDropped(element), uid_(element.uid), name_(android::pidToName(element.pid)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800286 PidEntry(const PidEntry& element)
287 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700288 uid_(element.uid_),
289 name_(element.name_ ? strdup(element.name_) : nullptr) {}
290 ~PidEntry() { free(name_); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700291
Tom Cherry9787f9a2020-05-19 19:01:16 -0700292 uid_t uid() const { return uid_; }
293 const char* name() const { return name_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700294
Tom Cherry9787f9a2020-05-19 19:01:16 -0700295 void Add(pid_t new_pid) {
296 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
297 free(name_);
298 name_ = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700299 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700300 if (!name_) {
301 name_ = android::pidToName(new_pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700302 }
303 }
304
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700305 void Add(const LogStatisticsElement& element) {
306 uid_t incoming_uid = element.uid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700307 if (uid() != incoming_uid) {
308 uid_ = incoming_uid;
309 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700310 name_ = android::pidToName(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700311 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700312 Add(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700313 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700314 EntryBaseDropped::Add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700315 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700316
Mark Salyzyn501c3732017-03-10 14:31:54 -0800317 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700318 std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700319
320 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700321 uid_t uid_;
322 char* name_;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700323};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700324
Tom Cherry9787f9a2020-05-19 19:01:16 -0700325class TidEntry : public EntryBaseDropped {
326 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800327 TidEntry(pid_t tid, pid_t pid)
328 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700329 pid_(pid),
330 uid_(android::pidToUid(tid)),
331 name_(android::tidToName(tid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700332 explicit TidEntry(const LogStatisticsElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800333 : EntryBaseDropped(element),
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700334 pid_(element.pid),
335 uid_(element.uid),
Tom Cherry4596b782020-06-03 13:49:24 -0700336 name_(android::tidToName(element.tid)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800337 TidEntry(const TidEntry& element)
338 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700339 pid_(element.pid_),
340 uid_(element.uid_),
341 name_(element.name_ ? strdup(element.name_) : nullptr) {}
342 ~TidEntry() { free(name_); }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700343
Tom Cherry9787f9a2020-05-19 19:01:16 -0700344 pid_t pid() const { return pid_; }
345 uid_t uid() const { return uid_; }
346 const char* name() const { return name_; }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700347
Tom Cherry9787f9a2020-05-19 19:01:16 -0700348 void Add(pid_t incomingTid) {
349 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
350 free(name_);
351 name_ = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700352 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700353 if (!name_) {
354 name_ = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700355 }
356 }
357
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700358 void Add(const LogStatisticsElement& element) {
359 uid_t incoming_uid = element.uid;
360 pid_t incoming_pid = element.pid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700361 if (uid() != incoming_uid || pid() != incoming_pid) {
362 uid_ = incoming_uid;
363 pid_ = incoming_pid;
364 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700365 name_ = android::tidToName(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700366 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700367 Add(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700368 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700369 EntryBaseDropped::Add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700370 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700371
Mark Salyzyn501c3732017-03-10 14:31:54 -0800372 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700373 std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700374
375 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700376 pid_t pid_;
377 uid_t uid_;
378 char* name_;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700379};
380
Tom Cherry9787f9a2020-05-19 19:01:16 -0700381class TagEntry : public EntryBaseDropped {
382 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700383 explicit TagEntry(const LogStatisticsElement& element)
384 : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
Mark Salyzyn344bff42015-04-13 14:24:45 -0700385
Tom Cherry9787f9a2020-05-19 19:01:16 -0700386 uint32_t key() const { return tag_; }
387 pid_t pid() const { return pid_; }
388 uid_t uid() const { return uid_; }
389 const char* name() const { return android::tagToName(tag_); }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700390
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700391 void Add(const LogStatisticsElement& element) {
392 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700393 uid_ = -1;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700394 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700395 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700396 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800397 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700398 EntryBaseDropped::Add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700399 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700400
Mark Salyzyn501c3732017-03-10 14:31:54 -0800401 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700402 std::string format(const LogStatistics& stat, log_id_t id, uint32_t) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700403
404 private:
405 const uint32_t tag_;
406 pid_t pid_;
407 uid_t uid_;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700408};
409
Tom Cherry9787f9a2020-05-19 19:01:16 -0700410class TagNameEntry : public EntryBase {
411 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700412 explicit TagNameEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700413 : EntryBase(element), tid_(element.tid), pid_(element.pid), uid_(element.uid) {}
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700414
Tom Cherry9787f9a2020-05-19 19:01:16 -0700415 pid_t tid() const { return tid_; }
416 pid_t pid() const { return pid_; }
417 uid_t uid() const { return uid_; }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700418
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700419 void Add(const LogStatisticsElement& element) {
420 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700421 uid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700422 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700423 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700424 pid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700425 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700426 if (tid_ != element.tid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700427 tid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700428 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700429 EntryBase::Add(element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700430 }
431
432 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherryb0263af2020-06-03 15:38:32 -0700433 std::string format(const LogStatistics& stat, log_id_t id, const std::string& key_name) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700434
435 private:
436 pid_t tid_;
437 pid_t pid_;
438 uid_t uid_;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700439};
440
Mark Salyzyn34facab2014-02-06 14:48:50 -0800441class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700442 friend UidEntry;
Tom Cherry64e90162020-05-07 14:44:43 -0700443 friend PidEntry;
444 friend TidEntry;
Mark Salyzync723df82015-08-24 11:08:00 -0700445
Tom Cherry64e90162020-05-07 14:44:43 -0700446 size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
447 size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
448 size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
449 size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
450 size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
451 log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
452 log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
453 log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
454 static std::atomic<size_t> SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700455 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800456
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700457 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700458 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700459 uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzyne457b742014-02-19 17:18:31 -0800460
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700461 // pid of system to size list
462 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700463 pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700464
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700465 // pid to uid list
466 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700467 pidTable_t pidTable GUARDED_BY(lock_);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700468
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700469 // tid to uid list
470 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700471 tidTable_t tidTable GUARDED_BY(lock_);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700472
Mark Salyzyn344bff42015-04-13 14:24:45 -0700473 // tag list
474 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700475 tagTable_t tagTable GUARDED_BY(lock_);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700476
Mark Salyzyn083b0372015-12-04 10:59:45 -0800477 // security tag list
Tom Cherry64e90162020-05-07 14:44:43 -0700478 tagTable_t securityTagTable GUARDED_BY(lock_);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800479
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700480 // global tag list
Tom Cherryb0263af2020-06-03 15:38:32 -0700481 typedef LogHashtable<std::string, TagNameEntry> tagNameTable_t;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700482 tagNameTable_t tagNameTable;
483
Tom Cherry64e90162020-05-07 14:44:43 -0700484 size_t sizeOf() const REQUIRES(lock_) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700485 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700486 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700487 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700488 (pidTable.size() * sizeof(pidTable_t::iterator)) +
489 (tagTable.size() * sizeof(tagTable_t::iterator));
Tom Cherry9b4246d2020-06-17 11:40:55 -0700490 for (const auto& it : pidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700491 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700492 if (name) size += strlen(name) + 1;
493 }
Tom Cherry9b4246d2020-06-17 11:40:55 -0700494 for (const auto& it : tidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700495 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700496 if (name) size += strlen(name) + 1;
497 }
Tom Cherry9b4246d2020-06-17 11:40:55 -0700498 for (const auto& it : tagNameTable) {
Tom Cherryb0263af2020-06-03 15:38:32 -0700499 size += sizeof(std::string);
500 size_t len = it.first.size();
501 // Account for short string optimization: if the string's length is <= 22 bytes for 64
502 // bit or <= 10 bytes for 32 bit, then there is no additional allocation.
503 if ((sizeof(std::string) == 24 && len > 22) ||
504 (sizeof(std::string) != 24 && len > 10)) {
505 size += len;
506 }
507 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700508 log_id_for_each(id) {
509 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700510 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700511 size += pidSystemTable[id].sizeOf();
Tom Cherryb0263af2020-06-03 15:38:32 -0700512 size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700513 }
514 return size;
515 }
516
Tom Cherry64e90162020-05-07 14:44:43 -0700517 public:
Tom Cherryec39a3f2020-07-09 09:51:16 -0700518 LogStatistics(bool enable_statistics, bool track_total_size,
519 std::optional<log_time> start_time = {});
Mark Salyzyn34facab2014-02-06 14:48:50 -0800520
Tom Cherrya26f7df2020-05-19 17:48:42 -0700521 void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
Tom Cherryf74503d2020-06-19 12:21:21 -0700522
523 // Add is for adding an element to the log buffer. It may be a chatty element in the case of
524 // log deduplication. Add the total size of the element to statistics.
525 void Add(LogStatisticsElement entry) EXCLUDES(lock_);
526 // Subtract is for removing an element from the log buffer. It may be a chatty element.
527 // Subtract the total size of the element from statistics.
528 void Subtract(LogStatisticsElement entry) EXCLUDES(lock_);
529 // Drop is for converting a normal element into a chatty element. entry->setDropped(1) must
530 // follow this call. Subtract only msg_len from statistics, since a chatty element will remain.
531 void Drop(LogStatisticsElement entry) EXCLUDES(lock_);
532 // Erase is for coalescing two chatty elements into one. Erase() is called on the element that
533 // is removed from the log buffer. Subtract the total size of the element, which is by
534 // definition only the size of the LogBufferElement + list overhead for chatty elements.
535 void Erase(LogStatisticsElement element) EXCLUDES(lock_);
Mark Salyzyne457b742014-02-19 17:18:31 -0800536
Tom Cherryb6b78e92020-05-07 09:13:12 -0700537 void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700538 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700539 void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700540 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700541 void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700542 size_t* second_worst_sizes) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800543
Tom Cherry64e90162020-05-07 14:44:43 -0700544 bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
545 EXCLUDES(lock_);
546
547 // Snapshot of the sizes for a given log buffer.
548 size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
549 auto lock = std::lock_guard{lock_};
Tom Cherryf74503d2020-06-19 12:21:21 -0700550 if (overhead_[id]) {
551 return *overhead_[id];
552 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800553 return mSizes[id];
554 }
Tom Cherry64e90162020-05-07 14:44:43 -0700555 // TODO: Get rid of this entirely.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800556 static size_t sizesTotal() {
557 return SizesTotal;
558 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800559
Tom Cherryec39a3f2020-07-09 09:51:16 -0700560 std::string ReportInteresting() const EXCLUDES(lock_);
Tom Cherry64e90162020-05-07 14:44:43 -0700561 std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
Mark Salyzyn9a038632014-04-07 07:05:40 -0700562
Tom Cherry64e90162020-05-07 14:44:43 -0700563 const char* PidToName(pid_t pid) const EXCLUDES(lock_);
564 uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
565 const char* UidToName(uid_t uid) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800566
Tom Cherryf74503d2020-06-19 12:21:21 -0700567 void set_overhead(log_id_t id, size_t size) {
568 auto lock = std::lock_guard{lock_};
569 overhead_[id] = size;
570 }
571
Tom Cherryb6b78e92020-05-07 09:13:12 -0700572 private:
573 template <typename TKey, typename TEntry>
574 void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
Tom Cherry64e90162020-05-07 14:44:43 -0700575 int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
576 template <typename TKey, typename TEntry>
577 std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
578 const std::string& name = std::string(""),
579 log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
580 void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
581 size_t nameLen) const REQUIRES(lock_);
582 const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
583
584 mutable std::mutex lock_;
Tom Cherryf74503d2020-06-19 12:21:21 -0700585 bool track_total_size_;
586
587 std::optional<size_t> overhead_[LOG_ID_MAX] GUARDED_BY(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700588};