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