xref: /aosp_15_r20/external/perfetto/src/trace_processor/util/descriptors.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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