xref: /aosp_15_r20/system/logging/logd/LogStatistics.h (revision 598139dc91b21518d67c408eaea2644226490971)
1*598139dcSAndroid Build Coastguard Worker /*
2*598139dcSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*598139dcSAndroid Build Coastguard Worker  *
4*598139dcSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*598139dcSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*598139dcSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*598139dcSAndroid Build Coastguard Worker  *
8*598139dcSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*598139dcSAndroid Build Coastguard Worker  *
10*598139dcSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*598139dcSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*598139dcSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*598139dcSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*598139dcSAndroid Build Coastguard Worker  * limitations under the License.
15*598139dcSAndroid Build Coastguard Worker  */
16*598139dcSAndroid Build Coastguard Worker 
17*598139dcSAndroid Build Coastguard Worker #pragma once
18*598139dcSAndroid Build Coastguard Worker 
19*598139dcSAndroid Build Coastguard Worker #include <ctype.h>
20*598139dcSAndroid Build Coastguard Worker #include <inttypes.h>
21*598139dcSAndroid Build Coastguard Worker #include <stdint.h>
22*598139dcSAndroid Build Coastguard Worker #include <stdlib.h>
23*598139dcSAndroid Build Coastguard Worker #include <string.h>
24*598139dcSAndroid Build Coastguard Worker #include <sys/types.h>
25*598139dcSAndroid Build Coastguard Worker 
26*598139dcSAndroid Build Coastguard Worker #include <algorithm>  // std::max
27*598139dcSAndroid Build Coastguard Worker #include <array>
28*598139dcSAndroid Build Coastguard Worker #include <memory>
29*598139dcSAndroid Build Coastguard Worker #include <mutex>
30*598139dcSAndroid Build Coastguard Worker #include <string>
31*598139dcSAndroid Build Coastguard Worker #include <string_view>
32*598139dcSAndroid Build Coastguard Worker #include <unordered_map>
33*598139dcSAndroid Build Coastguard Worker 
34*598139dcSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
35*598139dcSAndroid Build Coastguard Worker #include <android-base/thread_annotations.h>
36*598139dcSAndroid Build Coastguard Worker #include <android/log.h>
37*598139dcSAndroid Build Coastguard Worker #include <log/log_time.h>
38*598139dcSAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
39*598139dcSAndroid Build Coastguard Worker #include <utils/FastStrcmp.h>
40*598139dcSAndroid Build Coastguard Worker 
41*598139dcSAndroid Build Coastguard Worker #include "LogUtils.h"
42*598139dcSAndroid Build Coastguard Worker 
43*598139dcSAndroid Build Coastguard Worker #define log_id_for_each(i) \
44*598139dcSAndroid Build Coastguard Worker     for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
45*598139dcSAndroid Build Coastguard Worker 
46*598139dcSAndroid Build Coastguard Worker class LogStatistics;
47*598139dcSAndroid Build Coastguard Worker class UidEntry;
48*598139dcSAndroid Build Coastguard Worker class PidEntry;
49*598139dcSAndroid Build Coastguard Worker 
50*598139dcSAndroid Build Coastguard Worker struct LogStatisticsElement {
51*598139dcSAndroid Build Coastguard Worker     uid_t uid;
52*598139dcSAndroid Build Coastguard Worker     pid_t pid;
53*598139dcSAndroid Build Coastguard Worker     pid_t tid;
54*598139dcSAndroid Build Coastguard Worker     uint32_t tag;
55*598139dcSAndroid Build Coastguard Worker     log_time realtime;
56*598139dcSAndroid Build Coastguard Worker     const char* msg;
57*598139dcSAndroid Build Coastguard Worker     uint16_t msg_len;
58*598139dcSAndroid Build Coastguard Worker     log_id_t log_id;
59*598139dcSAndroid Build Coastguard Worker     uint16_t total_len;
60*598139dcSAndroid Build Coastguard Worker };
61*598139dcSAndroid Build Coastguard Worker 
62*598139dcSAndroid Build Coastguard Worker template <typename TKey, typename TEntry>
63*598139dcSAndroid Build Coastguard Worker class LogHashtable {
64*598139dcSAndroid Build Coastguard Worker     std::unordered_map<TKey, TEntry> map;
65*598139dcSAndroid Build Coastguard Worker 
bucket_size()66*598139dcSAndroid Build Coastguard Worker     size_t bucket_size() const {
67*598139dcSAndroid Build Coastguard Worker         size_t count = 0;
68*598139dcSAndroid Build Coastguard Worker         for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
69*598139dcSAndroid Build Coastguard Worker             size_t bucket_size = map.bucket_size(idx);
70*598139dcSAndroid Build Coastguard Worker             if (bucket_size == 0) bucket_size = 1;
71*598139dcSAndroid Build Coastguard Worker             count += bucket_size;
72*598139dcSAndroid Build Coastguard Worker         }
73*598139dcSAndroid Build Coastguard Worker         float load_factor = map.max_load_factor();
74*598139dcSAndroid Build Coastguard Worker         if (load_factor < 1.0) return count;
75*598139dcSAndroid Build Coastguard Worker         return count * load_factor;
76*598139dcSAndroid Build Coastguard Worker     }
77*598139dcSAndroid Build Coastguard Worker 
78*598139dcSAndroid Build Coastguard Worker     static const size_t unordered_map_per_entry_overhead = sizeof(void*);
79*598139dcSAndroid Build Coastguard Worker     static const size_t unordered_map_bucket_overhead = sizeof(void*);
80*598139dcSAndroid Build Coastguard Worker 
81*598139dcSAndroid Build Coastguard Worker   public:
size()82*598139dcSAndroid Build Coastguard Worker     size_t size() const {
83*598139dcSAndroid Build Coastguard Worker         return map.size();
84*598139dcSAndroid Build Coastguard Worker     }
85*598139dcSAndroid Build Coastguard Worker 
86*598139dcSAndroid Build Coastguard Worker     // Estimate unordered_map memory usage.
sizeOf()87*598139dcSAndroid Build Coastguard Worker     size_t sizeOf() const {
88*598139dcSAndroid Build Coastguard Worker         return sizeof(*this) +
89*598139dcSAndroid Build Coastguard Worker                (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
90*598139dcSAndroid Build Coastguard Worker                (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
91*598139dcSAndroid Build Coastguard Worker     }
92*598139dcSAndroid Build Coastguard Worker 
93*598139dcSAndroid Build Coastguard Worker     typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
94*598139dcSAndroid Build Coastguard Worker     typedef
95*598139dcSAndroid Build Coastguard Worker         typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
96*598139dcSAndroid Build Coastguard Worker 
97*598139dcSAndroid Build Coastguard Worker     // Returns a sorted array of up to len highest entries sorted by size.  If fewer than len
98*598139dcSAndroid Build Coastguard Worker     // entries are found, their positions are set to nullptr.
99*598139dcSAndroid Build Coastguard Worker     template <size_t len>
MaxEntries(uid_t uid,pid_t pid,std::array<const TKey *,len> & out_keys,std::array<const TEntry *,len> & out_entries)100*598139dcSAndroid Build Coastguard Worker     void MaxEntries(uid_t uid, pid_t pid, std::array<const TKey*, len>& out_keys,
101*598139dcSAndroid Build Coastguard Worker                     std::array<const TEntry*, len>& out_entries) const {
102*598139dcSAndroid Build Coastguard Worker         out_keys.fill(nullptr);
103*598139dcSAndroid Build Coastguard Worker         out_entries.fill(nullptr);
104*598139dcSAndroid Build Coastguard Worker         for (const auto& [key, entry] : map) {
105*598139dcSAndroid Build Coastguard Worker             uid_t entry_uid = 0;
106*598139dcSAndroid Build Coastguard Worker             if constexpr (std::is_same_v<TEntry, UidEntry>) {
107*598139dcSAndroid Build Coastguard Worker                 entry_uid = key;
108*598139dcSAndroid Build Coastguard Worker             } else {
109*598139dcSAndroid Build Coastguard Worker                 entry_uid = entry.uid();
110*598139dcSAndroid Build Coastguard Worker             }
111*598139dcSAndroid Build Coastguard Worker             if (uid != AID_ROOT && uid != entry_uid) {
112*598139dcSAndroid Build Coastguard Worker                 continue;
113*598139dcSAndroid Build Coastguard Worker             }
114*598139dcSAndroid Build Coastguard Worker             pid_t entry_pid = 0;
115*598139dcSAndroid Build Coastguard Worker             if constexpr (std::is_same_v<TEntry, PidEntry>) {
116*598139dcSAndroid Build Coastguard Worker                 entry_pid = key;
117*598139dcSAndroid Build Coastguard Worker             } else {
118*598139dcSAndroid Build Coastguard Worker                 entry_pid = entry.pid();
119*598139dcSAndroid Build Coastguard Worker             }
120*598139dcSAndroid Build Coastguard Worker             if (pid && entry_pid && pid != entry_pid) {
121*598139dcSAndroid Build Coastguard Worker                 continue;
122*598139dcSAndroid Build Coastguard Worker             }
123*598139dcSAndroid Build Coastguard Worker 
124*598139dcSAndroid Build Coastguard Worker             size_t sizes = entry.getSizes();
125*598139dcSAndroid Build Coastguard Worker             ssize_t index = len - 1;
126*598139dcSAndroid Build Coastguard Worker             while ((!out_entries[index] || sizes > out_entries[index]->getSizes()) && --index >= 0)
127*598139dcSAndroid Build Coastguard Worker                 ;
128*598139dcSAndroid Build Coastguard Worker             if (++index < (ssize_t)len) {
129*598139dcSAndroid Build Coastguard Worker                 size_t num = len - index - 1;
130*598139dcSAndroid Build Coastguard Worker                 if (num) {
131*598139dcSAndroid Build Coastguard Worker                     memmove(&out_keys[index + 1], &out_keys[index], num * sizeof(const TKey*));
132*598139dcSAndroid Build Coastguard Worker                     memmove(&out_entries[index + 1], &out_entries[index],
133*598139dcSAndroid Build Coastguard Worker                             num * sizeof(const TEntry*));
134*598139dcSAndroid Build Coastguard Worker                 }
135*598139dcSAndroid Build Coastguard Worker                 out_keys[index] = &key;
136*598139dcSAndroid Build Coastguard Worker                 out_entries[index] = &entry;
137*598139dcSAndroid Build Coastguard Worker             }
138*598139dcSAndroid Build Coastguard Worker         }
139*598139dcSAndroid Build Coastguard Worker     }
140*598139dcSAndroid Build Coastguard Worker 
Add(const TKey & key,const LogStatisticsElement & element)141*598139dcSAndroid Build Coastguard Worker     iterator Add(const TKey& key, const LogStatisticsElement& element) {
142*598139dcSAndroid Build Coastguard Worker         iterator it = map.find(key);
143*598139dcSAndroid Build Coastguard Worker         if (it == map.end()) {
144*598139dcSAndroid Build Coastguard Worker             it = map.insert(std::make_pair(key, TEntry(element))).first;
145*598139dcSAndroid Build Coastguard Worker         } else {
146*598139dcSAndroid Build Coastguard Worker             it->second.Add(element);
147*598139dcSAndroid Build Coastguard Worker         }
148*598139dcSAndroid Build Coastguard Worker         return it;
149*598139dcSAndroid Build Coastguard Worker     }
150*598139dcSAndroid Build Coastguard Worker 
Add(const TKey & key)151*598139dcSAndroid Build Coastguard Worker     iterator Add(const TKey& key) {
152*598139dcSAndroid Build Coastguard Worker         iterator it = map.find(key);
153*598139dcSAndroid Build Coastguard Worker         if (it == map.end()) {
154*598139dcSAndroid Build Coastguard Worker             it = map.insert(std::make_pair(key, TEntry(key))).first;
155*598139dcSAndroid Build Coastguard Worker         } else {
156*598139dcSAndroid Build Coastguard Worker             it->second.Add(key);
157*598139dcSAndroid Build Coastguard Worker         }
158*598139dcSAndroid Build Coastguard Worker         return it;
159*598139dcSAndroid Build Coastguard Worker     }
160*598139dcSAndroid Build Coastguard Worker 
Subtract(const TKey & key,const LogStatisticsElement & element)161*598139dcSAndroid Build Coastguard Worker     void Subtract(const TKey& key, const LogStatisticsElement& element) {
162*598139dcSAndroid Build Coastguard Worker         iterator it = map.find(key);
163*598139dcSAndroid Build Coastguard Worker         if (it != map.end() && it->second.Subtract(element)) {
164*598139dcSAndroid Build Coastguard Worker             map.erase(it);
165*598139dcSAndroid Build Coastguard Worker         }
166*598139dcSAndroid Build Coastguard Worker     }
167*598139dcSAndroid Build Coastguard Worker 
Drop(const TKey & key,const LogStatisticsElement & element)168*598139dcSAndroid Build Coastguard Worker     void Drop(const TKey& key, const LogStatisticsElement& element) {
169*598139dcSAndroid Build Coastguard Worker         iterator it = map.find(key);
170*598139dcSAndroid Build Coastguard Worker         if (it != map.end()) {
171*598139dcSAndroid Build Coastguard Worker             it->second.Drop(element);
172*598139dcSAndroid Build Coastguard Worker         }
173*598139dcSAndroid Build Coastguard Worker     }
174*598139dcSAndroid Build Coastguard Worker 
Erase(const TKey & key,const LogStatisticsElement & element)175*598139dcSAndroid Build Coastguard Worker     void Erase(const TKey& key, const LogStatisticsElement& element) {
176*598139dcSAndroid Build Coastguard Worker         iterator it = map.find(key);
177*598139dcSAndroid Build Coastguard Worker         if (it != map.end()) {
178*598139dcSAndroid Build Coastguard Worker             it->second.Erase(element);
179*598139dcSAndroid Build Coastguard Worker         }
180*598139dcSAndroid Build Coastguard Worker     }
181*598139dcSAndroid Build Coastguard Worker 
begin()182*598139dcSAndroid Build Coastguard Worker     iterator begin() { return map.begin(); }
begin()183*598139dcSAndroid Build Coastguard Worker     const_iterator begin() const { return map.begin(); }
end()184*598139dcSAndroid Build Coastguard Worker     iterator end() { return map.end(); }
end()185*598139dcSAndroid Build Coastguard Worker     const_iterator end() const { return map.end(); }
186*598139dcSAndroid Build Coastguard Worker };
187*598139dcSAndroid Build Coastguard Worker 
188*598139dcSAndroid Build Coastguard Worker class EntryBase {
189*598139dcSAndroid Build Coastguard Worker   public:
EntryBase()190*598139dcSAndroid Build Coastguard Worker     EntryBase() : size_(0) {}
EntryBase(const LogStatisticsElement & element)191*598139dcSAndroid Build Coastguard Worker     explicit EntryBase(const LogStatisticsElement& element) : size_(element.total_len) {}
192*598139dcSAndroid Build Coastguard Worker 
getSizes()193*598139dcSAndroid Build Coastguard Worker     size_t getSizes() const { return size_; }
194*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)195*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) { size_ += element.total_len; }
Subtract(const LogStatisticsElement & element)196*598139dcSAndroid Build Coastguard Worker     bool Subtract(const LogStatisticsElement& element) {
197*598139dcSAndroid Build Coastguard Worker         size_ -= element.total_len;
198*598139dcSAndroid Build Coastguard Worker         return size_ == 0;
199*598139dcSAndroid Build Coastguard Worker     }
Drop(const LogStatisticsElement & element)200*598139dcSAndroid Build Coastguard Worker     void Drop(const LogStatisticsElement& element) { size_ -= element.msg_len; }
Erase(const LogStatisticsElement & element)201*598139dcSAndroid Build Coastguard Worker     void Erase(const LogStatisticsElement& element) { size_ -= element.total_len; }
202*598139dcSAndroid Build Coastguard Worker 
203*598139dcSAndroid Build Coastguard Worker     static constexpr size_t PRUNED_LEN = 14;
204*598139dcSAndroid Build Coastguard Worker     static constexpr size_t TOTAL_LEN = 80;
205*598139dcSAndroid Build Coastguard Worker 
formatLine(const std::string & name,const std::string & size,const std::string & pruned)206*598139dcSAndroid Build Coastguard Worker     static std::string formatLine(const std::string& name,
207*598139dcSAndroid Build Coastguard Worker                                   const std::string& size,
208*598139dcSAndroid Build Coastguard Worker                                   const std::string& pruned) {
209*598139dcSAndroid Build Coastguard Worker         ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
210*598139dcSAndroid Build Coastguard Worker         ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
211*598139dcSAndroid Build Coastguard Worker 
212*598139dcSAndroid Build Coastguard Worker         std::string ret = android::base::StringPrintf(
213*598139dcSAndroid Build Coastguard Worker             "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
214*598139dcSAndroid Build Coastguard Worker             (int)drop_len, pruned.c_str());
215*598139dcSAndroid Build Coastguard Worker         // remove any trailing spaces
216*598139dcSAndroid Build Coastguard Worker         size_t pos = ret.size();
217*598139dcSAndroid Build Coastguard Worker         size_t len = 0;
218*598139dcSAndroid Build Coastguard Worker         while (pos && isspace(ret[--pos])) ++len;
219*598139dcSAndroid Build Coastguard Worker         if (len) ret.erase(pos + 1, len);
220*598139dcSAndroid Build Coastguard Worker         return ret + "\n";
221*598139dcSAndroid Build Coastguard Worker     }
222*598139dcSAndroid Build Coastguard Worker 
223*598139dcSAndroid Build Coastguard Worker   private:
224*598139dcSAndroid Build Coastguard Worker     size_t size_;
225*598139dcSAndroid Build Coastguard Worker };
226*598139dcSAndroid Build Coastguard Worker 
227*598139dcSAndroid Build Coastguard Worker class UidEntry : public EntryBase {
228*598139dcSAndroid Build Coastguard Worker   public:
UidEntry(const LogStatisticsElement & element)229*598139dcSAndroid Build Coastguard Worker     explicit UidEntry(const LogStatisticsElement& element)
230*598139dcSAndroid Build Coastguard Worker         : EntryBase(element), pid_(element.pid) {}
231*598139dcSAndroid Build Coastguard Worker 
pid()232*598139dcSAndroid Build Coastguard Worker     pid_t pid() const { return pid_; }
233*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)234*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) {
235*598139dcSAndroid Build Coastguard Worker         if (pid_ != element.pid) {
236*598139dcSAndroid Build Coastguard Worker             pid_ = -1;
237*598139dcSAndroid Build Coastguard Worker         }
238*598139dcSAndroid Build Coastguard Worker         EntryBase::Add(element);
239*598139dcSAndroid Build Coastguard Worker     }
240*598139dcSAndroid Build Coastguard Worker 
241*598139dcSAndroid Build Coastguard Worker     std::string formatHeader(const std::string& name, log_id_t id) const;
242*598139dcSAndroid Build Coastguard Worker     std::string format(const LogStatistics& stat, log_id_t id, uid_t uid) const;
243*598139dcSAndroid Build Coastguard Worker 
244*598139dcSAndroid Build Coastguard Worker   private:
245*598139dcSAndroid Build Coastguard Worker     pid_t pid_;
246*598139dcSAndroid Build Coastguard Worker };
247*598139dcSAndroid Build Coastguard Worker 
248*598139dcSAndroid Build Coastguard Worker namespace android {
249*598139dcSAndroid Build Coastguard Worker uid_t pidToUid(pid_t pid);
250*598139dcSAndroid Build Coastguard Worker }
251*598139dcSAndroid Build Coastguard Worker 
252*598139dcSAndroid Build Coastguard Worker class PidEntry : public EntryBase {
253*598139dcSAndroid Build Coastguard Worker   public:
PidEntry(pid_t pid)254*598139dcSAndroid Build Coastguard Worker     explicit PidEntry(pid_t pid)
255*598139dcSAndroid Build Coastguard Worker         : EntryBase(), uid_(android::pidToUid(pid)), name_(android::pidToName(pid)) {}
PidEntry(const LogStatisticsElement & element)256*598139dcSAndroid Build Coastguard Worker     explicit PidEntry(const LogStatisticsElement& element)
257*598139dcSAndroid Build Coastguard Worker         : EntryBase(element), uid_(element.uid), name_(android::pidToName(element.pid)) {}
PidEntry(const PidEntry & element)258*598139dcSAndroid Build Coastguard Worker     PidEntry(const PidEntry& element)
259*598139dcSAndroid Build Coastguard Worker         : EntryBase(element),
260*598139dcSAndroid Build Coastguard Worker           uid_(element.uid_),
261*598139dcSAndroid Build Coastguard Worker           name_(element.name_ ? strdup(element.name_) : nullptr) {}
~PidEntry()262*598139dcSAndroid Build Coastguard Worker     ~PidEntry() { free(name_); }
263*598139dcSAndroid Build Coastguard Worker 
uid()264*598139dcSAndroid Build Coastguard Worker     uid_t uid() const { return uid_; }
name()265*598139dcSAndroid Build Coastguard Worker     const char* name() const { return name_; }
266*598139dcSAndroid Build Coastguard Worker 
Add(pid_t new_pid)267*598139dcSAndroid Build Coastguard Worker     void Add(pid_t new_pid) {
268*598139dcSAndroid Build Coastguard Worker         if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
269*598139dcSAndroid Build Coastguard Worker             free(name_);
270*598139dcSAndroid Build Coastguard Worker             name_ = nullptr;
271*598139dcSAndroid Build Coastguard Worker         }
272*598139dcSAndroid Build Coastguard Worker         if (!name_) {
273*598139dcSAndroid Build Coastguard Worker             name_ = android::pidToName(new_pid);
274*598139dcSAndroid Build Coastguard Worker         }
275*598139dcSAndroid Build Coastguard Worker     }
276*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)277*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) {
278*598139dcSAndroid Build Coastguard Worker         uid_t incoming_uid = element.uid;
279*598139dcSAndroid Build Coastguard Worker         if (uid() != incoming_uid) {
280*598139dcSAndroid Build Coastguard Worker             uid_ = incoming_uid;
281*598139dcSAndroid Build Coastguard Worker             free(name_);
282*598139dcSAndroid Build Coastguard Worker             name_ = android::pidToName(element.pid);
283*598139dcSAndroid Build Coastguard Worker         } else {
284*598139dcSAndroid Build Coastguard Worker             Add(element.pid);
285*598139dcSAndroid Build Coastguard Worker         }
286*598139dcSAndroid Build Coastguard Worker         EntryBase::Add(element);
287*598139dcSAndroid Build Coastguard Worker     }
288*598139dcSAndroid Build Coastguard Worker 
289*598139dcSAndroid Build Coastguard Worker     std::string formatHeader(const std::string& name, log_id_t id) const;
290*598139dcSAndroid Build Coastguard Worker     std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
291*598139dcSAndroid Build Coastguard Worker 
292*598139dcSAndroid Build Coastguard Worker   private:
293*598139dcSAndroid Build Coastguard Worker     uid_t uid_;
294*598139dcSAndroid Build Coastguard Worker     char* name_;
295*598139dcSAndroid Build Coastguard Worker };
296*598139dcSAndroid Build Coastguard Worker 
297*598139dcSAndroid Build Coastguard Worker class TidEntry : public EntryBase {
298*598139dcSAndroid Build Coastguard Worker   public:
TidEntry(pid_t tid,pid_t pid)299*598139dcSAndroid Build Coastguard Worker     TidEntry(pid_t tid, pid_t pid)
300*598139dcSAndroid Build Coastguard Worker         : EntryBase(), pid_(pid), uid_(android::pidToUid(tid)), name_(android::tidToName(tid)) {}
TidEntry(const LogStatisticsElement & element)301*598139dcSAndroid Build Coastguard Worker     explicit TidEntry(const LogStatisticsElement& element)
302*598139dcSAndroid Build Coastguard Worker         : EntryBase(element),
303*598139dcSAndroid Build Coastguard Worker           pid_(element.pid),
304*598139dcSAndroid Build Coastguard Worker           uid_(element.uid),
305*598139dcSAndroid Build Coastguard Worker           name_(android::tidToName(element.tid)) {}
TidEntry(const TidEntry & element)306*598139dcSAndroid Build Coastguard Worker     TidEntry(const TidEntry& element)
307*598139dcSAndroid Build Coastguard Worker         : EntryBase(element),
308*598139dcSAndroid Build Coastguard Worker           pid_(element.pid_),
309*598139dcSAndroid Build Coastguard Worker           uid_(element.uid_),
310*598139dcSAndroid Build Coastguard Worker           name_(element.name_ ? strdup(element.name_) : nullptr) {}
~TidEntry()311*598139dcSAndroid Build Coastguard Worker     ~TidEntry() { free(name_); }
312*598139dcSAndroid Build Coastguard Worker 
pid()313*598139dcSAndroid Build Coastguard Worker     pid_t pid() const { return pid_; }
uid()314*598139dcSAndroid Build Coastguard Worker     uid_t uid() const { return uid_; }
name()315*598139dcSAndroid Build Coastguard Worker     const char* name() const { return name_; }
316*598139dcSAndroid Build Coastguard Worker 
Add(pid_t incomingTid)317*598139dcSAndroid Build Coastguard Worker     void Add(pid_t incomingTid) {
318*598139dcSAndroid Build Coastguard Worker         if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
319*598139dcSAndroid Build Coastguard Worker             free(name_);
320*598139dcSAndroid Build Coastguard Worker             name_ = nullptr;
321*598139dcSAndroid Build Coastguard Worker         }
322*598139dcSAndroid Build Coastguard Worker         if (!name_) {
323*598139dcSAndroid Build Coastguard Worker             name_ = android::tidToName(incomingTid);
324*598139dcSAndroid Build Coastguard Worker         }
325*598139dcSAndroid Build Coastguard Worker     }
326*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)327*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) {
328*598139dcSAndroid Build Coastguard Worker         uid_t incoming_uid = element.uid;
329*598139dcSAndroid Build Coastguard Worker         pid_t incoming_pid = element.pid;
330*598139dcSAndroid Build Coastguard Worker         if (uid() != incoming_uid || pid() != incoming_pid) {
331*598139dcSAndroid Build Coastguard Worker             uid_ = incoming_uid;
332*598139dcSAndroid Build Coastguard Worker             pid_ = incoming_pid;
333*598139dcSAndroid Build Coastguard Worker             free(name_);
334*598139dcSAndroid Build Coastguard Worker             name_ = android::tidToName(element.tid);
335*598139dcSAndroid Build Coastguard Worker         } else {
336*598139dcSAndroid Build Coastguard Worker             Add(element.tid);
337*598139dcSAndroid Build Coastguard Worker         }
338*598139dcSAndroid Build Coastguard Worker         EntryBase::Add(element);
339*598139dcSAndroid Build Coastguard Worker     }
340*598139dcSAndroid Build Coastguard Worker 
341*598139dcSAndroid Build Coastguard Worker     std::string formatHeader(const std::string& name, log_id_t id) const;
342*598139dcSAndroid Build Coastguard Worker     std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
343*598139dcSAndroid Build Coastguard Worker 
344*598139dcSAndroid Build Coastguard Worker   private:
345*598139dcSAndroid Build Coastguard Worker     pid_t pid_;
346*598139dcSAndroid Build Coastguard Worker     uid_t uid_;
347*598139dcSAndroid Build Coastguard Worker     char* name_;
348*598139dcSAndroid Build Coastguard Worker };
349*598139dcSAndroid Build Coastguard Worker 
350*598139dcSAndroid Build Coastguard Worker class TagEntry : public EntryBase {
351*598139dcSAndroid Build Coastguard Worker   public:
TagEntry(const LogStatisticsElement & element)352*598139dcSAndroid Build Coastguard Worker     explicit TagEntry(const LogStatisticsElement& element)
353*598139dcSAndroid Build Coastguard Worker         : EntryBase(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
354*598139dcSAndroid Build Coastguard Worker 
key()355*598139dcSAndroid Build Coastguard Worker     uint32_t key() const { return tag_; }
pid()356*598139dcSAndroid Build Coastguard Worker     pid_t pid() const { return pid_; }
uid()357*598139dcSAndroid Build Coastguard Worker     uid_t uid() const { return uid_; }
name()358*598139dcSAndroid Build Coastguard Worker     const char* name() const { return android::tagToName(tag_); }
359*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)360*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) {
361*598139dcSAndroid Build Coastguard Worker         if (uid_ != element.uid) {
362*598139dcSAndroid Build Coastguard Worker             uid_ = -1;
363*598139dcSAndroid Build Coastguard Worker         }
364*598139dcSAndroid Build Coastguard Worker         if (pid_ != element.pid) {
365*598139dcSAndroid Build Coastguard Worker             pid_ = -1;
366*598139dcSAndroid Build Coastguard Worker         }
367*598139dcSAndroid Build Coastguard Worker         EntryBase::Add(element);
368*598139dcSAndroid Build Coastguard Worker     }
369*598139dcSAndroid Build Coastguard Worker 
370*598139dcSAndroid Build Coastguard Worker     std::string formatHeader(const std::string& name, log_id_t id) const;
371*598139dcSAndroid Build Coastguard Worker     std::string format(const LogStatistics& stat, log_id_t id, uint32_t) const;
372*598139dcSAndroid Build Coastguard Worker 
373*598139dcSAndroid Build Coastguard Worker   private:
374*598139dcSAndroid Build Coastguard Worker     const uint32_t tag_;
375*598139dcSAndroid Build Coastguard Worker     pid_t pid_;
376*598139dcSAndroid Build Coastguard Worker     uid_t uid_;
377*598139dcSAndroid Build Coastguard Worker };
378*598139dcSAndroid Build Coastguard Worker 
379*598139dcSAndroid Build Coastguard Worker class TagNameEntry : public EntryBase {
380*598139dcSAndroid Build Coastguard Worker   public:
TagNameEntry(const LogStatisticsElement & element)381*598139dcSAndroid Build Coastguard Worker     explicit TagNameEntry(const LogStatisticsElement& element)
382*598139dcSAndroid Build Coastguard Worker         : EntryBase(element), tid_(element.tid), pid_(element.pid), uid_(element.uid) {}
383*598139dcSAndroid Build Coastguard Worker 
tid()384*598139dcSAndroid Build Coastguard Worker     pid_t tid() const { return tid_; }
pid()385*598139dcSAndroid Build Coastguard Worker     pid_t pid() const { return pid_; }
uid()386*598139dcSAndroid Build Coastguard Worker     uid_t uid() const { return uid_; }
387*598139dcSAndroid Build Coastguard Worker 
Add(const LogStatisticsElement & element)388*598139dcSAndroid Build Coastguard Worker     void Add(const LogStatisticsElement& element) {
389*598139dcSAndroid Build Coastguard Worker         if (uid_ != element.uid) {
390*598139dcSAndroid Build Coastguard Worker             uid_ = -1;
391*598139dcSAndroid Build Coastguard Worker         }
392*598139dcSAndroid Build Coastguard Worker         if (pid_ != element.pid) {
393*598139dcSAndroid Build Coastguard Worker             pid_ = -1;
394*598139dcSAndroid Build Coastguard Worker         }
395*598139dcSAndroid Build Coastguard Worker         if (tid_ != element.tid) {
396*598139dcSAndroid Build Coastguard Worker             tid_ = -1;
397*598139dcSAndroid Build Coastguard Worker         }
398*598139dcSAndroid Build Coastguard Worker         EntryBase::Add(element);
399*598139dcSAndroid Build Coastguard Worker     }
400*598139dcSAndroid Build Coastguard Worker 
401*598139dcSAndroid Build Coastguard Worker     std::string formatHeader(const std::string& name, log_id_t id) const;
402*598139dcSAndroid Build Coastguard Worker     std::string format(const LogStatistics& stat, log_id_t id, const std::string& key_name) const;
403*598139dcSAndroid Build Coastguard Worker 
404*598139dcSAndroid Build Coastguard Worker   private:
405*598139dcSAndroid Build Coastguard Worker     pid_t tid_;
406*598139dcSAndroid Build Coastguard Worker     pid_t pid_;
407*598139dcSAndroid Build Coastguard Worker     uid_t uid_;
408*598139dcSAndroid Build Coastguard Worker };
409*598139dcSAndroid Build Coastguard Worker 
410*598139dcSAndroid Build Coastguard Worker class LogStatistics {
411*598139dcSAndroid Build Coastguard Worker     friend UidEntry;
412*598139dcSAndroid Build Coastguard Worker     friend PidEntry;
413*598139dcSAndroid Build Coastguard Worker     friend TidEntry;
414*598139dcSAndroid Build Coastguard Worker 
415*598139dcSAndroid Build Coastguard Worker     size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
416*598139dcSAndroid Build Coastguard Worker     size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
417*598139dcSAndroid Build Coastguard Worker     size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
418*598139dcSAndroid Build Coastguard Worker     size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
419*598139dcSAndroid Build Coastguard Worker     log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
420*598139dcSAndroid Build Coastguard Worker     log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
421*598139dcSAndroid Build Coastguard Worker     static std::atomic<size_t> SizesTotal;
422*598139dcSAndroid Build Coastguard Worker     bool enable;
423*598139dcSAndroid Build Coastguard Worker 
424*598139dcSAndroid Build Coastguard Worker     // uid to size list
425*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<uid_t, UidEntry> uidTable_t;
426*598139dcSAndroid Build Coastguard Worker     uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
427*598139dcSAndroid Build Coastguard Worker 
428*598139dcSAndroid Build Coastguard Worker     // pid of system to size list
429*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
430*598139dcSAndroid Build Coastguard Worker     pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
431*598139dcSAndroid Build Coastguard Worker 
432*598139dcSAndroid Build Coastguard Worker     // pid to uid list
433*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
434*598139dcSAndroid Build Coastguard Worker     pidTable_t pidTable GUARDED_BY(lock_);
435*598139dcSAndroid Build Coastguard Worker 
436*598139dcSAndroid Build Coastguard Worker     // tid to uid list
437*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<pid_t, TidEntry> tidTable_t;
438*598139dcSAndroid Build Coastguard Worker     tidTable_t tidTable GUARDED_BY(lock_);
439*598139dcSAndroid Build Coastguard Worker 
440*598139dcSAndroid Build Coastguard Worker     // tag list
441*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
442*598139dcSAndroid Build Coastguard Worker     tagTable_t tagTable GUARDED_BY(lock_);
443*598139dcSAndroid Build Coastguard Worker 
444*598139dcSAndroid Build Coastguard Worker     // security tag list
445*598139dcSAndroid Build Coastguard Worker     tagTable_t securityTagTable GUARDED_BY(lock_);
446*598139dcSAndroid Build Coastguard Worker 
447*598139dcSAndroid Build Coastguard Worker     // global tag list
448*598139dcSAndroid Build Coastguard Worker     typedef LogHashtable<std::string, TagNameEntry> tagNameTable_t;
449*598139dcSAndroid Build Coastguard Worker     tagNameTable_t tagNameTable;
450*598139dcSAndroid Build Coastguard Worker 
sizeOf()451*598139dcSAndroid Build Coastguard Worker     size_t sizeOf() const REQUIRES(lock_) {
452*598139dcSAndroid Build Coastguard Worker         size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
453*598139dcSAndroid Build Coastguard Worker                       tagTable.sizeOf() + securityTagTable.sizeOf() +
454*598139dcSAndroid Build Coastguard Worker                       tagNameTable.sizeOf() +
455*598139dcSAndroid Build Coastguard Worker                       (pidTable.size() * sizeof(pidTable_t::iterator)) +
456*598139dcSAndroid Build Coastguard Worker                       (tagTable.size() * sizeof(tagTable_t::iterator));
457*598139dcSAndroid Build Coastguard Worker         for (const auto& it : pidTable) {
458*598139dcSAndroid Build Coastguard Worker             const char* name = it.second.name();
459*598139dcSAndroid Build Coastguard Worker             if (name) size += strlen(name) + 1;
460*598139dcSAndroid Build Coastguard Worker         }
461*598139dcSAndroid Build Coastguard Worker         for (const auto& it : tidTable) {
462*598139dcSAndroid Build Coastguard Worker             const char* name = it.second.name();
463*598139dcSAndroid Build Coastguard Worker             if (name) size += strlen(name) + 1;
464*598139dcSAndroid Build Coastguard Worker         }
465*598139dcSAndroid Build Coastguard Worker         for (const auto& it : tagNameTable) {
466*598139dcSAndroid Build Coastguard Worker             size += sizeof(std::string);
467*598139dcSAndroid Build Coastguard Worker             size_t len = it.first.size();
468*598139dcSAndroid Build Coastguard Worker             // Account for short string optimization: if the string's length is <= 22 bytes for 64
469*598139dcSAndroid Build Coastguard Worker             // bit or <= 10 bytes for 32 bit, then there is no additional allocation.
470*598139dcSAndroid Build Coastguard Worker             if ((sizeof(std::string) == 24 && len > 22) ||
471*598139dcSAndroid Build Coastguard Worker                 (sizeof(std::string) != 24 && len > 10)) {
472*598139dcSAndroid Build Coastguard Worker                 size += len;
473*598139dcSAndroid Build Coastguard Worker             }
474*598139dcSAndroid Build Coastguard Worker         }
475*598139dcSAndroid Build Coastguard Worker         log_id_for_each(id) {
476*598139dcSAndroid Build Coastguard Worker             size += uidTable[id].sizeOf();
477*598139dcSAndroid Build Coastguard Worker             size += uidTable[id].size() * sizeof(uidTable_t::iterator);
478*598139dcSAndroid Build Coastguard Worker             size += pidSystemTable[id].sizeOf();
479*598139dcSAndroid Build Coastguard Worker             size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
480*598139dcSAndroid Build Coastguard Worker         }
481*598139dcSAndroid Build Coastguard Worker         return size;
482*598139dcSAndroid Build Coastguard Worker     }
483*598139dcSAndroid Build Coastguard Worker 
484*598139dcSAndroid Build Coastguard Worker   public:
485*598139dcSAndroid Build Coastguard Worker     LogStatistics(bool enable_statistics, bool track_total_size,
486*598139dcSAndroid Build Coastguard Worker                   std::optional<log_time> start_time = {});
487*598139dcSAndroid Build Coastguard Worker 
488*598139dcSAndroid Build Coastguard Worker     void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
489*598139dcSAndroid Build Coastguard Worker 
490*598139dcSAndroid Build Coastguard Worker     // Add is for adding an element to the log buffer.
491*598139dcSAndroid Build Coastguard Worker     // Add the total size of the element to statistics.
492*598139dcSAndroid Build Coastguard Worker     void Add(LogStatisticsElement entry) EXCLUDES(lock_);
493*598139dcSAndroid Build Coastguard Worker     // Subtract is for removing an element from the log buffer.
494*598139dcSAndroid Build Coastguard Worker     // Subtract the total size of the element from statistics.
495*598139dcSAndroid Build Coastguard Worker     void Subtract(LogStatisticsElement entry) EXCLUDES(lock_);
496*598139dcSAndroid Build Coastguard Worker 
497*598139dcSAndroid Build Coastguard Worker     bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
498*598139dcSAndroid Build Coastguard Worker             EXCLUDES(lock_);
499*598139dcSAndroid Build Coastguard Worker 
500*598139dcSAndroid Build Coastguard Worker     // Return the consumed size of the given buffer.
Sizes(log_id_t id)501*598139dcSAndroid Build Coastguard Worker     size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
502*598139dcSAndroid Build Coastguard Worker         auto lock = std::lock_guard{lock_};
503*598139dcSAndroid Build Coastguard Worker         if (overhead_[id]) {
504*598139dcSAndroid Build Coastguard Worker             return *overhead_[id];
505*598139dcSAndroid Build Coastguard Worker         }
506*598139dcSAndroid Build Coastguard Worker         return mSizes[id];
507*598139dcSAndroid Build Coastguard Worker     }
508*598139dcSAndroid Build Coastguard Worker 
509*598139dcSAndroid Build Coastguard Worker     // Return the uncompressed size of the contents of the given buffer.
SizeReadable(log_id_t id)510*598139dcSAndroid Build Coastguard Worker     size_t SizeReadable(log_id_t id) const EXCLUDES(lock_) {
511*598139dcSAndroid Build Coastguard Worker         auto lock = std::lock_guard{lock_};
512*598139dcSAndroid Build Coastguard Worker         return mSizes[id];
513*598139dcSAndroid Build Coastguard Worker     }
514*598139dcSAndroid Build Coastguard Worker 
515*598139dcSAndroid Build Coastguard Worker     // TODO: Get rid of this entirely.
sizesTotal()516*598139dcSAndroid Build Coastguard Worker     static size_t sizesTotal() {
517*598139dcSAndroid Build Coastguard Worker         return SizesTotal;
518*598139dcSAndroid Build Coastguard Worker     }
519*598139dcSAndroid Build Coastguard Worker 
520*598139dcSAndroid Build Coastguard Worker     std::string ReportInteresting() const EXCLUDES(lock_);
521*598139dcSAndroid Build Coastguard Worker     std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
522*598139dcSAndroid Build Coastguard Worker 
523*598139dcSAndroid Build Coastguard Worker     const char* PidToName(pid_t pid) const EXCLUDES(lock_);
524*598139dcSAndroid Build Coastguard Worker     uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
525*598139dcSAndroid Build Coastguard Worker     const char* UidToName(uid_t uid) const EXCLUDES(lock_);
526*598139dcSAndroid Build Coastguard Worker 
set_overhead(log_id_t id,size_t size)527*598139dcSAndroid Build Coastguard Worker     void set_overhead(log_id_t id, size_t size) {
528*598139dcSAndroid Build Coastguard Worker         auto lock = std::lock_guard{lock_};
529*598139dcSAndroid Build Coastguard Worker         overhead_[id] = size;
530*598139dcSAndroid Build Coastguard Worker     }
531*598139dcSAndroid Build Coastguard Worker 
532*598139dcSAndroid Build Coastguard Worker   private:
533*598139dcSAndroid Build Coastguard Worker     template <typename TKey, typename TEntry>
534*598139dcSAndroid Build Coastguard Worker     std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
535*598139dcSAndroid Build Coastguard Worker                             const std::string& name = std::string(""),
536*598139dcSAndroid Build Coastguard Worker                             log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
537*598139dcSAndroid Build Coastguard Worker     void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
538*598139dcSAndroid Build Coastguard Worker                    size_t nameLen) const REQUIRES(lock_);
539*598139dcSAndroid Build Coastguard Worker     const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
540*598139dcSAndroid Build Coastguard Worker 
541*598139dcSAndroid Build Coastguard Worker     mutable std::mutex lock_;
542*598139dcSAndroid Build Coastguard Worker     bool track_total_size_;
543*598139dcSAndroid Build Coastguard Worker 
544*598139dcSAndroid Build Coastguard Worker     std::optional<size_t> overhead_[LOG_ID_MAX] GUARDED_BY(lock_);
545*598139dcSAndroid Build Coastguard Worker };
546