blob: 35bcb36b9bc666adeebfe8bd70d8c19362853348 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/importers/proto/statsd_module.h"
#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/statsd/statsd_atom.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/util/descriptors.h"
#include "src/trace_processor/importers/proto/atoms.descriptor.h"
namespace perfetto {
namespace trace_processor {
namespace {
constexpr const char* kAtomProtoName = ".android.os.statsd.Atom";
using BoundInserter = ArgsTracker::BoundInserter;
class InserterDelegate : public util::ProtoToArgsParser::Delegate {
public:
InserterDelegate(BoundInserter& inserter, TraceStorage& storage)
: inserter_(inserter), storage_(storage) {}
~InserterDelegate() override = default;
using Key = util::ProtoToArgsParser::Key;
void AddInteger(const Key& key, int64_t value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::Integer(value);
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddUnsignedInteger(const Key& key, uint64_t value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::UnsignedInteger(value);
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddString(const Key& key, const protozero::ConstChars& value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::String(storage_.InternString(value));
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddString(const Key& key, const std::string& value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val =
Variadic::String(storage_.InternString(base::StringView(value)));
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddDouble(const Key& key, double value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::Real(value);
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddPointer(const Key& key, const void* value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val =
Variadic::Pointer(reinterpret_cast<uintptr_t>(value));
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
void AddBoolean(const Key& key, bool value) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::Boolean(value);
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
bool AddJson(const Key&, const protozero::ConstChars&) override {
PERFETTO_FATAL("Unexpected JSON value when parsing statsd data");
}
void AddNull(const Key& key) override {
StringId flat_key_id =
storage_.InternString(base::StringView(key.flat_key));
StringId key_id = storage_.InternString(base::StringView(key.key));
Variadic variadic_val = Variadic::Null();
inserter_.AddArg(flat_key_id, key_id, variadic_val);
}
size_t GetArrayEntryIndex(const std::string& array_key) override {
base::ignore_result(array_key);
return 0;
}
size_t IncrementArrayEntryIndex(const std::string& array_key) override {
base::ignore_result(array_key);
return 0;
}
PacketSequenceStateGeneration* seq_state() override { return nullptr; }
protected:
InternedMessageView* GetInternedMessageView(uint32_t field_id,
uint64_t iid) override {
base::ignore_result(field_id);
base::ignore_result(iid);
return nullptr;
}
private:
BoundInserter& inserter_;
TraceStorage& storage_;
};
} // namespace
using perfetto::protos::pbzero::TracePacket;
PoolAndDescriptor::PoolAndDescriptor(const uint8_t* data,
size_t size,
const char* name) {
pool_.AddFromFileDescriptorSet(data, size);
std::optional<uint32_t> opt_idx = pool_.FindDescriptorIdx(name);
if (opt_idx.has_value()) {
descriptor_ = &pool_.descriptors()[opt_idx.value()];
}
}
PoolAndDescriptor::~PoolAndDescriptor() = default;
StatsdModule::StatsdModule(TraceProcessorContext* context)
: context_(context),
pool_(kAtomsDescriptor.data(), kAtomsDescriptor.size(), kAtomProtoName),
args_parser_(*(pool_.pool())) {
RegisterForField(TracePacket::kStatsdAtomFieldNumber, context);
}
StatsdModule::~StatsdModule() = default;
void StatsdModule::ParseTracePacketData(const TracePacket::Decoder& decoder,
int64_t ts,
const TracePacketData&,
uint32_t field_id) {
if (field_id != TracePacket::kStatsdAtomFieldNumber) {
return;
}
const auto& atoms_wrapper =
protos::pbzero::StatsdAtom::Decoder(decoder.statsd_atom());
for (auto it = atoms_wrapper.atom(); it; ++it) {
ParseAtom(ts, *it);
}
}
void StatsdModule::ParseAtom(int64_t ts, protozero::ConstBytes nested_bytes) {
// nested_bytes is an Atom proto. We (deliberately) don't generate
// decoding code for every kind of atom (or the parent Atom proto)
// and instead use the descriptor to parse the args/name.
// Atom is a giant oneof of all the possible 'kinds' of atom so here
// we use the protozero decoder implementation to grab the first
// field id which we we use to look up the field name:
protozero::ProtoDecoder nested_decoder(nested_bytes);
protozero::Field field = nested_decoder.ReadField();
uint32_t nested_field_id = 0;
if (field.valid()) {
nested_field_id = field.id();
}
StringId atom_name = GetAtomName(nested_field_id);
AsyncTrackSetTracker::TrackSetId track_set = InternAsyncTrackSetId();
TrackId track = context_->async_track_set_tracker->Scoped(track_set, ts, 0);
std::optional<SliceId> opt_slice =
context_->slice_tracker->Scoped(ts, track, kNullStringId, atom_name, 0);
if (!opt_slice) {
return;
}
SliceId slice = opt_slice.value();
auto inserter = context_->args_tracker->AddArgsTo(slice);
InserterDelegate delgate(inserter, *context_->storage.get());
args_parser_.ParseMessage(nested_bytes, kAtomProtoName,
nullptr /* parse all fields */, delgate);
}
StringId StatsdModule::GetAtomName(uint32_t atom_field_id) {
StringId* cached_name = atom_names_.Find(atom_field_id);
if (cached_name == nullptr) {
if (pool_.descriptor() == nullptr) {
return context_->storage->InternString("Could not load atom descriptor");
}
const auto& fields = pool_.descriptor()->fields();
const auto& field_it = fields.find(atom_field_id);
if (field_it == fields.end()) {
return context_->storage->InternString("Unknown atom");
}
const FieldDescriptor& field = field_it->second;
StringId name =
context_->storage->InternString(base::StringView(field.name()));
atom_names_[atom_field_id] = name;
return name;
}
return *cached_name;
}
AsyncTrackSetTracker::TrackSetId StatsdModule::InternAsyncTrackSetId() {
if (!track_set_id_) {
StringId name = context_->storage->InternString("Statsd Atoms");
track_set_id_ =
context_->async_track_set_tracker->InternGlobalTrackSet(name);
}
return track_set_id_.value();
}
} // namespace trace_processor
} // namespace perfetto