blob: 6a46adbd96fbd1126088510a7aa977effba7e721 [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
41#include "LogBufferElement.h"
Mark Salyzyn5ac5c6b2015-08-28 08:02:59 -070042#include "LogUtils.h"
Mark Salyzyn34facab2014-02-06 14:48:50 -080043
44#define log_id_for_each(i) \
Mark Salyzyn501c3732017-03-10 14:31:54 -080045 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 -080046
Mark Salyzyn758058f2015-08-21 16:44:30 -070047class LogStatistics;
48
Mark Salyzyn720f6d12015-03-16 08:26:05 -070049template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070050class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070051 std::unordered_map<TKey, TEntry> map;
52
Mark Salyzyn6d981af2016-10-06 09:55:21 -070053 size_t bucket_size() const {
54 size_t count = 0;
55 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
56 size_t bucket_size = map.bucket_size(idx);
57 if (bucket_size == 0) bucket_size = 1;
58 count += bucket_size;
59 }
60 float load_factor = map.max_load_factor();
61 if (load_factor < 1.0) return count;
62 return count * load_factor;
63 }
64
65 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
66 static const size_t unordered_map_bucket_overhead = sizeof(void*);
67
Tom Cherry9787f9a2020-05-19 19:01:16 -070068 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -080069 size_t size() const {
70 return map.size();
71 }
Mark Salyzynb0672292016-10-06 10:09:24 -070072
Mark Salyzyn6d981af2016-10-06 09:55:21 -070073 // Estimate unordered_map memory usage.
74 size_t sizeOf() const {
75 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070076 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070077 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
78 }
79
Mark Salyzyn511338d2015-05-19 09:12:30 -070080 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080081 typedef
82 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070083
Tom Cherryb6b78e92020-05-07 09:13:12 -070084 // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
85 // entries are found, their positions are set to nullptr.
86 template <size_t len>
87 void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
88 auto& retval = *out;
89 retval.fill(nullptr);
Mark Salyzyn501c3732017-03-10 14:31:54 -080090 for (const_iterator it = map.begin(); it != map.end(); ++it) {
91 const TEntry& entry = it->second;
Mark Salyzynee3b8382015-12-17 09:58:43 -080092
Tom Cherry9787f9a2020-05-19 19:01:16 -070093 if (uid != AID_ROOT && uid != entry.uid()) {
Mark Salyzynee3b8382015-12-17 09:58:43 -080094 continue;
95 }
Tom Cherry9787f9a2020-05-19 19:01:16 -070096 if (pid && entry.pid() && pid != entry.pid()) {
Mark Salyzynee3b8382015-12-17 09:58:43 -080097 continue;
98 }
99
Mark Salyzyn758058f2015-08-21 16:44:30 -0700100 size_t sizes = entry.getSizes();
101 ssize_t index = len - 1;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800102 while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
103 (--index >= 0))
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700104 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700105 if (++index < (ssize_t)len) {
106 size_t num = len - index - 1;
107 if (num) {
108 memmove(&retval[index + 1], &retval[index],
109 num * sizeof(retval[0]));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700110 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700111 retval[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700112 }
113 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700114 }
115
Tom Cherry9787f9a2020-05-19 19:01:16 -0700116 iterator Add(const TKey& key, const LogBufferElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700117 iterator it = map.find(key);
118 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700119 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700120 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700121 it->second.Add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700122 }
123 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700124 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700125
Tom Cherry9787f9a2020-05-19 19:01:16 -0700126 iterator Add(const TKey& key) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700127 iterator it = map.find(key);
128 if (it == map.end()) {
129 it = map.insert(std::make_pair(key, TEntry(key))).first;
130 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700131 it->second.Add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700132 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700133 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700134 }
135
Tom Cherry9787f9a2020-05-19 19:01:16 -0700136 void Subtract(const TKey& key, const LogBufferElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700137 iterator it = map.find(key);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700138 if (it != map.end() && it->second.Subtract(element)) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700139 map.erase(it);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700140 }
141 }
142
Tom Cherry9787f9a2020-05-19 19:01:16 -0700143 void Drop(const TKey& key, const LogBufferElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700144 iterator it = map.find(key);
145 if (it != map.end()) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700146 it->second.Drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700147 }
148 }
149
Tom Cherry9787f9a2020-05-19 19:01:16 -0700150 iterator begin() { return map.begin(); }
151 const_iterator begin() const { return map.begin(); }
152 iterator end() { return map.end(); }
153 const_iterator end() const { return map.end(); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700154};
155
Tom Cherry9787f9a2020-05-19 19:01:16 -0700156class EntryBase {
157 public:
158 EntryBase() : size_(0) {}
159 explicit EntryBase(const LogBufferElement& element) : size_(element.msg_len()) {}
Mark Salyzyn758058f2015-08-21 16:44:30 -0700160
Tom Cherry9787f9a2020-05-19 19:01:16 -0700161 size_t getSizes() const { return size_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700162
Tom Cherry9787f9a2020-05-19 19:01:16 -0700163 void Add(const LogBufferElement& element) { size_ += element.msg_len(); }
164 bool Subtract(const LogBufferElement& element) {
165 size_ -= element.msg_len();
166 return !size_;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800167 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700168
Tom Cherry9787f9a2020-05-19 19:01:16 -0700169 static constexpr size_t PRUNED_LEN = 14;
170 static constexpr size_t TOTAL_LEN = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700171
Mark Salyzyn501c3732017-03-10 14:31:54 -0800172 static std::string formatLine(const std::string& name,
173 const std::string& size,
174 const std::string& pruned) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700175 ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
176 ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700177
Mark Salyzyn501c3732017-03-10 14:31:54 -0800178 std::string ret = android::base::StringPrintf(
179 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
180 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800181 // remove any trailing spaces
182 size_t pos = ret.size();
183 size_t len = 0;
184 while (pos && isspace(ret[--pos])) ++len;
185 if (len) ret.erase(pos + 1, len);
186 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700187 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700188
189 private:
190 size_t size_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700191};
192
Tom Cherry9787f9a2020-05-19 19:01:16 -0700193class EntryBaseDropped : public EntryBase {
194 public:
195 EntryBaseDropped() : dropped_(0) {}
196 explicit EntryBaseDropped(const LogBufferElement& element)
197 : EntryBase(element), dropped_(element.dropped_count()) {}
Mark Salyzyn34facab2014-02-06 14:48:50 -0800198
Tom Cherry9787f9a2020-05-19 19:01:16 -0700199 size_t dropped_count() const { return dropped_; }
200
201 void Add(const LogBufferElement& element) {
202 dropped_ += element.dropped_count();
203 EntryBase::Add(element);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800204 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700205 bool Subtract(const LogBufferElement& element) {
206 dropped_ -= element.dropped_count();
207 return EntryBase::Subtract(element) && !dropped_;
208 }
209 void Drop(const LogBufferElement& element) {
210 dropped_ += 1;
211 EntryBase::Subtract(element);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700212 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800213
Tom Cherry9787f9a2020-05-19 19:01:16 -0700214 private:
215 size_t dropped_;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800216};
217
Tom Cherry9787f9a2020-05-19 19:01:16 -0700218class UidEntry : public EntryBaseDropped {
219 public:
220 explicit UidEntry(const LogBufferElement& element)
221 : EntryBaseDropped(element), uid_(element.uid()), pid_(element.pid()) {}
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700222
Tom Cherry9787f9a2020-05-19 19:01:16 -0700223 uid_t key() const { return uid_; }
224 uid_t uid() const { return key(); }
225 pid_t pid() const { return pid_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700226
Tom Cherry9787f9a2020-05-19 19:01:16 -0700227 void Add(const LogBufferElement& element) {
228 if (pid_ != element.pid()) {
229 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800230 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700231 EntryBaseDropped::Add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800232 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700233
Mark Salyzyn501c3732017-03-10 14:31:54 -0800234 std::string formatHeader(const std::string& name, log_id_t id) const;
235 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700236
237 private:
238 const uid_t uid_;
239 pid_t pid_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700240};
241
Tom Cherry40da03b2019-06-28 13:21:27 -0700242namespace android {
243uid_t pidToUid(pid_t pid);
244}
245
Tom Cherry9787f9a2020-05-19 19:01:16 -0700246class PidEntry : public EntryBaseDropped {
247 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800248 explicit PidEntry(pid_t pid)
249 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700250 pid_(pid),
251 uid_(android::pidToUid(pid)),
252 name_(android::pidToName(pid)) {}
253 explicit PidEntry(const LogBufferElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800254 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700255 pid_(element.pid()),
256 uid_(element.uid()),
257 name_(android::pidToName(pid_)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800258 PidEntry(const PidEntry& element)
259 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700260 pid_(element.pid_),
261 uid_(element.uid_),
262 name_(element.name_ ? strdup(element.name_) : nullptr) {}
263 ~PidEntry() { free(name_); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700264
Tom Cherry9787f9a2020-05-19 19:01:16 -0700265 pid_t key() const { return pid_; }
266 pid_t pid() const { return key(); }
267 uid_t uid() const { return uid_; }
268 const char* name() const { return name_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700269
Tom Cherry9787f9a2020-05-19 19:01:16 -0700270 void Add(pid_t new_pid) {
271 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
272 free(name_);
273 name_ = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700274 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700275 if (!name_) {
276 name_ = android::pidToName(new_pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700277 }
278 }
279
Tom Cherry9787f9a2020-05-19 19:01:16 -0700280 void Add(const LogBufferElement& element) {
281 uid_t incoming_uid = element.uid();
282 if (uid() != incoming_uid) {
283 uid_ = incoming_uid;
284 free(name_);
285 name_ = android::pidToName(element.pid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700286 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700287 Add(element.pid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700288 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700289 EntryBaseDropped::Add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700290 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700291
Mark Salyzyn501c3732017-03-10 14:31:54 -0800292 std::string formatHeader(const std::string& name, log_id_t id) const;
293 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700294
295 private:
296 const pid_t pid_;
297 uid_t uid_;
298 char* name_;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700299};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700300
Tom Cherry9787f9a2020-05-19 19:01:16 -0700301class TidEntry : public EntryBaseDropped {
302 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800303 TidEntry(pid_t tid, pid_t pid)
304 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700305 tid_(tid),
306 pid_(pid),
307 uid_(android::pidToUid(tid)),
308 name_(android::tidToName(tid)) {}
309 explicit TidEntry(const LogBufferElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800310 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700311 tid_(element.tid()),
312 pid_(element.pid()),
313 uid_(element.uid()),
314 name_(android::tidToName(tid_)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800315 TidEntry(const TidEntry& element)
316 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700317 tid_(element.tid_),
318 pid_(element.pid_),
319 uid_(element.uid_),
320 name_(element.name_ ? strdup(element.name_) : nullptr) {}
321 ~TidEntry() { free(name_); }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700322
Tom Cherry9787f9a2020-05-19 19:01:16 -0700323 pid_t key() const { return tid_; }
324 pid_t tid() const { return key(); }
325 pid_t pid() const { return pid_; }
326 uid_t uid() const { return uid_; }
327 const char* name() const { return name_; }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700328
Tom Cherry9787f9a2020-05-19 19:01:16 -0700329 void Add(pid_t incomingTid) {
330 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
331 free(name_);
332 name_ = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700333 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700334 if (!name_) {
335 name_ = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700336 }
337 }
338
Tom Cherry9787f9a2020-05-19 19:01:16 -0700339 void Add(const LogBufferElement& element) {
340 uid_t incoming_uid = element.uid();
341 pid_t incoming_pid = element.pid();
342 if (uid() != incoming_uid || pid() != incoming_pid) {
343 uid_ = incoming_uid;
344 pid_ = incoming_pid;
345 free(name_);
346 name_ = android::tidToName(element.tid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700347 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700348 Add(element.tid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700349 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700350 EntryBaseDropped::Add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700351 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700352
Mark Salyzyn501c3732017-03-10 14:31:54 -0800353 std::string formatHeader(const std::string& name, log_id_t id) const;
354 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700355
356 private:
357 const pid_t tid_;
358 pid_t pid_;
359 uid_t uid_;
360 char* name_;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700361};
362
Tom Cherry9787f9a2020-05-19 19:01:16 -0700363class TagEntry : public EntryBaseDropped {
364 public:
365 explicit TagEntry(const LogBufferElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800366 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700367 tag_(element.GetTag()),
368 pid_(element.pid()),
369 uid_(element.uid()) {}
Mark Salyzyn344bff42015-04-13 14:24:45 -0700370
Tom Cherry9787f9a2020-05-19 19:01:16 -0700371 uint32_t key() const { return tag_; }
372 pid_t pid() const { return pid_; }
373 uid_t uid() const { return uid_; }
374 const char* name() const { return android::tagToName(tag_); }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700375
Tom Cherry9787f9a2020-05-19 19:01:16 -0700376 void Add(const LogBufferElement& element) {
377 if (uid_ != element.uid()) {
378 uid_ = -1;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700379 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700380 if (pid_ != element.pid()) {
381 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800382 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700383 EntryBaseDropped::Add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700384 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700385
Mark Salyzyn501c3732017-03-10 14:31:54 -0800386 std::string formatHeader(const std::string& name, log_id_t id) const;
387 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700388
389 private:
390 const uint32_t tag_;
391 pid_t pid_;
392 uid_t uid_;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700393};
394
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700395struct TagNameKey {
396 std::string* alloc;
Elliott Hughese8058832017-11-30 16:31:35 -0800397 std::string_view name; // Saves space if const char*
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700398
Tom Cherry9787f9a2020-05-19 19:01:16 -0700399 explicit TagNameKey(const LogBufferElement& element) : alloc(nullptr), name("", strlen("")) {
400 if (element.IsBinary()) {
401 uint32_t tag = element.GetTag();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700402 if (tag) {
403 const char* cp = android::tagToName(tag);
404 if (cp) {
Elliott Hughese8058832017-11-30 16:31:35 -0800405 name = std::string_view(cp, strlen(cp));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700406 return;
407 }
408 }
409 alloc = new std::string(
410 android::base::StringPrintf("[%" PRIu32 "]", tag));
411 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800412 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700413 return;
414 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700415 const char* msg = element.msg();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700416 if (!msg) {
Elliott Hughese8058832017-11-30 16:31:35 -0800417 name = std::string_view("chatty", strlen("chatty"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700418 return;
419 }
420 ++msg;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700421 uint16_t len = element.msg_len();
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700422 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
423 if (!len) {
Elliott Hughese8058832017-11-30 16:31:35 -0800424 name = std::string_view("<NULL>", strlen("<NULL>"));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700425 return;
426 }
427 alloc = new std::string(msg, len);
428 if (!alloc) return;
Elliott Hughese8058832017-11-30 16:31:35 -0800429 name = std::string_view(alloc->c_str(), alloc->size());
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700430 }
431
Chih-Hung Hsieh747eb142018-09-25 11:16:22 -0700432 explicit TagNameKey(TagNameKey&& rval) noexcept
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700433 : alloc(rval.alloc), name(rval.name.data(), rval.name.length()) {
434 rval.alloc = nullptr;
435 }
436
437 explicit TagNameKey(const TagNameKey& rval)
438 : alloc(rval.alloc ? new std::string(*rval.alloc) : nullptr),
439 name(alloc ? alloc->data() : rval.name.data(), rval.name.length()) {
440 }
441
442 ~TagNameKey() {
443 if (alloc) delete alloc;
444 }
445
Elliott Hughese8058832017-11-30 16:31:35 -0800446 operator const std::string_view() const {
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700447 return name;
448 }
449
450 const char* data() const {
451 return name.data();
452 }
453 size_t length() const {
454 return name.length();
455 }
456
457 bool operator==(const TagNameKey& rval) const {
458 if (length() != rval.length()) return false;
459 if (length() == 0) return true;
460 return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
461 }
462 bool operator!=(const TagNameKey& rval) const {
463 return !(*this == rval);
464 }
465
466 size_t getAllocLength() const {
467 return alloc ? alloc->length() + 1 + sizeof(std::string) : 0;
468 }
469};
470
471// Hash for TagNameKey
472template <>
473struct std::hash<TagNameKey>
474 : public std::unary_function<const TagNameKey&, size_t> {
475 size_t operator()(const TagNameKey& __t) const noexcept {
476 if (!__t.length()) return 0;
Elliott Hughese8058832017-11-30 16:31:35 -0800477 return std::hash<std::string_view>()(std::string_view(__t));
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700478 }
479};
480
Tom Cherry9787f9a2020-05-19 19:01:16 -0700481class TagNameEntry : public EntryBase {
482 public:
483 explicit TagNameEntry(const LogBufferElement& element)
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700484 : EntryBase(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700485 tid_(element.tid()),
486 pid_(element.pid()),
487 uid_(element.uid()),
488 name_(element) {}
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700489
Tom Cherry9787f9a2020-05-19 19:01:16 -0700490 const TagNameKey& key() const { return name_; }
491 pid_t tid() const { return tid_; }
492 pid_t pid() const { return pid_; }
493 uid_t uid() const { return uid_; }
494 const char* name() const { return name_.data(); }
495 size_t getNameAllocLength() const { return name_.getAllocLength(); }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700496
Tom Cherry9787f9a2020-05-19 19:01:16 -0700497 void Add(const LogBufferElement& element) {
498 if (uid_ != element.uid()) {
499 uid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700500 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700501 if (pid_ != element.pid()) {
502 pid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700503 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700504 if (tid_ != element.tid()) {
505 tid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700506 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700507 EntryBase::Add(element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700508 }
509
510 std::string formatHeader(const std::string& name, log_id_t id) const;
511 std::string format(const LogStatistics& stat, log_id_t id) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700512
513 private:
514 pid_t tid_;
515 pid_t pid_;
516 uid_t uid_;
517 TagNameKey name_;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700518};
519
Mark Salyzyn34facab2014-02-06 14:48:50 -0800520// Log Statistics
521class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700522 friend UidEntry;
Tom Cherry64e90162020-05-07 14:44:43 -0700523 friend PidEntry;
524 friend TidEntry;
Mark Salyzync723df82015-08-24 11:08:00 -0700525
Tom Cherry64e90162020-05-07 14:44:43 -0700526 size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
527 size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
528 size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
529 size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
530 size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
531 log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
532 log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
533 log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
534 static std::atomic<size_t> SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700535 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800536
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700537 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700538 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700539 uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzyne457b742014-02-19 17:18:31 -0800540
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700541 // pid of system to size list
542 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700543 pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700544
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700545 // pid to uid list
546 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700547 pidTable_t pidTable GUARDED_BY(lock_);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700548
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700549 // tid to uid list
550 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700551 tidTable_t tidTable GUARDED_BY(lock_);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700552
Mark Salyzyn344bff42015-04-13 14:24:45 -0700553 // tag list
554 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700555 tagTable_t tagTable GUARDED_BY(lock_);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700556
Mark Salyzyn083b0372015-12-04 10:59:45 -0800557 // security tag list
Tom Cherry64e90162020-05-07 14:44:43 -0700558 tagTable_t securityTagTable GUARDED_BY(lock_);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800559
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700560 // global tag list
561 typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
562 tagNameTable_t tagNameTable;
563
Tom Cherry64e90162020-05-07 14:44:43 -0700564 size_t sizeOf() const REQUIRES(lock_) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700565 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700566 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700567 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700568 (pidTable.size() * sizeof(pidTable_t::iterator)) +
569 (tagTable.size() * sizeof(tagTable_t::iterator));
Mark Salyzyn501c3732017-03-10 14:31:54 -0800570 for (auto it : pidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700571 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700572 if (name) size += strlen(name) + 1;
573 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800574 for (auto it : tidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700575 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700576 if (name) size += strlen(name) + 1;
577 }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700578 for (auto it : tagNameTable) size += it.second.getNameAllocLength();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700579 log_id_for_each(id) {
580 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700581 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700582 size += pidSystemTable[id].sizeOf();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800583 size +=
584 pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700585 }
586 return size;
587 }
588
Tom Cherry64e90162020-05-07 14:44:43 -0700589 public:
590 LogStatistics(bool enable_statistics);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800591
Tom Cherrya26f7df2020-05-19 17:48:42 -0700592 void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700593 void Add(const LogBufferElement& entry) EXCLUDES(lock_);
594 void Subtract(const LogBufferElement& entry) EXCLUDES(lock_);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700595 // entry->setDropped(1) must follow this call
Tom Cherry9787f9a2020-05-19 19:01:16 -0700596 void Drop(const LogBufferElement& entry) EXCLUDES(lock_);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700597 // Correct for coalescing two entries referencing dropped content
Tom Cherry9787f9a2020-05-19 19:01:16 -0700598 void Erase(const LogBufferElement& element) EXCLUDES(lock_) {
Tom Cherry64e90162020-05-07 14:44:43 -0700599 auto lock = std::lock_guard{lock_};
Tom Cherry9787f9a2020-05-19 19:01:16 -0700600 log_id_t log_id = element.log_id();
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700601 --mElements[log_id];
602 --mDroppedElements[log_id];
603 }
Mark Salyzyne457b742014-02-19 17:18:31 -0800604
Tom Cherryb6b78e92020-05-07 09:13:12 -0700605 void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700606 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700607 void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700608 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700609 void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700610 size_t* second_worst_sizes) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800611
Tom Cherry64e90162020-05-07 14:44:43 -0700612 bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
613 EXCLUDES(lock_);
614
615 // Snapshot of the sizes for a given log buffer.
616 size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
617 auto lock = std::lock_guard{lock_};
Mark Salyzyn501c3732017-03-10 14:31:54 -0800618 return mSizes[id];
619 }
Tom Cherry64e90162020-05-07 14:44:43 -0700620 // TODO: Get rid of this entirely.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800621 static size_t sizesTotal() {
622 return SizesTotal;
623 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800624
Tom Cherry64e90162020-05-07 14:44:43 -0700625 std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
Mark Salyzyn9a038632014-04-07 07:05:40 -0700626
Tom Cherry64e90162020-05-07 14:44:43 -0700627 const char* PidToName(pid_t pid) const EXCLUDES(lock_);
628 uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
629 const char* UidToName(uid_t uid) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800630
Tom Cherryb6b78e92020-05-07 09:13:12 -0700631 private:
632 template <typename TKey, typename TEntry>
633 void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
Tom Cherry64e90162020-05-07 14:44:43 -0700634 int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
635 template <typename TKey, typename TEntry>
636 std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
637 const std::string& name = std::string(""),
638 log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
639 void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
640 size_t nameLen) const REQUIRES(lock_);
641 const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
642
643 mutable std::mutex lock_;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700644};