blob: 84dbff3cfc87b89a9095b201d192d034bb92f8bb [file] [log] [blame]
Mark Salyzyn34facab2014-02-06 14:48:50 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LOGD_LOG_STATISTICS_H__
18#define _LOGD_LOG_STATISTICS_H__
19
Mark Salyzynb545e1c2016-12-19 14:51:15 -080020#include <ctype.h>
Mark Salyzyn903156d2017-04-19 14:39:21 -070021#include <inttypes.h>
22#include <stdint.h>
Mark Salyzyn720f6d12015-03-16 08:26:05 -070023#include <stdlib.h>
Mark Salyzyn903156d2017-04-19 14:39:21 -070024#include <string.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080025#include <sys/types.h>
26
Mark Salyzyn501c3732017-03-10 14:31:54 -080027#include <algorithm> // std::max
Mark Salyzyn903156d2017-04-19 14:39:21 -070028#include <experimental/string_view>
Mark Salyzynb545e1c2016-12-19 14:51:15 -080029#include <memory>
Mark Salyzyn501c3732017-03-10 14:31:54 -080030#include <string> // std::string
Mark Salyzyn511338d2015-05-19 09:12:30 -070031#include <unordered_map>
32
Elliott Hughes4f713192015-12-04 22:00:26 -080033#include <android-base/stringprintf.h>
Mark Salyzyn501c3732017-03-10 14:31:54 -080034#include <android/log.h>
Mark Salyzyn03bb7592017-04-14 09:46:57 -070035#include <log/log_time.h>
Mark Salyzyn758058f2015-08-21 16:44:30 -070036#include <private/android_filesystem_config.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070037
38#include "LogBufferElement.h"
Mark Salyzyn5ac5c6b2015-08-28 08:02:59 -070039#include "LogUtils.h"
Mark Salyzyn34facab2014-02-06 14:48:50 -080040
41#define log_id_for_each(i) \
Mark Salyzyn501c3732017-03-10 14:31:54 -080042 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 -080043
Mark Salyzyn758058f2015-08-21 16:44:30 -070044class LogStatistics;
45
Mark Salyzyn720f6d12015-03-16 08:26:05 -070046template <typename TKey, typename TEntry>
Mark Salyzyn511338d2015-05-19 09:12:30 -070047class LogHashtable {
Mark Salyzyn511338d2015-05-19 09:12:30 -070048 std::unordered_map<TKey, TEntry> map;
49
Mark Salyzyn6d981af2016-10-06 09:55:21 -070050 size_t bucket_size() const {
51 size_t count = 0;
52 for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
53 size_t bucket_size = map.bucket_size(idx);
54 if (bucket_size == 0) bucket_size = 1;
55 count += bucket_size;
56 }
57 float load_factor = map.max_load_factor();
58 if (load_factor < 1.0) return count;
59 return count * load_factor;
60 }
61
62 static const size_t unordered_map_per_entry_overhead = sizeof(void*);
63 static const size_t unordered_map_bucket_overhead = sizeof(void*);
64
Mark Salyzyn501c3732017-03-10 14:31:54 -080065 public:
66 size_t size() const {
67 return map.size();
68 }
Mark Salyzynb0672292016-10-06 10:09:24 -070069
Mark Salyzyn6d981af2016-10-06 09:55:21 -070070 // Estimate unordered_map memory usage.
71 size_t sizeOf() const {
72 return sizeof(*this) +
Mark Salyzynb0672292016-10-06 10:09:24 -070073 (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
Mark Salyzyn6d981af2016-10-06 09:55:21 -070074 (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
75 }
76
Mark Salyzyn511338d2015-05-19 09:12:30 -070077 typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
Mark Salyzyn501c3732017-03-10 14:31:54 -080078 typedef
79 typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
Mark Salyzyn511338d2015-05-19 09:12:30 -070080
Mark Salyzyn501c3732017-03-10 14:31:54 -080081 std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
Mark Salyzynee3b8382015-12-17 09:58:43 -080082 size_t len) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -070083 if (!len) {
Mark Salyzyn903156d2017-04-19 14:39:21 -070084 std::unique_ptr<const TEntry* []> sorted(nullptr);
Mark Salyzyn720f6d12015-03-16 08:26:05 -070085 return sorted;
86 }
87
Mark Salyzyn501c3732017-03-10 14:31:54 -080088 const TEntry** retval = new const TEntry*[len];
Mark Salyzyn758058f2015-08-21 16:44:30 -070089 memset(retval, 0, sizeof(*retval) * len);
Mark Salyzyn720f6d12015-03-16 08:26:05 -070090
Mark Salyzyn501c3732017-03-10 14:31:54 -080091 for (const_iterator it = map.begin(); it != map.end(); ++it) {
92 const TEntry& entry = it->second;
Mark Salyzynee3b8382015-12-17 09:58:43 -080093
94 if ((uid != AID_ROOT) && (uid != entry.getUid())) {
95 continue;
96 }
97 if (pid && entry.getPid() && (pid != entry.getPid())) {
98 continue;
99 }
100
Mark Salyzyn758058f2015-08-21 16:44:30 -0700101 size_t sizes = entry.getSizes();
102 ssize_t index = len - 1;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800103 while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
104 (--index >= 0))
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700105 ;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700106 if (++index < (ssize_t)len) {
107 size_t num = len - index - 1;
108 if (num) {
109 memmove(&retval[index + 1], &retval[index],
110 num * sizeof(retval[0]));
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700111 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700112 retval[index] = &entry;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700113 }
114 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800115 std::unique_ptr<const TEntry* []> sorted(retval);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700116 return sorted;
117 }
118
Mark Salyzyn501c3732017-03-10 14:31:54 -0800119 inline iterator add(TKey key, LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700120 iterator it = map.find(key);
121 if (it == map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700122 it = map.insert(std::make_pair(key, TEntry(element))).first;
Mark Salyzyn511338d2015-05-19 09:12:30 -0700123 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700124 it->second.add(element);
Mark Salyzyn511338d2015-05-19 09:12:30 -0700125 }
126 return it;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700127 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700128
Mark Salyzyn511338d2015-05-19 09:12:30 -0700129 inline iterator add(TKey key) {
130 iterator it = map.find(key);
131 if (it == map.end()) {
132 it = map.insert(std::make_pair(key, TEntry(key))).first;
133 } else {
134 it->second.add(key);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700135 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700136 return it;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700137 }
138
Mark Salyzyn501c3732017-03-10 14:31:54 -0800139 void subtract(TKey key, LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700140 iterator it = map.find(key);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700141 if ((it != map.end()) && it->second.subtract(element)) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700142 map.erase(it);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700143 }
144 }
145
Mark Salyzyn501c3732017-03-10 14:31:54 -0800146 inline void drop(TKey key, LogBufferElement* element) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700147 iterator it = map.find(key);
148 if (it != map.end()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700149 it->second.drop(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700150 }
151 }
152
Mark Salyzyn501c3732017-03-10 14:31:54 -0800153 inline iterator begin() {
154 return map.begin();
155 }
156 inline const_iterator begin() const {
157 return map.begin();
158 }
159 inline iterator end() {
160 return map.end();
161 }
162 inline const_iterator end() const {
163 return map.end();
164 }
Mark Salyzyn511338d2015-05-19 09:12:30 -0700165
Mark Salyzyn501c3732017-03-10 14:31:54 -0800166 std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
167 const std::string& name = std::string(""),
168 log_id_t id = LOG_ID_MAX) const {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700169 static const size_t maximum_sorted_entries = 32;
170 std::string output;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800171 std::unique_ptr<const TEntry* []> sorted =
172 sort(uid, pid, maximum_sorted_entries);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700173 if (!sorted.get()) {
174 return output;
175 }
176 bool headerPrinted = false;
177 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800178 const TEntry* entry = sorted[index];
Mark Salyzyn758058f2015-08-21 16:44:30 -0700179 if (!entry) {
180 break;
181 }
182 if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
183 break;
184 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700185 if (!headerPrinted) {
186 output += "\n\n";
187 output += entry->formatHeader(name, id);
188 headerPrinted = true;
189 }
190 output += entry->format(stat, id);
191 }
192 return output;
193 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700194};
195
Mark Salyzyn758058f2015-08-21 16:44:30 -0700196namespace EntryBaseConstants {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800197static constexpr size_t pruned_len = 14;
198static constexpr size_t total_len = 80;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700199}
200
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700201struct EntryBase {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700202 size_t size;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700203
Mark Salyzyn501c3732017-03-10 14:31:54 -0800204 EntryBase() : size(0) {
205 }
206 explicit EntryBase(LogBufferElement* element) : size(element->getMsgLen()) {
207 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700208
Mark Salyzyn501c3732017-03-10 14:31:54 -0800209 size_t getSizes() const {
210 return size;
211 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700212
Mark Salyzyn501c3732017-03-10 14:31:54 -0800213 inline void add(LogBufferElement* element) {
214 size += element->getMsgLen();
215 }
216 inline bool subtract(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700217 size -= element->getMsgLen();
218 return !size;
219 }
220
Mark Salyzyn501c3732017-03-10 14:31:54 -0800221 static std::string formatLine(const std::string& name,
222 const std::string& size,
223 const std::string& pruned) {
224 ssize_t drop_len =
225 std::max(pruned.length() + 1, EntryBaseConstants::pruned_len);
226 ssize_t size_len =
227 std::max(size.length() + 1, EntryBaseConstants::total_len -
228 name.length() - drop_len - 1);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700229
Mark Salyzyn501c3732017-03-10 14:31:54 -0800230 std::string ret = android::base::StringPrintf(
231 "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
232 (int)drop_len, pruned.c_str());
Mark Salyzynb545e1c2016-12-19 14:51:15 -0800233 // remove any trailing spaces
234 size_t pos = ret.size();
235 size_t len = 0;
236 while (pos && isspace(ret[--pos])) ++len;
237 if (len) ret.erase(pos + 1, len);
238 return ret + "\n";
Mark Salyzyn758058f2015-08-21 16:44:30 -0700239 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700240};
241
242struct EntryBaseDropped : public EntryBase {
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700243 size_t dropped;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800244
Mark Salyzyn501c3732017-03-10 14:31:54 -0800245 EntryBaseDropped() : dropped(0) {
246 }
247 explicit EntryBaseDropped(LogBufferElement* element)
248 : EntryBase(element), dropped(element->getDropped()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700249 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800250
Mark Salyzyn501c3732017-03-10 14:31:54 -0800251 size_t getDropped() const {
252 return dropped;
253 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700254
Mark Salyzyn501c3732017-03-10 14:31:54 -0800255 inline void add(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700256 dropped += element->getDropped();
257 EntryBase::add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700258 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800259 inline bool subtract(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700260 dropped -= element->getDropped();
261 return EntryBase::subtract(element) && !dropped;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700262 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800263 inline void drop(LogBufferElement* element) {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700264 dropped += 1;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700265 EntryBase::subtract(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700266 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800267};
268
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700269struct UidEntry : public EntryBaseDropped {
270 const uid_t uid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800271 pid_t pid;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700272
Mark Salyzyn501c3732017-03-10 14:31:54 -0800273 explicit UidEntry(LogBufferElement* element)
274 : EntryBaseDropped(element),
275 uid(element->getUid()),
276 pid(element->getPid()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700277 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700278
Mark Salyzyn501c3732017-03-10 14:31:54 -0800279 inline const uid_t& getKey() const {
280 return uid;
281 }
282 inline const uid_t& getUid() const {
283 return getKey();
284 }
285 inline const pid_t& getPid() const {
286 return pid;
287 }
Mark Salyzynee3b8382015-12-17 09:58:43 -0800288
Mark Salyzyn501c3732017-03-10 14:31:54 -0800289 inline void add(LogBufferElement* element) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800290 if (pid != element->getPid()) {
291 pid = -1;
292 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800293 EntryBaseDropped::add(element);
Mark Salyzynee3b8382015-12-17 09:58:43 -0800294 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700295
Mark Salyzyn501c3732017-03-10 14:31:54 -0800296 std::string formatHeader(const std::string& name, log_id_t id) const;
297 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700298};
299
300namespace android {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700301uid_t pidToUid(pid_t pid);
302}
303
304struct PidEntry : public EntryBaseDropped {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700305 const pid_t pid;
306 uid_t uid;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800307 char* name;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700308
Mark Salyzyn501c3732017-03-10 14:31:54 -0800309 explicit PidEntry(pid_t pid)
310 : EntryBaseDropped(),
311 pid(pid),
312 uid(android::pidToUid(pid)),
313 name(android::pidToName(pid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700314 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800315 explicit PidEntry(LogBufferElement* element)
316 : EntryBaseDropped(element),
317 pid(element->getPid()),
318 uid(element->getUid()),
319 name(android::pidToName(pid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700320 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800321 PidEntry(const PidEntry& element)
322 : EntryBaseDropped(element),
323 pid(element.pid),
324 uid(element.uid),
Mark Salyzyn903156d2017-04-19 14:39:21 -0700325 name(element.name ? strdup(element.name) : nullptr) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700326 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800327 ~PidEntry() {
328 free(name);
329 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700330
Mark Salyzyn501c3732017-03-10 14:31:54 -0800331 const pid_t& getKey() const {
332 return pid;
333 }
334 const pid_t& getPid() const {
335 return getKey();
336 }
337 const uid_t& getUid() const {
338 return uid;
339 }
340 const char* getName() const {
341 return name;
342 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700343
Mark Salyzyn758058f2015-08-21 16:44:30 -0700344 inline void add(pid_t newPid) {
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800345 if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700346 free(name);
Mark Salyzyn903156d2017-04-19 14:39:21 -0700347 name = nullptr;
Mark Salyzynaa43ae22015-04-20 10:27:38 -0700348 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700349 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700350 name = android::pidToName(newPid);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700351 }
352 }
353
Mark Salyzyn501c3732017-03-10 14:31:54 -0800354 inline void add(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700355 uid_t incomingUid = element->getUid();
356 if (getUid() != incomingUid) {
357 uid = incomingUid;
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700358 free(name);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700359 name = android::pidToName(element->getPid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700360 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700361 add(element->getPid());
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700362 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700363 EntryBaseDropped::add(element);
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700364 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700365
Mark Salyzyn501c3732017-03-10 14:31:54 -0800366 std::string formatHeader(const std::string& name, log_id_t id) const;
367 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700368};
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700369
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700370struct TidEntry : public EntryBaseDropped {
371 const pid_t tid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800372 pid_t pid;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700373 uid_t uid;
Mark Salyzyn501c3732017-03-10 14:31:54 -0800374 char* name;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700375
Mark Salyzyn501c3732017-03-10 14:31:54 -0800376 TidEntry(pid_t tid, pid_t pid)
377 : EntryBaseDropped(),
378 tid(tid),
379 pid(pid),
380 uid(android::pidToUid(tid)),
381 name(android::tidToName(tid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700382 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800383 explicit TidEntry(LogBufferElement* element)
384 : EntryBaseDropped(element),
385 tid(element->getTid()),
386 pid(element->getPid()),
387 uid(element->getUid()),
388 name(android::tidToName(tid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700389 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800390 TidEntry(const TidEntry& element)
391 : EntryBaseDropped(element),
392 tid(element.tid),
393 pid(element.pid),
394 uid(element.uid),
Mark Salyzyn903156d2017-04-19 14:39:21 -0700395 name(element.name ? strdup(element.name) : nullptr) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700396 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800397 ~TidEntry() {
398 free(name);
399 }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700400
Mark Salyzyn501c3732017-03-10 14:31:54 -0800401 const pid_t& getKey() const {
402 return tid;
403 }
404 const pid_t& getTid() const {
405 return getKey();
406 }
407 const pid_t& getPid() const {
408 return pid;
409 }
410 const uid_t& getUid() const {
411 return uid;
412 }
413 const char* getName() const {
414 return name;
415 }
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700416
Mark Salyzyn758058f2015-08-21 16:44:30 -0700417 inline void add(pid_t incomingTid) {
Mark Salyzyn0eeb06b2016-12-02 10:08:48 -0800418 if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700419 free(name);
Mark Salyzyn903156d2017-04-19 14:39:21 -0700420 name = nullptr;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700421 }
422 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700423 name = android::tidToName(incomingTid);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700424 }
425 }
426
Mark Salyzyn501c3732017-03-10 14:31:54 -0800427 inline void add(LogBufferElement* element) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700428 uid_t incomingUid = element->getUid();
Mark Salyzynee3b8382015-12-17 09:58:43 -0800429 pid_t incomingPid = element->getPid();
430 if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700431 uid = incomingUid;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800432 pid = incomingPid;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700433 free(name);
Mark Salyzyn758058f2015-08-21 16:44:30 -0700434 name = android::tidToName(element->getTid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700435 } else {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700436 add(element->getTid());
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700437 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700438 EntryBaseDropped::add(element);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700439 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700440
Mark Salyzyn501c3732017-03-10 14:31:54 -0800441 std::string formatHeader(const std::string& name, log_id_t id) const;
442 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700443};
444
Mark Salyzyn6a066942016-07-14 15:34:30 -0700445struct TagEntry : public EntryBaseDropped {
Mark Salyzyn344bff42015-04-13 14:24:45 -0700446 const uint32_t tag;
Mark Salyzynee3b8382015-12-17 09:58:43 -0800447 pid_t pid;
Mark Salyzyn344bff42015-04-13 14:24:45 -0700448 uid_t uid;
449
Mark Salyzyn501c3732017-03-10 14:31:54 -0800450 explicit TagEntry(LogBufferElement* element)
451 : EntryBaseDropped(element),
452 tag(element->getTag()),
453 pid(element->getPid()),
454 uid(element->getUid()) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700455 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700456
Mark Salyzyn501c3732017-03-10 14:31:54 -0800457 const uint32_t& getKey() const {
458 return tag;
459 }
460 const pid_t& getPid() const {
461 return pid;
462 }
463 const uid_t& getUid() const {
464 return uid;
465 }
466 const char* getName() const {
467 return android::tagToName(tag);
468 }
Mark Salyzyn344bff42015-04-13 14:24:45 -0700469
Mark Salyzyn501c3732017-03-10 14:31:54 -0800470 inline void add(LogBufferElement* element) {
Mark Salyzynee3b8382015-12-17 09:58:43 -0800471 if (uid != element->getUid()) {
Mark Salyzyn344bff42015-04-13 14:24:45 -0700472 uid = -1;
473 }
Mark Salyzynee3b8382015-12-17 09:58:43 -0800474 if (pid != element->getPid()) {
475 pid = -1;
476 }
Mark Salyzyna2c02222016-12-13 10:31:29 -0800477 EntryBaseDropped::add(element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700478 }
Mark Salyzyn758058f2015-08-21 16:44:30 -0700479
Mark Salyzyn501c3732017-03-10 14:31:54 -0800480 std::string formatHeader(const std::string& name, log_id_t id) const;
481 std::string format(const LogStatistics& stat, log_id_t id) const;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700482};
483
Mark Salyzyn903156d2017-04-19 14:39:21 -0700484struct TagNameEntry : public EntryBaseDropped {
485 // We do not care that a dropped entry does, or does not exist, because
486 // the size will always report zero. But if it does, we need to account
487 // for the ones that transitioned from a known tag to chatty so that we
488 // do not spring a leak on the dropped counts.
489 static size_t droppedElsewhere;
490
491 pid_t tid;
492 pid_t pid;
493 uid_t uid;
494 std::string* alloc;
495 std::experimental::string_view name; // Saves space if const char*
496
497 explicit TagNameEntry(LogBufferElement* element)
498 : EntryBaseDropped(element),
499 tid(element->getTid()),
500 pid(element->getPid()),
501 uid(element->getUid()),
502 alloc(nullptr) {
503 if (element->isBinary()) {
504 uint32_t tag = element->getTag();
505 if (tag) {
506 const char* cp = android::tagToName(tag);
507 if (cp) {
508 name = std::experimental::string_view(cp, strlen(cp));
509 return;
510 }
511 }
512 alloc = new std::string(
513 android::base::StringPrintf("[%" PRIu32 "]", tag));
514 if (!alloc) return;
515 name = std::experimental::string_view(alloc->c_str(), alloc->size());
516 return;
517 }
518 const char* msg = element->getMsg();
519 if (!msg) {
520 name = std::experimental::string_view("chatty", strlen("chatty"));
521 return;
522 }
523 ++msg;
524 unsigned short len = element->getMsgLen();
525 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
526 if (!len) {
527 name = std::experimental::string_view("<NULL>", strlen("<NULL>"));
528 return;
529 }
530 alloc = new std::string(msg, len);
531 if (!alloc) return;
532 name = std::experimental::string_view(alloc->c_str(), alloc->size());
533 }
534
535 explicit TagNameEntry(TagNameEntry&& rval)
536 : tid(rval.tid),
537 pid(rval.pid),
538 uid(rval.uid),
539 alloc(rval.alloc),
540 name(rval.name.data(), rval.name.length()) {
541 rval.alloc = nullptr;
542 }
543
544 explicit TagNameEntry(const TagNameEntry& rval)
545 : tid(rval.tid),
546 pid(rval.pid),
547 uid(rval.uid),
548 alloc(rval.alloc ? new std::string(*rval.alloc) : nullptr),
549 name(alloc ? alloc->data() : rval.name.data(), rval.name.length()) {
550 }
551
552 ~TagNameEntry() {
553 if (alloc) delete alloc;
554 }
555
556 const std::experimental::string_view& getKey() const {
557 return name;
558 }
559 const pid_t& getTid() const {
560 return tid;
561 }
562 const pid_t& getPid() const {
563 return pid;
564 }
565 const uid_t& getUid() const {
566 return uid;
567 }
568 const char* getName() const {
569 return name.data();
570 }
571 size_t getNameAllocLength() const {
572 return alloc ? alloc->length() + 1 : 0;
573 }
574
575 size_t getDropped() {
576 if (__predict_false(name == "chatty")) { // plug the leak
577 dropped += droppedElsewhere;
578 droppedElsewhere = 0;
579 }
580 return EntryBaseDropped::getDropped();
581 }
582
583 inline void add(LogBufferElement* element) {
584 if (uid != element->getUid()) {
585 uid = -1;
586 }
587 if (pid != element->getPid()) {
588 pid = -1;
589 }
590 if (tid != element->getTid()) {
591 tid = -1;
592 }
593 // Fixup of dropped can be deferred.
594 EntryBaseDropped::add(element);
595 }
596
597 inline bool subtract(LogBufferElement* element) {
598 if (__predict_false(name == "chatty")) { // plug the leak
599 dropped += droppedElsewhere;
600 droppedElsewhere = 0;
601 }
602 return EntryBaseDropped::subtract(element);
603 }
604
605 inline void drop(LogBufferElement* element) {
606 if (__predict_false(name == "chatty")) { // plug the leak
607 dropped += droppedElsewhere;
608 droppedElsewhere = 0;
609 } else {
610 ++droppedElsewhere;
611 }
612 return EntryBaseDropped::drop(element);
613 }
614
615 std::string formatHeader(const std::string& name, log_id_t id) const;
616 std::string format(const LogStatistics& stat, log_id_t id) const;
617};
618
Mark Salyzyn6a066942016-07-14 15:34:30 -0700619template <typename TEntry>
620class LogFindWorst {
Mark Salyzyn501c3732017-03-10 14:31:54 -0800621 std::unique_ptr<const TEntry* []> sorted;
Mark Salyzyn6a066942016-07-14 15:34:30 -0700622
Mark Salyzyn501c3732017-03-10 14:31:54 -0800623 public:
624 explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
625 : sorted(std::move(sorted)) {
626 }
Mark Salyzyn6a066942016-07-14 15:34:30 -0700627
Mark Salyzyn501c3732017-03-10 14:31:54 -0800628 void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
629 size_t threshold) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700630 if (sorted.get() && sorted[0] && sorted[1]) {
631 worst_sizes = sorted[0]->getSizes();
632 if ((worst_sizes > threshold)
633 // Allow time horizon to extend roughly tenfold, assume
634 // average entry length is 100 characters.
Mark Salyzyn501c3732017-03-10 14:31:54 -0800635 && (worst_sizes > (10 * sorted[0]->getDropped()))) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700636 worst = sorted[0]->getKey();
637 second_worst_sizes = sorted[1]->getSizes();
638 if (second_worst_sizes < threshold) {
639 second_worst_sizes = threshold;
640 }
641 }
642 }
643 }
644
Mark Salyzyn501c3732017-03-10 14:31:54 -0800645 void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700646 if (sorted.get() && sorted[0] && sorted[1]) {
647 worst = sorted[0]->getKey();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800648 second_worst_sizes =
649 worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
Mark Salyzyn6a066942016-07-14 15:34:30 -0700650 }
651 }
652};
653
Mark Salyzyn34facab2014-02-06 14:48:50 -0800654// Log Statistics
655class LogStatistics {
Mark Salyzync723df82015-08-24 11:08:00 -0700656 friend UidEntry;
657
Mark Salyzyn34facab2014-02-06 14:48:50 -0800658 size_t mSizes[LOG_ID_MAX];
659 size_t mElements[LOG_ID_MAX];
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700660 size_t mDroppedElements[LOG_ID_MAX];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700661 size_t mSizesTotal[LOG_ID_MAX];
662 size_t mElementsTotal[LOG_ID_MAX];
Mark Salyzyn03bb7592017-04-14 09:46:57 -0700663 log_time mOldest[LOG_ID_MAX];
664 log_time mNewest[LOG_ID_MAX];
665 log_time mNewestDropped[LOG_ID_MAX];
Mark Salyzyn32962912016-09-12 10:29:17 -0700666 static size_t SizesTotal;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700667 bool enable;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800668
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700669 // uid to size list
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700670 typedef LogHashtable<uid_t, UidEntry> uidTable_t;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700671 uidTable_t uidTable[LOG_ID_MAX];
Mark Salyzyne457b742014-02-19 17:18:31 -0800672
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700673 // pid of system to size list
674 typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
675 pidSystemTable_t pidSystemTable[LOG_ID_MAX];
676
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700677 // pid to uid list
678 typedef LogHashtable<pid_t, PidEntry> pidTable_t;
679 pidTable_t pidTable;
680
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700681 // tid to uid list
682 typedef LogHashtable<pid_t, TidEntry> tidTable_t;
683 tidTable_t tidTable;
684
Mark Salyzyn344bff42015-04-13 14:24:45 -0700685 // tag list
686 typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
687 tagTable_t tagTable;
688
Mark Salyzyn083b0372015-12-04 10:59:45 -0800689 // security tag list
690 tagTable_t securityTagTable;
691
Mark Salyzyn903156d2017-04-19 14:39:21 -0700692 // global tag list
693 typedef LogHashtable<std::experimental::string_view, TagNameEntry>
694 tagNameTable_t;
695 tagNameTable_t tagNameTable;
696
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700697 size_t sizeOf() const {
698 size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700699 tagTable.sizeOf() + securityTagTable.sizeOf() +
Mark Salyzyn903156d2017-04-19 14:39:21 -0700700 tagNameTable.sizeOf() +
Mark Salyzynb0672292016-10-06 10:09:24 -0700701 (pidTable.size() * sizeof(pidTable_t::iterator)) +
702 (tagTable.size() * sizeof(tagTable_t::iterator));
Mark Salyzyn501c3732017-03-10 14:31:54 -0800703 for (auto it : pidTable) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700704 const char* name = it.second.getName();
705 if (name) size += strlen(name) + 1;
706 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800707 for (auto it : tidTable) {
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700708 const char* name = it.second.getName();
709 if (name) size += strlen(name) + 1;
710 }
Mark Salyzyn903156d2017-04-19 14:39:21 -0700711 for (auto it : tagNameTable) size += it.second.getNameAllocLength();
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700712 log_id_for_each(id) {
713 size += uidTable[id].sizeOf();
Mark Salyzynb0672292016-10-06 10:09:24 -0700714 size += uidTable[id].size() * sizeof(uidTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700715 size += pidSystemTable[id].sizeOf();
Mark Salyzyn501c3732017-03-10 14:31:54 -0800716 size +=
717 pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
Mark Salyzyn6d981af2016-10-06 09:55:21 -0700718 }
719 return size;
720 }
721
Mark Salyzyn501c3732017-03-10 14:31:54 -0800722 public:
Mark Salyzyn34facab2014-02-06 14:48:50 -0800723 LogStatistics();
724
Mark Salyzyn501c3732017-03-10 14:31:54 -0800725 void enableStatistics() {
726 enable = true;
727 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800728
Mark Salyzyn02dd2f42017-04-14 09:46:57 -0700729 void addTotal(LogBufferElement* entry);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800730 void add(LogBufferElement* entry);
731 void subtract(LogBufferElement* entry);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700732 // entry->setDropped(1) must follow this call
Mark Salyzyn501c3732017-03-10 14:31:54 -0800733 void drop(LogBufferElement* entry);
Mark Salyzynaaad42f2015-09-30 07:40:09 -0700734 // Correct for coalescing two entries referencing dropped content
Mark Salyzyn501c3732017-03-10 14:31:54 -0800735 void erase(LogBufferElement* element) {
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700736 log_id_t log_id = element->getLogId();
737 --mElements[log_id];
738 --mDroppedElements[log_id];
739 }
Mark Salyzyne457b742014-02-19 17:18:31 -0800740
Mark Salyzyn6a066942016-07-14 15:34:30 -0700741 LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
742 return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
Mark Salyzyn758058f2015-08-21 16:44:30 -0700743 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800744 LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
745 log_id id) {
Mark Salyzyn6a066942016-07-14 15:34:30 -0700746 return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
747 }
748 LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
749 return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
Mark Salyzynbec3c3d2015-08-28 08:02:59 -0700750 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800751
752 // fast track current value by id only
Mark Salyzyn501c3732017-03-10 14:31:54 -0800753 size_t sizes(log_id_t id) const {
754 return mSizes[id];
755 }
756 size_t elements(log_id_t id) const {
757 return mElements[id];
758 }
Mark Salyzyn58b8be82015-09-30 07:40:09 -0700759 size_t realElements(log_id_t id) const {
760 return mElements[id] - mDroppedElements[id];
761 }
Mark Salyzyn501c3732017-03-10 14:31:54 -0800762 size_t sizesTotal(log_id_t id) const {
763 return mSizesTotal[id];
764 }
765 size_t elementsTotal(log_id_t id) const {
766 return mElementsTotal[id];
767 }
768 static size_t sizesTotal() {
769 return SizesTotal;
770 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800771
Mark Salyzynee3b8382015-12-17 09:58:43 -0800772 std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
Mark Salyzyn9a038632014-04-07 07:05:40 -0700773
Mark Salyzyned777e92015-06-24 16:22:54 -0700774 // helper (must be locked directly or implicitly by mLogElementsLock)
Mark Salyzyn501c3732017-03-10 14:31:54 -0800775 const char* pidToName(pid_t pid) const;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700776 uid_t pidToUid(pid_t pid);
Mark Salyzyn501c3732017-03-10 14:31:54 -0800777 const char* uidToName(uid_t uid) const;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800778};
779
Mark Salyzyn501c3732017-03-10 14:31:54 -0800780#endif // _LOGD_LOG_STATISTICS_H__