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