• 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 <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