1 /* 2 * Copyright (C) 2019 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 17 #ifndef SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ 18 #define SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ 19 20 #include <algorithm> 21 #include <cstdint> 22 #include <optional> 23 #include <set> 24 #include <string> 25 #include <unordered_map> 26 #include <vector> 27 28 #include "perfetto/base/status.h" 29 #include "protos/perfetto/common/descriptor.pbzero.h" 30 31 namespace protozero { 32 struct ConstBytes; 33 } 34 35 namespace perfetto { 36 namespace trace_processor { 37 38 class FieldDescriptor { 39 public: 40 FieldDescriptor(std::string name, 41 uint32_t number, 42 uint32_t type, 43 std::string raw_type_name, 44 std::vector<uint8_t> options, 45 std::optional<std::string> default_value, 46 bool is_repeated, 47 bool is_packed, 48 bool is_extension = false); 49 name()50 const std::string& name() const { return name_; } number()51 uint32_t number() const { return number_; } type()52 uint32_t type() const { return type_; } raw_type_name()53 const std::string& raw_type_name() const { return raw_type_name_; } resolved_type_name()54 const std::string& resolved_type_name() const { return resolved_type_name_; } is_repeated()55 bool is_repeated() const { return is_repeated_; } is_packed()56 bool is_packed() const { return is_packed_; } is_extension()57 bool is_extension() const { return is_extension_; } 58 options()59 const std::vector<uint8_t>& options() const { return options_; } mutable_options()60 std::vector<uint8_t>* mutable_options() { return &options_; } default_value()61 const std::optional<std::string>& default_value() const { 62 return default_value_; 63 } 64 set_resolved_type_name(const std::string & resolved_type_name)65 void set_resolved_type_name(const std::string& resolved_type_name) { 66 resolved_type_name_ = resolved_type_name; 67 } 68 69 private: 70 std::string name_; 71 uint32_t number_; 72 uint32_t type_; 73 std::string raw_type_name_; 74 std::string resolved_type_name_; 75 std::vector<uint8_t> options_; 76 std::optional<std::string> default_value_; 77 bool is_repeated_; 78 bool is_packed_; 79 bool is_extension_; 80 }; 81 82 class ProtoDescriptor { 83 public: 84 enum class Type { kEnum = 0, kMessage = 1 }; 85 86 ProtoDescriptor(std::string file_name, 87 std::string package_name, 88 std::string full_name, 89 Type type, 90 std::optional<uint32_t> parent_id); 91 AddField(FieldDescriptor descriptor)92 void AddField(FieldDescriptor descriptor) { 93 PERFETTO_DCHECK(type_ == Type::kMessage); 94 fields_.emplace(descriptor.number(), std::move(descriptor)); 95 } 96 AddEnumValue(int32_t integer_representation,std::string string_representation)97 void AddEnumValue(int32_t integer_representation, 98 std::string string_representation) { 99 PERFETTO_DCHECK(type_ == Type::kEnum); 100 enum_values_by_name_[string_representation] = integer_representation; 101 enum_names_by_value_[integer_representation] = 102 std::move(string_representation); 103 } 104 FindFieldByName(const std::string & name)105 const FieldDescriptor* FindFieldByName(const std::string& name) const { 106 PERFETTO_DCHECK(type_ == Type::kMessage); 107 auto it = std::find_if( 108 fields_.begin(), fields_.end(), 109 [name](const std::pair<const uint32_t, FieldDescriptor>& p) { 110 return p.second.name() == name; 111 }); 112 if (it == fields_.end()) { 113 return nullptr; 114 } 115 return &it->second; 116 } 117 FindFieldByTag(const uint32_t tag_number)118 const FieldDescriptor* FindFieldByTag(const uint32_t tag_number) const { 119 PERFETTO_DCHECK(type_ == Type::kMessage); 120 auto it = fields_.find(tag_number); 121 if (it == fields_.end()) { 122 return nullptr; 123 } 124 return &it->second; 125 } 126 FindEnumString(const int32_t value)127 std::optional<std::string> FindEnumString(const int32_t value) const { 128 PERFETTO_DCHECK(type_ == Type::kEnum); 129 auto it = enum_names_by_value_.find(value); 130 return it == enum_names_by_value_.end() ? std::nullopt 131 : std::make_optional(it->second); 132 } 133 FindEnumValue(const std::string & value)134 std::optional<int32_t> FindEnumValue(const std::string& value) const { 135 PERFETTO_DCHECK(type_ == Type::kEnum); 136 auto it = enum_values_by_name_.find(value); 137 return it == enum_values_by_name_.end() ? std::nullopt 138 : std::make_optional(it->second); 139 } 140 file_name()141 const std::string& file_name() const { return file_name_; } 142 package_name()143 const std::string& package_name() const { return package_name_; } 144 full_name()145 const std::string& full_name() const { return full_name_; } 146 type()147 Type type() const { return type_; } 148 fields()149 const std::unordered_map<uint32_t, FieldDescriptor>& fields() const { 150 return fields_; 151 } mutable_fields()152 std::unordered_map<uint32_t, FieldDescriptor>* mutable_fields() { 153 return &fields_; 154 } 155 156 private: 157 std::string file_name_; // File in which descriptor was originally defined. 158 std::string package_name_; 159 std::string full_name_; 160 const Type type_; 161 std::optional<uint32_t> parent_id_; 162 std::unordered_map<uint32_t, FieldDescriptor> fields_; 163 std::unordered_map<int32_t, std::string> enum_names_by_value_; 164 std::unordered_map<std::string, int32_t> enum_values_by_name_; 165 }; 166 167 using ExtensionInfo = std::pair<std::string, protozero::ConstBytes>; 168 169 class DescriptorPool { 170 public: 171 // Adds Descriptors from file_descriptor_set_proto. Ignores any FileDescriptor 172 // with name matching a prefix in |skip_prefixes|. 173 base::Status AddFromFileDescriptorSet( 174 const uint8_t* file_descriptor_set_proto, 175 size_t size, 176 const std::vector<std::string>& skip_prefixes = {}, 177 bool merge_existing_messages = false); 178 179 std::optional<uint32_t> FindDescriptorIdx(const std::string& full_name) const; 180 181 std::vector<uint8_t> SerializeAsDescriptorSet(); 182 AddProtoDescriptorForTesting(ProtoDescriptor descriptor)183 void AddProtoDescriptorForTesting(ProtoDescriptor descriptor) { 184 AddProtoDescriptor(std::move(descriptor)); 185 } 186 descriptors()187 const std::vector<ProtoDescriptor>& descriptors() const { 188 return descriptors_; 189 } 190 191 private: 192 base::Status AddNestedProtoDescriptors(const std::string& file_name, 193 const std::string& package_name, 194 std::optional<uint32_t> parent_idx, 195 protozero::ConstBytes descriptor_proto, 196 std::vector<ExtensionInfo>* extensions, 197 bool merge_existing_messages); 198 base::Status AddEnumProtoDescriptors(const std::string& file_name, 199 const std::string& package_name, 200 std::optional<uint32_t> parent_idx, 201 protozero::ConstBytes descriptor_proto, 202 bool merge_existing_messages); 203 204 base::Status AddExtensionField(const std::string& package_name, 205 protozero::ConstBytes field_desc_proto); 206 207 // Recursively searches for the given short type in all parent messages 208 // and packages. 209 std::optional<uint32_t> ResolveShortType(const std::string& parent_path, 210 const std::string& short_type); 211 212 base::Status ResolveUninterpretedOption(const ProtoDescriptor&, 213 const FieldDescriptor&, 214 std::vector<uint8_t>&); 215 216 // Adds a new descriptor to the pool and returns its index. There must not be 217 // already a descriptor with the same full_name in the pool. 218 uint32_t AddProtoDescriptor(ProtoDescriptor descriptor); 219 220 std::vector<ProtoDescriptor> descriptors_; 221 // full_name -> index in the descriptors_ vector. 222 std::unordered_map<std::string, uint32_t> full_name_to_descriptor_index_; 223 std::set<std::string> processed_files_; 224 }; 225 226 } // namespace trace_processor 227 } // namespace perfetto 228 229 #endif // SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ 230