1 /*
2 * Copyright (C) 2022 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 #include "src/trace_processor/importers/proto/statsd_module.h"
17
18 #include "perfetto/ext/base/string_utils.h"
19 #include "protos/perfetto/trace/statsd/statsd_atom.pbzero.h"
20 #include "protos/perfetto/trace/trace_packet.pbzero.h"
21 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
22 #include "src/trace_processor/importers/common/slice_tracker.h"
23 #include "src/trace_processor/importers/common/track_tracker.h"
24 #include "src/trace_processor/sorter/trace_sorter.h"
25 #include "src/trace_processor/storage/trace_storage.h"
26 #include "src/trace_processor/util/descriptors.h"
27
28 #include "src/trace_processor/importers/proto/atoms.descriptor.h"
29
30 namespace perfetto {
31 namespace trace_processor {
32 namespace {
33
34 constexpr const char* kAtomProtoName = ".android.os.statsd.Atom";
35
36 using BoundInserter = ArgsTracker::BoundInserter;
37
38 class InserterDelegate : public util::ProtoToArgsParser::Delegate {
39 public:
InserterDelegate(BoundInserter & inserter,TraceStorage & storage)40 InserterDelegate(BoundInserter& inserter, TraceStorage& storage)
41 : inserter_(inserter), storage_(storage) {}
42 ~InserterDelegate() override = default;
43
44 using Key = util::ProtoToArgsParser::Key;
45
AddInteger(const Key & key,int64_t value)46 void AddInteger(const Key& key, int64_t value) override {
47 StringId flat_key_id =
48 storage_.InternString(base::StringView(key.flat_key));
49 StringId key_id = storage_.InternString(base::StringView(key.key));
50 Variadic variadic_val = Variadic::Integer(value);
51 inserter_.AddArg(flat_key_id, key_id, variadic_val);
52 }
53
AddUnsignedInteger(const Key & key,uint64_t value)54 void AddUnsignedInteger(const Key& key, uint64_t value) override {
55 StringId flat_key_id =
56 storage_.InternString(base::StringView(key.flat_key));
57 StringId key_id = storage_.InternString(base::StringView(key.key));
58 Variadic variadic_val = Variadic::UnsignedInteger(value);
59 inserter_.AddArg(flat_key_id, key_id, variadic_val);
60 }
61
AddString(const Key & key,const protozero::ConstChars & value)62 void AddString(const Key& key, const protozero::ConstChars& value) override {
63 StringId flat_key_id =
64 storage_.InternString(base::StringView(key.flat_key));
65 StringId key_id = storage_.InternString(base::StringView(key.key));
66 Variadic variadic_val = Variadic::String(storage_.InternString(value));
67 inserter_.AddArg(flat_key_id, key_id, variadic_val);
68 }
69
AddString(const Key & key,const std::string & value)70 void AddString(const Key& key, const std::string& value) override {
71 StringId flat_key_id =
72 storage_.InternString(base::StringView(key.flat_key));
73 StringId key_id = storage_.InternString(base::StringView(key.key));
74 Variadic variadic_val =
75 Variadic::String(storage_.InternString(base::StringView(value)));
76 inserter_.AddArg(flat_key_id, key_id, variadic_val);
77 }
78
AddDouble(const Key & key,double value)79 void AddDouble(const Key& key, double value) override {
80 StringId flat_key_id =
81 storage_.InternString(base::StringView(key.flat_key));
82 StringId key_id = storage_.InternString(base::StringView(key.key));
83 Variadic variadic_val = Variadic::Real(value);
84 inserter_.AddArg(flat_key_id, key_id, variadic_val);
85 }
86
AddPointer(const Key & key,const void * value)87 void AddPointer(const Key& key, const void* value) override {
88 StringId flat_key_id =
89 storage_.InternString(base::StringView(key.flat_key));
90 StringId key_id = storage_.InternString(base::StringView(key.key));
91 Variadic variadic_val =
92 Variadic::Pointer(reinterpret_cast<uintptr_t>(value));
93 inserter_.AddArg(flat_key_id, key_id, variadic_val);
94 }
95
AddBoolean(const Key & key,bool value)96 void AddBoolean(const Key& key, bool value) override {
97 StringId flat_key_id =
98 storage_.InternString(base::StringView(key.flat_key));
99 StringId key_id = storage_.InternString(base::StringView(key.key));
100 Variadic variadic_val = Variadic::Boolean(value);
101 inserter_.AddArg(flat_key_id, key_id, variadic_val);
102 }
103
AddJson(const Key &,const protozero::ConstChars &)104 bool AddJson(const Key&, const protozero::ConstChars&) override {
105 PERFETTO_FATAL("Unexpected JSON value when parsing statsd data");
106 }
107
AddNull(const Key & key)108 void AddNull(const Key& key) override {
109 StringId flat_key_id =
110 storage_.InternString(base::StringView(key.flat_key));
111 StringId key_id = storage_.InternString(base::StringView(key.key));
112 Variadic variadic_val = Variadic::Null();
113 inserter_.AddArg(flat_key_id, key_id, variadic_val);
114 }
115
GetArrayEntryIndex(const std::string & array_key)116 size_t GetArrayEntryIndex(const std::string& array_key) override {
117 base::ignore_result(array_key);
118 return 0;
119 }
120
IncrementArrayEntryIndex(const std::string & array_key)121 size_t IncrementArrayEntryIndex(const std::string& array_key) override {
122 base::ignore_result(array_key);
123 return 0;
124 }
125
seq_state()126 PacketSequenceStateGeneration* seq_state() override { return nullptr; }
127
128 protected:
GetInternedMessageView(uint32_t field_id,uint64_t iid)129 InternedMessageView* GetInternedMessageView(uint32_t field_id,
130 uint64_t iid) override {
131 base::ignore_result(field_id);
132 base::ignore_result(iid);
133 return nullptr;
134 }
135
136 private:
137 BoundInserter& inserter_;
138 TraceStorage& storage_;
139 };
140
141 } // namespace
142
143 using perfetto::protos::pbzero::TracePacket;
144
PoolAndDescriptor(const uint8_t * data,size_t size,const char * name)145 PoolAndDescriptor::PoolAndDescriptor(const uint8_t* data,
146 size_t size,
147 const char* name) {
148 pool_.AddFromFileDescriptorSet(data, size);
149 std::optional<uint32_t> opt_idx = pool_.FindDescriptorIdx(name);
150 if (opt_idx.has_value()) {
151 descriptor_ = &pool_.descriptors()[opt_idx.value()];
152 }
153 }
154
155 PoolAndDescriptor::~PoolAndDescriptor() = default;
156
StatsdModule(TraceProcessorContext * context)157 StatsdModule::StatsdModule(TraceProcessorContext* context)
158 : context_(context),
159 pool_(kAtomsDescriptor.data(), kAtomsDescriptor.size(), kAtomProtoName),
160 args_parser_(*(pool_.pool())) {
161 RegisterForField(TracePacket::kStatsdAtomFieldNumber, context);
162 }
163
164 StatsdModule::~StatsdModule() = default;
165
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData &,uint32_t field_id)166 void StatsdModule::ParseTracePacketData(const TracePacket::Decoder& decoder,
167 int64_t ts,
168 const TracePacketData&,
169 uint32_t field_id) {
170 if (field_id != TracePacket::kStatsdAtomFieldNumber) {
171 return;
172 }
173 const auto& atoms_wrapper =
174 protos::pbzero::StatsdAtom::Decoder(decoder.statsd_atom());
175 for (auto it = atoms_wrapper.atom(); it; ++it) {
176 ParseAtom(ts, *it);
177 }
178 }
179
ParseAtom(int64_t ts,protozero::ConstBytes nested_bytes)180 void StatsdModule::ParseAtom(int64_t ts, protozero::ConstBytes nested_bytes) {
181 // nested_bytes is an Atom proto. We (deliberately) don't generate
182 // decoding code for every kind of atom (or the parent Atom proto)
183 // and instead use the descriptor to parse the args/name.
184
185 // Atom is a giant oneof of all the possible 'kinds' of atom so here
186 // we use the protozero decoder implementation to grab the first
187 // field id which we we use to look up the field name:
188 protozero::ProtoDecoder nested_decoder(nested_bytes);
189 protozero::Field field = nested_decoder.ReadField();
190 uint32_t nested_field_id = 0;
191 if (field.valid()) {
192 nested_field_id = field.id();
193 }
194 StringId atom_name = GetAtomName(nested_field_id);
195
196 AsyncTrackSetTracker::TrackSetId track_set = InternAsyncTrackSetId();
197 TrackId track = context_->async_track_set_tracker->Scoped(track_set, ts, 0);
198 std::optional<SliceId> opt_slice =
199 context_->slice_tracker->Scoped(ts, track, kNullStringId, atom_name, 0);
200 if (!opt_slice) {
201 return;
202 }
203 SliceId slice = opt_slice.value();
204 auto inserter = context_->args_tracker->AddArgsTo(slice);
205 InserterDelegate delgate(inserter, *context_->storage.get());
206 args_parser_.ParseMessage(nested_bytes, kAtomProtoName,
207 nullptr /* parse all fields */, delgate);
208 }
209
GetAtomName(uint32_t atom_field_id)210 StringId StatsdModule::GetAtomName(uint32_t atom_field_id) {
211 StringId* cached_name = atom_names_.Find(atom_field_id);
212 if (cached_name == nullptr) {
213 if (pool_.descriptor() == nullptr) {
214 return context_->storage->InternString("Could not load atom descriptor");
215 }
216
217 const auto& fields = pool_.descriptor()->fields();
218 const auto& field_it = fields.find(atom_field_id);
219 if (field_it == fields.end()) {
220 return context_->storage->InternString("Unknown atom");
221 }
222
223 const FieldDescriptor& field = field_it->second;
224 StringId name =
225 context_->storage->InternString(base::StringView(field.name()));
226 atom_names_[atom_field_id] = name;
227 return name;
228 }
229 return *cached_name;
230 }
231
InternAsyncTrackSetId()232 AsyncTrackSetTracker::TrackSetId StatsdModule::InternAsyncTrackSetId() {
233 if (!track_set_id_) {
234 StringId name = context_->storage->InternString("Statsd Atoms");
235 track_set_id_ =
236 context_->async_track_set_tracker->InternGlobalTrackSet(name);
237 }
238 return track_set_id_.value();
239 }
240
241 } // namespace trace_processor
242 } // namespace perfetto
243