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