| /* |
| * Copyright (C) 2019 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. |
| */ |
| |
| #ifndef SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ |
| #define SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "perfetto/base/status.h" |
| #include "protos/perfetto/common/descriptor.pbzero.h" |
| |
| namespace protozero { |
| struct ConstBytes; |
| } |
| |
| namespace perfetto { |
| namespace trace_processor { |
| |
| class FieldDescriptor { |
| public: |
| FieldDescriptor(std::string name, |
| uint32_t number, |
| uint32_t type, |
| std::string raw_type_name, |
| std::vector<uint8_t>, |
| bool is_repeated, |
| bool is_packed, |
| bool is_extension = false); |
| |
| const std::string& name() const { return name_; } |
| uint32_t number() const { return number_; } |
| uint32_t type() const { return type_; } |
| const std::string& raw_type_name() const { return raw_type_name_; } |
| const std::string& resolved_type_name() const { return resolved_type_name_; } |
| bool is_repeated() const { return is_repeated_; } |
| bool is_packed() const { return is_packed_; } |
| bool is_extension() const { return is_extension_; } |
| |
| const std::vector<uint8_t>& options() const { return options_; } |
| std::vector<uint8_t>* mutable_options() { return &options_; } |
| |
| void set_resolved_type_name(const std::string& resolved_type_name) { |
| resolved_type_name_ = resolved_type_name; |
| } |
| |
| private: |
| std::string name_; |
| uint32_t number_; |
| uint32_t type_; |
| std::string raw_type_name_; |
| std::string resolved_type_name_; |
| std::vector<uint8_t> options_; |
| bool is_repeated_; |
| bool is_packed_; |
| bool is_extension_; |
| }; |
| |
| class ProtoDescriptor { |
| public: |
| enum class Type { kEnum = 0, kMessage = 1 }; |
| |
| ProtoDescriptor(std::string file_name, |
| std::string package_name, |
| std::string full_name, |
| Type type, |
| std::optional<uint32_t> parent_id); |
| |
| void AddField(FieldDescriptor descriptor) { |
| PERFETTO_DCHECK(type_ == Type::kMessage); |
| fields_.emplace(descriptor.number(), std::move(descriptor)); |
| } |
| |
| void AddEnumValue(int32_t integer_representation, |
| std::string string_representation) { |
| PERFETTO_DCHECK(type_ == Type::kEnum); |
| enum_values_by_name_[string_representation] = integer_representation; |
| enum_names_by_value_[integer_representation] = |
| std::move(string_representation); |
| } |
| |
| const FieldDescriptor* FindFieldByName(const std::string& name) const { |
| PERFETTO_DCHECK(type_ == Type::kMessage); |
| auto it = std::find_if( |
| fields_.begin(), fields_.end(), |
| [name](const std::pair<const uint32_t, FieldDescriptor>& p) { |
| return p.second.name() == name; |
| }); |
| if (it == fields_.end()) { |
| return nullptr; |
| } |
| return &it->second; |
| } |
| |
| const FieldDescriptor* FindFieldByTag(const uint32_t tag_number) const { |
| PERFETTO_DCHECK(type_ == Type::kMessage); |
| auto it = fields_.find(tag_number); |
| if (it == fields_.end()) { |
| return nullptr; |
| } |
| return &it->second; |
| } |
| |
| std::optional<std::string> FindEnumString(const int32_t value) const { |
| PERFETTO_DCHECK(type_ == Type::kEnum); |
| auto it = enum_names_by_value_.find(value); |
| return it == enum_names_by_value_.end() ? std::nullopt |
| : std::make_optional(it->second); |
| } |
| |
| std::optional<int32_t> FindEnumValue(const std::string& value) const { |
| PERFETTO_DCHECK(type_ == Type::kEnum); |
| auto it = enum_values_by_name_.find(value); |
| return it == enum_values_by_name_.end() ? std::nullopt |
| : std::make_optional(it->second); |
| } |
| |
| const std::string& file_name() const { return file_name_; } |
| |
| const std::string& package_name() const { return package_name_; } |
| |
| const std::string& full_name() const { return full_name_; } |
| |
| Type type() const { return type_; } |
| |
| const std::unordered_map<uint32_t, FieldDescriptor>& fields() const { |
| return fields_; |
| } |
| std::unordered_map<uint32_t, FieldDescriptor>* mutable_fields() { |
| return &fields_; |
| } |
| |
| private: |
| std::string file_name_; // File in which descriptor was originally defined. |
| std::string package_name_; |
| std::string full_name_; |
| const Type type_; |
| std::optional<uint32_t> parent_id_; |
| std::unordered_map<uint32_t, FieldDescriptor> fields_; |
| std::unordered_map<int32_t, std::string> enum_names_by_value_; |
| std::unordered_map<std::string, int32_t> enum_values_by_name_; |
| }; |
| |
| using ExtensionInfo = std::pair<std::string, protozero::ConstBytes>; |
| |
| class DescriptorPool { |
| public: |
| // Adds Descriptors from file_descriptor_set_proto. Ignores any FileDescriptor |
| // with name matching a prefix in |skip_prefixes|. |
| base::Status AddFromFileDescriptorSet( |
| const uint8_t* file_descriptor_set_proto, |
| size_t size, |
| const std::vector<std::string>& skip_prefixes = {}, |
| bool merge_existing_messages = false); |
| |
| std::optional<uint32_t> FindDescriptorIdx(const std::string& full_name) const; |
| |
| std::vector<uint8_t> SerializeAsDescriptorSet(); |
| |
| void AddProtoDescriptorForTesting(ProtoDescriptor descriptor) { |
| AddProtoDescriptor(std::move(descriptor)); |
| } |
| |
| const std::vector<ProtoDescriptor>& descriptors() const { |
| return descriptors_; |
| } |
| |
| private: |
| base::Status AddNestedProtoDescriptors(const std::string& file_name, |
| const std::string& package_name, |
| std::optional<uint32_t> parent_idx, |
| protozero::ConstBytes descriptor_proto, |
| std::vector<ExtensionInfo>* extensions, |
| bool merge_existing_messages); |
| base::Status AddEnumProtoDescriptors(const std::string& file_name, |
| const std::string& package_name, |
| std::optional<uint32_t> parent_idx, |
| protozero::ConstBytes descriptor_proto, |
| bool merge_existing_messages); |
| |
| base::Status AddExtensionField(const std::string& package_name, |
| protozero::ConstBytes field_desc_proto); |
| |
| // Recursively searches for the given short type in all parent messages |
| // and packages. |
| std::optional<uint32_t> ResolveShortType(const std::string& parent_path, |
| const std::string& short_type); |
| |
| base::Status ResolveUninterpretedOption(const ProtoDescriptor&, |
| const FieldDescriptor&, |
| std::vector<uint8_t>&); |
| |
| // Adds a new descriptor to the pool and returns its index. There must not be |
| // already a descriptor with the same full_name in the pool. |
| uint32_t AddProtoDescriptor(ProtoDescriptor descriptor); |
| |
| std::vector<ProtoDescriptor> descriptors_; |
| // full_name -> index in the descriptors_ vector. |
| std::unordered_map<std::string, uint32_t> full_name_to_descriptor_index_; |
| std::set<std::string> processed_files_; |
| }; |
| |
| } // namespace trace_processor |
| } // namespace perfetto |
| |
| #endif // SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ |