blob: 5f558026c974a30b8e4ebcddd2f0780c6bd4f497 [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;
60};
61
Mark Salyzyn720f6d12015-03-16 08:26:05 -070062template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070063class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070064 std::unordered_map<TKey, TEntry> map;
65
Mark Salyzyn6d981af2016-10-06 09:55:21 -070066 size_t bucket_size() const {
67 size_t count = 0;
68 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
69 size_t bucket_size = map.bucket_size(idx);
70 if (bucket_size == 0) bucket_size = 1;
71 count += bucket_size;
72 }
73 float load_factor = map.max_load_factor();
74 if (load_factor < 1.0) return count;
75 return count * load_factor;
76 }
77
78 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
79 static const size_t unordered_map_bucket_overhead = sizeof(void*);
80
Tom Cherry9787f9a2020-05-19 19:01:16 -070081 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -080082 size_t size() const {
83 return map.size();
84 }
Mark Salyzynb0672292016-10-06 10:09:24 -070085
Mark Salyzyn6d981af2016-10-06 09:55:21 -070086 // Estimate unordered_map memory usage.
87 size_t sizeOf() const {
88 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070089 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070090 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
91 }
92
Mark Salyzyn511338d2015-05-19 09:12:30 -070093 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080094 typedef
95 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070096
Tom Cherryb6b78e92020-05-07 09:13:12 -070097 // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
98 // entries are found, their positions are set to nullptr.
99 template <size_t len>
Tom Cherry4596b782020-06-03 13:49:24 -0700100 void MaxEntries(uid_t uid, pid_t pid, std::array<const TKey*, len>& out_keys,
101 std::array<const TEntry*, len>& out_entries) const {
102 out_keys.fill(nullptr);
103 out_entries.fill(nullptr);
104 for (const auto& [key, entry] : map) {
105 uid_t entry_uid = 0;
106 if constexpr (std::is_same_v<TEntry, UidEntry>) {
107 entry_uid = key;
108 } else {
109 entry_uid = entry.uid();
110 }
111 if (uid != AID_ROOT && uid != entry_uid) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800112 continue;
113 }
Tom Cherry4596b782020-06-03 13:49:24 -0700114 pid_t entry_pid = 0;
115 if constexpr (std::is_same_v<TEntry, PidEntry>) {
116 entry_pid = key;
117 } else {
118 entry_pid = entry.pid();
119 }
120 if (pid && entry_pid && pid != entry_pid) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800121 continue;
122 }
123
Mark Salyzyn758058f2015-08-21 16:44:30 -0700124 size_t sizes = entry.getSizes();
125 ssize_t index = len - 1;
Tom Cherry4596b782020-06-03 13:49:24 -0700126 while ((!out_entries[index] || sizes > out_entries[index]->getSizes()) && --index >= 0)
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700127 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700128 if (++index < (ssize_t)len) {
129 size_t num = len - index - 1;
130 if (num) {
Tom Cherry9b4246d2020-06-17 11:40:55 -0700131 memmove(&out_keys[index + 1], &out_keys[index], num * sizeof(const TKey*));
Tom Cherry4596b782020-06-03 13:49:24 -0700132 memmove(&out_entries[index + 1], &out_entries[index],
Tom Cherry9b4246d2020-06-17 11:40:55 -0700133 num * sizeof(const TEntry*));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700134 }
Tom Cherry4596b782020-06-03 13:49:24 -0700135 out_keys[index] = &key;
136 out_entries[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700137 }
138 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700139 }
140
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700141 iterator Add(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700142 iterator it = map.find(key);
143 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700144 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700145 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700146 it->second.Add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700147 }
148 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700149 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700150
Tom Cherry9787f9a2020-05-19 19:01:16 -0700151 iterator Add(const TKey& key) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700152 iterator it = map.find(key);
153 if (it == map.end()) {
154 it = map.insert(std::make_pair(key, TEntry(key))).first;
155 } else {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700156 it->second.Add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700157 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700158 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700159 }
160
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700161 void Subtract(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700162 iterator it = map.find(key);
Tom Cherry9787f9a2020-05-19 19:01:16 -0700163 if (it != map.end() && it->second.Subtract(element)) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700164 map.erase(it);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700165 }
166 }
167
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700168 void Drop(const TKey& key, const LogStatisticsElement& element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700169 iterator it = map.find(key);
170 if (it != map.end()) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700171 it->second.Drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700172 }
173 }
174
Tom Cherry9787f9a2020-05-19 19:01:16 -0700175 iterator begin() { return map.begin(); }
176 const_iterator begin() const { return map.begin(); }
177 iterator end() { return map.end(); }
178 const_iterator end() const { return map.end(); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700179};
180
Tom Cherry9787f9a2020-05-19 19:01:16 -0700181class EntryBase {
182 public:
183 EntryBase() : size_(0) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700184 explicit EntryBase(const LogStatisticsElement& element) : size_(element.msg_len) {}
Mark Salyzyn758058f2015-08-21 16:44:30 -0700185
Tom Cherry9787f9a2020-05-19 19:01:16 -0700186 size_t getSizes() const { return size_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700187
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700188 void Add(const LogStatisticsElement& element) { size_ += element.msg_len; }
189 bool Subtract(const LogStatisticsElement& element) {
190 size_ -= element.msg_len;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700191 return !size_;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800192 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700193
Tom Cherry9787f9a2020-05-19 19:01:16 -0700194 static constexpr size_t PRUNED_LEN = 14;
195 static constexpr size_t TOTAL_LEN = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700196
Mark Salyzyn501c3732017-03-10 14:31:54 -0800197 static std::string formatLine(const std::string& name,
198 const std::string& size,
199 const std::string& pruned) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700200 ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
201 ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700202
Mark Salyzyn501c3732017-03-10 14:31:54 -0800203 std::string ret = android::base::StringPrintf(
204 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
205 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800206 // remove any trailing spaces
207 size_t pos = ret.size();
208 size_t len = 0;
209 while (pos && isspace(ret[--pos])) ++len;
210 if (len) ret.erase(pos + 1, len);
211 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700212 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700213
214 private:
215 size_t size_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700216};
217
Tom Cherry9787f9a2020-05-19 19:01:16 -0700218class EntryBaseDropped : public EntryBase {
219 public:
220 EntryBaseDropped() : dropped_(0) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700221 explicit EntryBaseDropped(const LogStatisticsElement& element)
222 : EntryBase(element), dropped_(element.dropped_count) {}
Mark Salyzyn34facab2014-02-06 14:48:50 -0800223
Tom Cherry9787f9a2020-05-19 19:01:16 -0700224 size_t dropped_count() const { return dropped_; }
225
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700226 void Add(const LogStatisticsElement& element) {
227 dropped_ += element.dropped_count;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700228 EntryBase::Add(element);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800229 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700230 bool Subtract(const LogStatisticsElement& element) {
231 dropped_ -= element.dropped_count;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700232 return EntryBase::Subtract(element) && !dropped_;
233 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700234 void Drop(const LogStatisticsElement& element) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700235 dropped_ += 1;
236 EntryBase::Subtract(element);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700237 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800238
Tom Cherry9787f9a2020-05-19 19:01:16 -0700239 private:
240 size_t dropped_;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800241};
242
Tom Cherry9787f9a2020-05-19 19:01:16 -0700243class UidEntry : public EntryBaseDropped {
244 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700245 explicit UidEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700246 : EntryBaseDropped(element), pid_(element.pid) {}
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700247
Tom Cherry9787f9a2020-05-19 19:01:16 -0700248 pid_t pid() const { return pid_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700249
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700250 void Add(const LogStatisticsElement& element) {
251 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700252 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800253 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700254 EntryBaseDropped::Add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800255 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700256
Mark Salyzyn501c3732017-03-10 14:31:54 -0800257 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700258 std::string format(const LogStatistics& stat, log_id_t id, uid_t uid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700259
260 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700261 pid_t pid_;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700262};
263
Tom Cherry40da03b2019-06-28 13:21:27 -0700264namespace android {
265uid_t pidToUid(pid_t pid);
266}
267
Tom Cherry9787f9a2020-05-19 19:01:16 -0700268class PidEntry : public EntryBaseDropped {
269 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800270 explicit PidEntry(pid_t pid)
271 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700272 uid_(android::pidToUid(pid)),
273 name_(android::pidToName(pid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700274 explicit PidEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700275 : EntryBaseDropped(element), uid_(element.uid), name_(android::pidToName(element.pid)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800276 PidEntry(const PidEntry& element)
277 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700278 uid_(element.uid_),
279 name_(element.name_ ? strdup(element.name_) : nullptr) {}
280 ~PidEntry() { free(name_); }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700281
Tom Cherry9787f9a2020-05-19 19:01:16 -0700282 uid_t uid() const { return uid_; }
283 const char* name() const { return name_; }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700284
Tom Cherry9787f9a2020-05-19 19:01:16 -0700285 void Add(pid_t new_pid) {
286 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
287 free(name_);
288 name_ = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700289 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700290 if (!name_) {
291 name_ = android::pidToName(new_pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700292 }
293 }
294
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700295 void Add(const LogStatisticsElement& element) {
296 uid_t incoming_uid = element.uid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700297 if (uid() != incoming_uid) {
298 uid_ = incoming_uid;
299 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700300 name_ = android::pidToName(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700301 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700302 Add(element.pid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700303 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700304 EntryBaseDropped::Add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700305 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700306
Mark Salyzyn501c3732017-03-10 14:31:54 -0800307 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700308 std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700309
310 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700311 uid_t uid_;
312 char* name_;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700313};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700314
Tom Cherry9787f9a2020-05-19 19:01:16 -0700315class TidEntry : public EntryBaseDropped {
316 public:
Mark Salyzyn501c3732017-03-10 14:31:54 -0800317 TidEntry(pid_t tid, pid_t pid)
318 : EntryBaseDropped(),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700319 pid_(pid),
320 uid_(android::pidToUid(tid)),
321 name_(android::tidToName(tid)) {}
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700322 explicit TidEntry(const LogStatisticsElement& element)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800323 : EntryBaseDropped(element),
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700324 pid_(element.pid),
325 uid_(element.uid),
Tom Cherry4596b782020-06-03 13:49:24 -0700326 name_(android::tidToName(element.tid)) {}
Mark Salyzyn501c3732017-03-10 14:31:54 -0800327 TidEntry(const TidEntry& element)
328 : EntryBaseDropped(element),
Tom Cherry9787f9a2020-05-19 19:01:16 -0700329 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 pid() const { return pid_; }
335 uid_t uid() const { return uid_; }
336 const char* name() const { return name_; }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700337
Tom Cherry9787f9a2020-05-19 19:01:16 -0700338 void Add(pid_t incomingTid) {
339 if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
340 free(name_);
341 name_ = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700342 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700343 if (!name_) {
344 name_ = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700345 }
346 }
347
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700348 void Add(const LogStatisticsElement& element) {
349 uid_t incoming_uid = element.uid;
350 pid_t incoming_pid = element.pid;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700351 if (uid() != incoming_uid || pid() != incoming_pid) {
352 uid_ = incoming_uid;
353 pid_ = incoming_pid;
354 free(name_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700355 name_ = android::tidToName(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700356 } else {
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700357 Add(element.tid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700358 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700359 EntryBaseDropped::Add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700360 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700361
Mark Salyzyn501c3732017-03-10 14:31:54 -0800362 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700363 std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700364
365 private:
Tom Cherry9787f9a2020-05-19 19:01:16 -0700366 pid_t pid_;
367 uid_t uid_;
368 char* name_;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700369};
370
Tom Cherry9787f9a2020-05-19 19:01:16 -0700371class TagEntry : public EntryBaseDropped {
372 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700373 explicit TagEntry(const LogStatisticsElement& element)
374 : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
Mark Salyzyn344bff42015-04-13 14:24:45 -0700375
Tom Cherry9787f9a2020-05-19 19:01:16 -0700376 uint32_t key() const { return tag_; }
377 pid_t pid() const { return pid_; }
378 uid_t uid() const { return uid_; }
379 const char* name() const { return android::tagToName(tag_); }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700380
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700381 void Add(const LogStatisticsElement& element) {
382 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700383 uid_ = -1;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700384 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700385 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700386 pid_ = -1;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800387 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700388 EntryBaseDropped::Add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700389 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700390
Mark Salyzyn501c3732017-03-10 14:31:54 -0800391 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherry4596b782020-06-03 13:49:24 -0700392 std::string format(const LogStatistics& stat, log_id_t id, uint32_t) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700393
394 private:
395 const uint32_t tag_;
396 pid_t pid_;
397 uid_t uid_;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700398};
399
Tom Cherry9787f9a2020-05-19 19:01:16 -0700400class TagNameEntry : public EntryBase {
401 public:
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700402 explicit TagNameEntry(const LogStatisticsElement& element)
Tom Cherry4596b782020-06-03 13:49:24 -0700403 : EntryBase(element), tid_(element.tid), pid_(element.pid), uid_(element.uid) {}
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700404
Tom Cherry9787f9a2020-05-19 19:01:16 -0700405 pid_t tid() const { return tid_; }
406 pid_t pid() const { return pid_; }
407 uid_t uid() const { return uid_; }
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700408
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700409 void Add(const LogStatisticsElement& element) {
410 if (uid_ != element.uid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700411 uid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700412 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700413 if (pid_ != element.pid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700414 pid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700415 }
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700416 if (tid_ != element.tid) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700417 tid_ = -1;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700418 }
Tom Cherry9787f9a2020-05-19 19:01:16 -0700419 EntryBase::Add(element);
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700420 }
421
422 std::string formatHeader(const std::string& name, log_id_t id) const;
Tom Cherryb0263af2020-06-03 15:38:32 -0700423 std::string format(const LogStatistics& stat, log_id_t id, const std::string& key_name) const;
Tom Cherry9787f9a2020-05-19 19:01:16 -0700424
425 private:
426 pid_t tid_;
427 pid_t pid_;
428 uid_t uid_;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700429};
430
Mark Salyzyn34facab2014-02-06 14:48:50 -0800431class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700432 friend UidEntry;
Tom Cherry64e90162020-05-07 14:44:43 -0700433 friend PidEntry;
434 friend TidEntry;
Mark Salyzync723df82015-08-24 11:08:00 -0700435
Tom Cherry64e90162020-05-07 14:44:43 -0700436 size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
437 size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
438 size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
439 size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
440 size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
441 log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
442 log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
443 log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
444 static std::atomic<size_t> SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700445 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800446
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700447 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700448 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700449 uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzyne457b742014-02-19 17:18:31 -0800450
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700451 // pid of system to size list
452 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700453 pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700454
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700455 // pid to uid list
456 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700457 pidTable_t pidTable GUARDED_BY(lock_);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700458
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700459 // tid to uid list
460 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700461 tidTable_t tidTable GUARDED_BY(lock_);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700462
Mark Salyzyn344bff42015-04-13 14:24:45 -0700463 // tag list
464 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
Tom Cherry64e90162020-05-07 14:44:43 -0700465 tagTable_t tagTable GUARDED_BY(lock_);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700466
Mark Salyzyn083b0372015-12-04 10:59:45 -0800467 // security tag list
Tom Cherry64e90162020-05-07 14:44:43 -0700468 tagTable_t securityTagTable GUARDED_BY(lock_);
Mark Salyzyn083b0372015-12-04 10:59:45 -0800469
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700470 // global tag list
Tom Cherryb0263af2020-06-03 15:38:32 -0700471 typedef LogHashtable<std::string, TagNameEntry> tagNameTable_t;
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700472 tagNameTable_t tagNameTable;
473
Tom Cherry64e90162020-05-07 14:44:43 -0700474 size_t sizeOf() const REQUIRES(lock_) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700475 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700476 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzynf99a7d62017-04-19 14:39:21 -0700477 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700478 (pidTable.size() * sizeof(pidTable_t::iterator)) +
479 (tagTable.size() * sizeof(tagTable_t::iterator));
Tom Cherry9b4246d2020-06-17 11:40:55 -0700480 for (const auto& it : pidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700481 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700482 if (name) size += strlen(name) + 1;
483 }
Tom Cherry9b4246d2020-06-17 11:40:55 -0700484 for (const auto& it : tidTable) {
Tom Cherry9787f9a2020-05-19 19:01:16 -0700485 const char* name = it.second.name();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700486 if (name) size += strlen(name) + 1;
487 }
Tom Cherry9b4246d2020-06-17 11:40:55 -0700488 for (const auto& it : tagNameTable) {
Tom Cherryb0263af2020-06-03 15:38:32 -0700489 size += sizeof(std::string);
490 size_t len = it.first.size();
491 // Account for short string optimization: if the string's length is <= 22 bytes for 64
492 // bit or <= 10 bytes for 32 bit, then there is no additional allocation.
493 if ((sizeof(std::string) == 24 && len > 22) ||
494 (sizeof(std::string) != 24 && len > 10)) {
495 size += len;
496 }
497 }
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700498 log_id_for_each(id) {
499 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700500 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700501 size += pidSystemTable[id].sizeOf();
Tom Cherryb0263af2020-06-03 15:38:32 -0700502 size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700503 }
504 return size;
505 }
506
Tom Cherry64e90162020-05-07 14:44:43 -0700507 public:
Tom Cherry9b4246d2020-06-17 11:40:55 -0700508 explicit LogStatistics(bool enable_statistics);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800509
Tom Cherrya26f7df2020-05-19 17:48:42 -0700510 void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700511 void Add(const LogStatisticsElement& entry) EXCLUDES(lock_);
512 void Subtract(const LogStatisticsElement& entry) EXCLUDES(lock_);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700513 // entry->setDropped(1) must follow this call
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700514 void Drop(const LogStatisticsElement& entry) EXCLUDES(lock_);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700515 // Correct for coalescing two entries referencing dropped content
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700516 void Erase(const LogStatisticsElement& element) EXCLUDES(lock_) {
Tom Cherry64e90162020-05-07 14:44:43 -0700517 auto lock = std::lock_guard{lock_};
Tom Cherry3dd3ec32020-06-02 15:39:21 -0700518 log_id_t log_id = element.log_id;
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700519 --mElements[log_id];
520 --mDroppedElements[log_id];
521 }
Mark Salyzyne457b742014-02-19 17:18:31 -0800522
Tom Cherryb6b78e92020-05-07 09:13:12 -0700523 void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700524 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700525 void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
Tom Cherry64e90162020-05-07 14:44:43 -0700526 size_t* second_worst_sizes) const EXCLUDES(lock_);
Tom Cherryb6b78e92020-05-07 09:13:12 -0700527 void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
Tom Cherry64e90162020-05-07 14:44:43 -0700528 size_t* second_worst_sizes) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800529
Tom Cherry64e90162020-05-07 14:44:43 -0700530 bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
531 EXCLUDES(lock_);
532
533 // Snapshot of the sizes for a given log buffer.
534 size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
535 auto lock = std::lock_guard{lock_};
Mark Salyzyn501c3732017-03-10 14:31:54 -0800536 return mSizes[id];
537 }
Tom Cherry64e90162020-05-07 14:44:43 -0700538 // TODO: Get rid of this entirely.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800539 static size_t sizesTotal() {
540 return SizesTotal;
541 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800542
Tom Cherry64e90162020-05-07 14:44:43 -0700543 std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
Mark Salyzyn9a038632014-04-07 07:05:40 -0700544
Tom Cherry64e90162020-05-07 14:44:43 -0700545 const char* PidToName(pid_t pid) const EXCLUDES(lock_);
546 uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
547 const char* UidToName(uid_t uid) const EXCLUDES(lock_);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800548
Tom Cherryb6b78e92020-05-07 09:13:12 -0700549 private:
550 template <typename TKey, typename TEntry>
551 void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
Tom Cherry64e90162020-05-07 14:44:43 -0700552 int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
553 template <typename TKey, typename TEntry>
554 std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
555 const std::string& name = std::string(""),
556 log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
557 void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
558 size_t nameLen) const REQUIRES(lock_);
559 const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
560
561 mutable std::mutex lock_;
Tom Cherryb6b78e92020-05-07 09:13:12 -0700562};