blob: 33a4d63f76c03302fe263c02bff43dfec28b3e1d [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;
47
Tom Cherry3dd3ec32020-06-02 15:39:21 -070048struct LogStatisticsElement {
49 uid_t uid;
50 pid_t pid;
51 pid_t tid;
52 uint32_t tag;
53 log_time realtime;
54 const char* msg;
55 uint16_t msg_len;
56 uint16_t dropped_count;
57 log_id_t log_id;
58};
59
Mark Salyzyn720f6d12015-03-16 08:26:05 -070060template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070061class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070062 std::unordered_map<TKey, TEntry> map;
63
Mark Salyzyn6d981af2016-10-06 09:55:21 -070064 size_t bucket_size() const {
65 size_t count = 0;
66 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
67 size_t bucket_size = map.bucket_size(idx);
68 if (bucket_size == 0) bucket_size = 1;
69 count += bucket_size;
70 }
71 float load_factor = map.max_load_factor();
72 if (load_factor < 1.0) return count;
73 return count * load_factor;
74 }
75
76 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
77 static const size_t unordered_map_bucket_overhead = sizeof(void*);
78
Tom Cherry9787f9a2020-05-19 19:01:16 -070079 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -080080 size_t size() const {
81 return map.size();
82 }
Mark Salyzynb0672292016-10-06 10:09:24 -070083
Mark Salyzyn6d981af2016-10-06 09:55:21 -070084 // Estimate unordered_map memory usage.
85 size_t sizeOf() const {
86 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070087 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070088 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
89 }
90
Mark Salyzyn511338d2015-05-19 09:12:30 -070091 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080092 typedef
93 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070094
Tom Cherryb6b78e92020-05-07 09:13:12 -070095 // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
96 // entries are found, their positions are set to nullptr.
97 template <size_t len>
98 void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
99 auto& retval = *out;
100 retval.fill(nullptr);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800101 for (const_iterator it = map.begin(); it != map.end(); ++it) {
102 const TEntry& entry = it->second;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800103
Tom Cherry9787f9a2020-05-19 19:01:16 -0700104 if (uid != AID_ROOT && uid != entry.uid()) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800105 continue;
106 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700107 if (pid && entry.pid() && pid != entry.pid()) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800108 continue;
109 }
110
Mark Salyzyn758058f2015-08-21 16:44:30 -0700111 size_t sizes = entry.getSizes();
112 ssize_t index = len - 1;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800113 while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
114 (--index >= 0))
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700115 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700116 if (++index < (ssize_t)len) {
117 size_t num = len - index - 1;
118 if (num) {
119 memmove(&retval[index + 1], &retval[index],
120 num * sizeof(retval[0]));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700121 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700122 retval[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700123 }
124 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700125 }
126
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700127 iterator Add(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700128 iterator it = map.find(key);
129 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700130 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700131 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700132 it->second.Add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700133 }
134 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700135 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700136
Tom Cherry9787f9a2020-05-19 19:01:16 -0700137 iterator Add(const TKey& key) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700138 iterator it = map.find(key);
139 if (it == map.end()) {
140 it = map.insert(std::make_pair(key, TEntry(key))).first;
141 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700142 it->second.Add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700143 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700144 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700145 }
146
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700147 void Subtract(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700148 iterator it = map.find(key);
Tom Cherry9787f9a2020-05-19 19:01:16 -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
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700154 void Drop(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700155 iterator it = map.find(key);
156 if (it != map.end()) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700157 it->second.Drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700158 }
159 }
160
Tom Cherry9787f9a2020-05-19 19:01:16 -0700161 iterator begin() { return map.begin(); }
162 const_iterator begin() const { return map.begin(); }
163 iterator end() { return map.end(); }
164 const_iterator end() const { return map.end(); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700165};
166
Tom Cherry9787f9a2020-05-19 19:01:16 -0700167class EntryBase {
168 public:
169 EntryBase() : size_(0) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700170 explicit EntryBase(const LogStatisticsElement& element) : size_(element.msg_len) {}
Mark Salyzyn758058f2015-08-21 16:44:30 -0700171
Tom Cherry9787f9a2020-05-19 19:01:16 -0700172 size_t getSizes() const { return size_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700173
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700174 void Add(const LogStatisticsElement& element) { size_ += element.msg_len; }
175 bool Subtract(const LogStatisticsElement& element) {
176 size_ -= element.msg_len;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700177 return !size_;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800178 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700179
Tom Cherry9787f9a2020-05-19 19:01:16 -0700180 static constexpr size_t PRUNED_LEN = 14;
181 static constexpr size_t TOTAL_LEN = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700182
Mark Salyzyn501c3732017-03-10 14:31:54 -0800183 static std::string formatLine(const std::string& name,
184 const std::string& size,
185 const std::string& pruned) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700186 ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
187 ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700188
Mark Salyzyn501c3732017-03-10 14:31:54 -0800189 std::string ret = android::base::StringPrintf(
190 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
191 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800192 // remove any trailing spaces
193 size_t pos = ret.size();
194 size_t len = 0;
195 while (pos && isspace(ret[--pos])) ++len;
196 if (len) ret.erase(pos + 1, len);
197 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700198 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700199
200 private:
201 size_t size_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700202};
203
Tom Cherry9787f9a2020-05-19 19:01:16 -0700204class EntryBaseDropped : public EntryBase {
205 public:
206 EntryBaseDropped() : dropped_(0) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700207 explicit EntryBaseDropped(const LogStatisticsElement& element)
208 : EntryBase(element), dropped_(element.dropped_count) {}
Mark Salyzyn34facab2014-02-06 14:48:50 -0800209
Tom Cherry9787f9a2020-05-19 19:01:16 -0700210 size_t dropped_count() const { return dropped_; }
211
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700212 void Add(const LogStatisticsElement& element) {
213 dropped_ += element.dropped_count;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700214 EntryBase::Add(element);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800215 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700216 bool Subtract(const LogStatisticsElement& element) {
217 dropped_ -= element.dropped_count;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700218 return EntryBase::Subtract(element) && !dropped_;
219 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700220 void Drop(const LogStatisticsElement& element) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700221 dropped_ += 1;
222 EntryBase::Subtract(element);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700223 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800224
Tom Cherry9787f9a2020-05-19 19:01:16 -0700225 private:
226 size_t dropped_;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800227};
228
Tom Cherry9787f9a2020-05-19 19:01:16 -0700229class UidEntry : public EntryBaseDropped {
230 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700231 explicit UidEntry(const LogStatisticsElement& element)
232 : EntryBaseDropped(element), uid_(element.uid), pid_(element.pid) {}
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700233
Tom Cherry9787f9a2020-05-19 19:01:16 -0700234 uid_t key() const { return uid_; }
235 uid_t uid() const { return key(); }
236 pid_t pid() const { return pid_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700237
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700238 void Add(const LogStatisticsElement& element) {
239 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700240 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800241 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700242 EntryBaseDropped::Add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800243 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700244
Mark Salyzyn501c3732017-03-10 14:31:54 -0800245 std::string formatHeader(const std::string& name, log_id_t id) const;
246 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700247
248 private:
249 const uid_t uid_;
250 pid_t pid_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700251};
252
Tom Cherry40da03b2019-06-28 13:21:27 -0700253namespace android {
254uid_t pidToUid(pid_t pid);
255}
256
Tom Cherry9787f9a2020-05-19 19:01:16 -0700257class PidEntry : public EntryBaseDropped {
258 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800259 explicit PidEntry(pid_t pid)
260 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700261 pid_(pid),
262 uid_(android::pidToUid(pid)),
263 name_(android::pidToName(pid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700264 explicit PidEntry(const LogStatisticsElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800265 : EntryBaseDropped(element),
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700266 pid_(element.pid),
267 uid_(element.uid),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700268 name_(android::pidToName(pid_)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800269 PidEntry(const PidEntry& element)
270 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700271 pid_(element.pid_),
272 uid_(element.uid_),
273 name_(element.name_ ? strdup(element.name_) : nullptr) {}
274 ~PidEntry() { free(name_); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700275
Tom Cherry9787f9a2020-05-19 19:01:16 -0700276 pid_t key() const { return pid_; }
277 pid_t pid() const { return key(); }
278 uid_t uid() const { return uid_; }
279 const char* name() const { return name_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700280
Tom Cherry9787f9a2020-05-19 19:01:16 -0700281 void Add(pid_t new_pid) {
282 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
283 free(name_);
284 name_ = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700285 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700286 if (!name_) {
287 name_ = android::pidToName(new_pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700288 }
289 }
290
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700291 void Add(const LogStatisticsElement& element) {
292 uid_t incoming_uid = element.uid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700293 if (uid() != incoming_uid) {
294 uid_ = incoming_uid;
295 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700296 name_ = android::pidToName(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700297 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700298 Add(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700299 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700300 EntryBaseDropped::Add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700301 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700302
Mark Salyzyn501c3732017-03-10 14:31:54 -0800303 std::string formatHeader(const std::string& name, log_id_t id) const;
304 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700305
306 private:
307 const pid_t pid_;
308 uid_t uid_;
309 char* name_;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700310};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700311
Tom Cherry9787f9a2020-05-19 19:01:16 -0700312class TidEntry : public EntryBaseDropped {
313 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800314 TidEntry(pid_t tid, pid_t pid)
315 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700316 tid_(tid),
317 pid_(pid),
318 uid_(android::pidToUid(tid)),
319 name_(android::tidToName(tid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700320 explicit TidEntry(const LogStatisticsElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800321 : EntryBaseDropped(element),
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700322 tid_(element.tid),
323 pid_(element.pid),
324 uid_(element.uid),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700325 name_(android::tidToName(tid_)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800326 TidEntry(const TidEntry& element)
327 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700328 tid_(element.tid_),
329 pid_(element.pid_),
330 uid_(element.uid_),
331 name_(element.name_ ? strdup(element.name_) : nullptr) {}
332 ~TidEntry() { free(name_); }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700333
Tom Cherry9787f9a2020-05-19 19:01:16 -0700334 pid_t key() const { return tid_; }
335 pid_t tid() const { return key(); }
336 pid_t pid() const { return pid_; }
337 uid_t uid() const { return uid_; }
338 const char* name() const { return name_; }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700339
Tom Cherry9787f9a2020-05-19 19:01:16 -0700340 void Add(pid_t incomingTid) {
341 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
342 free(name_);
343 name_ = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700344 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700345 if (!name_) {
346 name_ = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700347 }
348 }
349
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700350 void Add(const LogStatisticsElement& element) {
351 uid_t incoming_uid = element.uid;
352 pid_t incoming_pid = element.pid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700353 if (uid() != incoming_uid || pid() != incoming_pid) {
354 uid_ = incoming_uid;
355 pid_ = incoming_pid;
356 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700357 name_ = android::tidToName(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700358 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700359 Add(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700360 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700361 EntryBaseDropped::Add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700362 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700363
Mark Salyzyn501c3732017-03-10 14:31:54 -0800364 std::string formatHeader(const std::string& name, log_id_t id) const;
365 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700366
367 private:
368 const pid_t tid_;
369 pid_t pid_;
370 uid_t uid_;
371 char* name_;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700372};
373
Tom Cherry9787f9a2020-05-19 19:01:16 -0700374class TagEntry : public EntryBaseDropped {
375 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700376 explicit TagEntry(const LogStatisticsElement& element)
377 : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
Mark Salyzyn344bff42015-04-13 14:24:45 -0700378
Tom Cherry9787f9a2020-05-19 19:01:16 -0700379 uint32_t key() const { return tag_; }
380 pid_t pid() const { return pid_; }
381 uid_t uid() const { return uid_; }
382 const char* name() const { return android::tagToName(tag_); }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700383
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700384 void Add(const LogStatisticsElement& element) {
385 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700386 uid_ = -1;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700387 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700388 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700389 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800390 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700391 EntryBaseDropped::Add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700392 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700393
Mark Salyzyn501c3732017-03-10 14:31:54 -0800394 std::string formatHeader(const std::string& name, log_id_t id) const;
395 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700396
397 private:
398 const uint32_t tag_;
399 pid_t pid_;
400 uid_t uid_;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700401};
402
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700403struct TagNameKey {
404 std::string* alloc;
Elliott Hughese8058832017-11-30 16:31:35 -0800405 std::string_view name; // Saves space if const char*
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700406
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700407 explicit TagNameKey(const LogStatisticsElement& element)
408 : alloc(nullptr), name("", strlen("")) {
409 if (IsBinary(element.log_id)) {
410 uint32_t tag = element.tag;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700411 if (tag) {
412 const char* cp = android::tagToName(tag);
413 if (cp) {
Elliott Hughese8058832017-11-30 16:31:35 -0800414 name = std::string_view(cp, strlen(cp));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700415 return;
416 }
417 }
418 alloc = new std::string(
419 android::base::StringPrintf("[%" PRIu32 "]", tag));
420 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800421 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700422 return;
423 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700424 const char* msg = element.msg;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700425 if (!msg) {
Elliott Hughese8058832017-11-30 16:31:35 -0800426 name = std::string_view("chatty", strlen("chatty"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700427 return;
428 }
429 ++msg;
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700430 uint16_t len = element.msg_len;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700431 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
432 if (!len) {
Elliott Hughese8058832017-11-30 16:31:35 -0800433 name = std::string_view("<NULL>", strlen("<NULL>"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700434 return;
435 }
436 alloc = new std::string(msg, len);
437 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800438 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700439 }
440
Chih-Hung Hsieh747eb142018-09-25 11:16:22 -0700441 explicit TagNameKey(TagNameKey&& rval) noexcept
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700442 : alloc(rval.alloc), name(rval.name.data(), rval.name.length()) {
443 rval.alloc = nullptr;
444 }
445
446 explicit TagNameKey(const TagNameKey& rval)
447 : alloc(rval.alloc ? new std::string(*rval.alloc) : nullptr),
448 name(alloc ? alloc->data() : rval.name.data(), rval.name.length()) {
449 }
450
451 ~TagNameKey() {
452 if (alloc) delete alloc;
453 }
454
Elliott Hughese8058832017-11-30 16:31:35 -0800455 operator const std::string_view() const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700456 return name;
457 }
458
459 const char* data() const {
460 return name.data();
461 }
462 size_t length() const {
463 return name.length();
464 }
465
466 bool operator==(const TagNameKey& rval) const {
467 if (length() != rval.length()) return false;
468 if (length() == 0) return true;
469 return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
470 }
471 bool operator!=(const TagNameKey& rval) const {
472 return !(*this == rval);
473 }
474
475 size_t getAllocLength() const {
476 return alloc ? alloc->length() + 1 + sizeof(std::string) : 0;
477 }
478};
479
480// Hash for TagNameKey
481template <>
482struct std::hash<TagNameKey>
483 : public std::unary_function<const TagNameKey&, size_t> {
484 size_t operator()(const TagNameKey& __t) const noexcept {
485 if (!__t.length()) return 0;
Elliott Hughese8058832017-11-30 16:31:35 -0800486 return std::hash<std::string_view>()(std::string_view(__t));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700487 }
488};
489
Tom Cherry9787f9a2020-05-19 19:01:16 -0700490class TagNameEntry : public EntryBase {
491 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700492 explicit TagNameEntry(const LogStatisticsElement& element)
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700493 : EntryBase(element),
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700494 tid_(element.tid),
495 pid_(element.pid),
496 uid_(element.uid),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700497 name_(element) {}
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700498
Tom Cherry9787f9a2020-05-19 19:01:16 -0700499 const TagNameKey& key() const { return name_; }
500 pid_t tid() const { return tid_; }
501 pid_t pid() const { return pid_; }
502 uid_t uid() const { return uid_; }
503 const char* name() const { return name_.data(); }
504 size_t getNameAllocLength() const { return name_.getAllocLength(); }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700505
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700506 void Add(const LogStatisticsElement& element) {
507 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700508 uid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700509 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700510 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700511 pid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700512 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700513 if (tid_ != element.tid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700514 tid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700515 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700516 EntryBase::Add(element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700517 }
518
519 std::string formatHeader(const std::string& name, log_id_t id) const;
520 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700521
522 private:
523 pid_t tid_;
524 pid_t pid_;
525 uid_t uid_;
526 TagNameKey name_;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700527};
528
Mark Salyzyn34facab2014-02-06 14:48:50 -0800529// Log Statistics
530class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700531 friend UidEntry;
Tom Cherry64e90162020-05-07 14:44:43 -0700532 friend PidEntry;
533 friend TidEntry;
Mark Salyzync723df82015-08-24 11:08:00 -0700534
Tom Cherry64e90162020-05-07 14:44:43 -0700535 size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
536 size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
537 size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
538 size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
539 size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
540 log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
541 log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
542 log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
543 static std::atomic<size_t> SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700544 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800545
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700546 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700547 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700548 uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzyne457b742014-02-19 17:18:31 -0800549
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700550 // pid of system to size list
551 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700552 pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700553
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700554 // pid to uid list
555 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700556 pidTable_t pidTable GUARDED_BY(lock_);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700557
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700558 // tid to uid list
559 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700560 tidTable_t tidTable GUARDED_BY(lock_);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700561
Mark Salyzyn344bff42015-04-13 14:24:45 -0700562 // tag list
563 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700564 tagTable_t tagTable GUARDED_BY(lock_);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700565
Mark Salyzyn083b0372015-12-04 10:59:45 -0800566 // security tag list
Tom Cherry64e90162020-05-07 14:44:43 -0700567 tagTable_t securityTagTable GUARDED_BY(lock_);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800568
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700569 // global tag list
570 typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
571 tagNameTable_t tagNameTable;
572
Tom Cherry64e90162020-05-07 14:44:43 -0700573 size_t sizeOf() const REQUIRES(lock_) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700574 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700575 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700576 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700577 (pidTable.size() * sizeof(pidTable_t::iterator)) +
578 (tagTable.size() * sizeof(tagTable_t::iterator));
Mark Salyzyn501c3732017-03-10 14:31:54 -0800579 for (auto it : pidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700580 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700581 if (name) size += strlen(name) + 1;
582 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800583 for (auto it : tidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700584 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700585 if (name) size += strlen(name) + 1;
586 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700587 for (auto it : tagNameTable) size += it.second.getNameAllocLength();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700588 log_id_for_each(id) {
589 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700590 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700591 size += pidSystemTable[id].sizeOf();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800592 size +=
593 pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700594 }
595 return size;
596 }
597
Tom Cherry64e90162020-05-07 14:44:43 -0700598 public:
599 LogStatistics(bool enable_statistics);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800600
Tom Cherrya26f7df2020-05-19 17:48:42 -0700601 void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700602 void Add(const LogStatisticsElement& entry) EXCLUDES(lock_);
603 void Subtract(const LogStatisticsElement& entry) EXCLUDES(lock_);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700604 // entry->setDropped(1) must follow this call
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700605 void Drop(const LogStatisticsElement& entry) EXCLUDES(lock_);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700606 // Correct for coalescing two entries referencing dropped content
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700607 void Erase(const LogStatisticsElement& element) EXCLUDES(lock_) {
Tom Cherry64e90162020-05-07 14:44:43 -0700608 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700609 log_id_t log_id = element.log_id;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700610 --mElements[log_id];
611 --mDroppedElements[log_id];
612 }
Mark Salyzyne457b742014-02-19 17:18:31 -0800613
Tom Cherryb6b78e92020-05-07 09:13:12 -0700614 void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700615 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700616 void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700617 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700618 void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700619 size_t* second_worst_sizes) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800620
Tom Cherry64e90162020-05-07 14:44:43 -0700621 bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
622 EXCLUDES(lock_);
623
624 // Snapshot of the sizes for a given log buffer.
625 size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
626 auto lock = std::lock_guard{lock_};
Mark Salyzyn501c3732017-03-10 14:31:54 -0800627 return mSizes[id];
628 }
Tom Cherry64e90162020-05-07 14:44:43 -0700629 // TODO: Get rid of this entirely.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800630 static size_t sizesTotal() {
631 return SizesTotal;
632 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800633
Tom Cherry64e90162020-05-07 14:44:43 -0700634 std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
Mark Salyzyn9a038632014-04-07 07:05:40 -0700635
Tom Cherry64e90162020-05-07 14:44:43 -0700636 const char* PidToName(pid_t pid) const EXCLUDES(lock_);
637 uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
638 const char* UidToName(uid_t uid) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800639
Tom Cherryb6b78e92020-05-07 09:13:12 -0700640 private:
641 template <typename TKey, typename TEntry>
642 void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
Tom Cherry64e90162020-05-07 14:44:43 -0700643 int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
644 template <typename TKey, typename TEntry>
645 std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
646 const std::string& name = std::string(""),
647 log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
648 void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
649 size_t nameLen) const REQUIRES(lock_);
650 const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
651
652 mutable std::mutex lock_;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700653};