• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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