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_[integer_representation] = std::move(string_representation); 91 } 92 FindFieldByName(const std::string & name)93 const FieldDescriptor* FindFieldByName(const std::string& name) const { 94 PERFETTO_DCHECK(type_ == Type::kMessage); 95 auto it = 96 std::find_if(fields_.begin(), fields_.end(), 97 [name](std::pair<int32_t, const FieldDescriptor&> p) { 98 return p.second.name() == name; 99 }); 100 if (it == fields_.end()) { 101 return nullptr; 102 } 103 return &it->second; 104 } 105 FindFieldByTag(const uint32_t tag_number)106 const FieldDescriptor* FindFieldByTag(const uint32_t tag_number) const { 107 PERFETTO_DCHECK(type_ == Type::kMessage); 108 auto it = fields_.find(tag_number); 109 if (it == fields_.end()) { 110 return nullptr; 111 } 112 return &it->second; 113 } 114 FindEnumString(const int32_t value)115 base::Optional<std::string> FindEnumString(const int32_t value) const { 116 PERFETTO_DCHECK(type_ == Type::kEnum); 117 auto it = enum_values_.find(value); 118 return it == enum_values_.end() ? base::nullopt 119 : base::Optional<std::string>(it->second); 120 } 121 file_name()122 const std::string& file_name() const { return file_name_; } 123 package_name()124 const std::string& package_name() const { return package_name_; } 125 full_name()126 const std::string& full_name() const { return full_name_; } 127 type()128 Type type() const { return type_; } 129 fields()130 const std::unordered_map<uint32_t, FieldDescriptor>& fields() const { 131 return fields_; 132 } mutable_fields()133 std::unordered_map<uint32_t, FieldDescriptor>* mutable_fields() { 134 return &fields_; 135 } 136 137 private: 138 std::string file_name_; // File in which descriptor was originally defined. 139 std::string package_name_; 140 std::string full_name_; 141 const Type type_; 142 base::Optional<uint32_t> parent_id_; 143 std::unordered_map<uint32_t, FieldDescriptor> fields_; 144 std::unordered_map<int32_t, std::string> enum_values_; 145 }; 146 147 using ExtensionInfo = std::pair<std::string, protozero::ConstBytes>; 148 149 class DescriptorPool { 150 public: 151 base::Status AddFromFileDescriptorSet( 152 const uint8_t* file_descriptor_set_proto, 153 size_t size, 154 bool merge_existing_messages = false); 155 156 base::Optional<uint32_t> FindDescriptorIdx( 157 const std::string& full_name) const; 158 descriptors()159 const std::vector<ProtoDescriptor>& descriptors() const { 160 return descriptors_; 161 } 162 163 std::vector<uint8_t> SerializeAsDescriptorSet(); 164 165 private: 166 base::Status AddNestedProtoDescriptors(const std::string& file_name, 167 const std::string& package_name, 168 base::Optional<uint32_t> parent_idx, 169 protozero::ConstBytes descriptor_proto, 170 std::vector<ExtensionInfo>* extensions, 171 bool merge_existing_messages); 172 base::Status AddEnumProtoDescriptors(const std::string& file_name, 173 const std::string& package_name, 174 base::Optional<uint32_t> parent_idx, 175 protozero::ConstBytes descriptor_proto, 176 bool merge_existing_messages); 177 178 base::Status AddExtensionField(const std::string& package_name, 179 protozero::ConstBytes field_desc_proto); 180 181 // Recursively searches for the given short type in all parent messages 182 // and packages. 183 base::Optional<uint32_t> ResolveShortType(const std::string& parent_path, 184 const std::string& short_type); 185 186 std::vector<ProtoDescriptor> descriptors_; 187 std::set<std::string> processed_files_; 188 }; 189 190 } // namespace trace_processor 191 } // namespace perfetto 192 193 #endif // SRC_TRACE_PROCESSOR_UTIL_DESCRIPTORS_H_ 194