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