blob: 4c0ecd90ac874a5d68976abbad7ef8db6a8b0cb1 [file] [log] [blame]
Lalit Maganti62211072019-05-10 14:09:58 +01001/*
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
Lalit Maganti3d9bbff2020-04-15 13:40:58 +010017#include "src/trace_processor/util/descriptors.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010018#include "perfetto/ext/base/string_view.h"
Primiano Tucci8f7359c2019-10-17 12:59:33 +010019#include "perfetto/protozero/field.h"
Lalit Maganti62211072019-05-10 14:09:58 +010020
Primiano Tucci355b8c82019-08-29 08:37:51 +020021#include "protos/perfetto/common/descriptor.pbzero.h"
Lalit Maganti62211072019-05-10 14:09:58 +010022
23namespace perfetto {
24namespace trace_processor {
Lalit Maganti62211072019-05-10 14:09:58 +010025
Lalit Magantifaa525d2019-05-28 11:25:59 +010026FieldDescriptor CreateFieldFromDecoder(
27 const protos::pbzero::FieldDescriptorProto::Decoder& f_decoder) {
28 using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
29 std::string type_name =
30 f_decoder.has_type_name()
31 ? base::StringView(f_decoder.type_name()).ToStdString()
32 : "";
33 // TODO(lalitm): add support for enums here.
Primiano Tucci335412d2019-05-30 16:29:16 +010034 uint32_t type =
35 f_decoder.has_type()
36 ? static_cast<uint32_t>(f_decoder.type())
37 : static_cast<uint32_t>(FieldDescriptorProto::TYPE_MESSAGE);
Lalit Magantifaa525d2019-05-28 11:25:59 +010038 return FieldDescriptor(
39 base::StringView(f_decoder.name()).ToStdString(),
40 static_cast<uint32_t>(f_decoder.number()), type, std::move(type_name),
41 f_decoder.label() == FieldDescriptorProto::LABEL_REPEATED);
42}
43
Lalit Magantifaa525d2019-05-28 11:25:59 +010044base::Optional<uint32_t> DescriptorPool::ResolveShortType(
45 const std::string& parent_path,
46 const std::string& short_type) {
47 PERFETTO_DCHECK(!short_type.empty());
48
49 std::string search_path = short_type[0] == '.'
50 ? parent_path + short_type
51 : parent_path + '.' + short_type;
52 auto opt_idx = FindDescriptorIdx(search_path);
53 if (opt_idx)
54 return opt_idx;
55
56 if (parent_path.empty())
57 return base::nullopt;
58
59 auto parent_dot_idx = parent_path.rfind('.');
60 auto parent_substr = parent_dot_idx == std::string::npos
61 ? ""
62 : parent_path.substr(0, parent_dot_idx);
63 return ResolveShortType(parent_substr, short_type);
64}
65
Primiano Tucci8f7359c2019-10-17 12:59:33 +010066util::Status DescriptorPool::AddExtensionField(
67 const std::string& package_name,
68 protozero::ConstBytes field_desc_proto) {
Lalit Magantifaa525d2019-05-28 11:25:59 +010069 using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
Primiano Tucci8f7359c2019-10-17 12:59:33 +010070 FieldDescriptorProto::Decoder f_decoder(field_desc_proto);
Lalit Magantifaa525d2019-05-28 11:25:59 +010071 auto field = CreateFieldFromDecoder(f_decoder);
72
Ioannis Ilkoscea99d42020-05-31 12:03:53 +010073 auto extendee_name = base::StringView(f_decoder.extendee()).ToStdString();
74 PERFETTO_CHECK(!extendee_name.empty());
75 if (extendee_name[0] != '.') {
76 // Only prepend if the extendee is not fully qualified
77 extendee_name = package_name + "." + extendee_name;
78 }
Lalit Magantifaa525d2019-05-28 11:25:59 +010079 auto extendee = FindDescriptorIdx(extendee_name);
80 if (!extendee.has_value()) {
81 return util::ErrStatus("Extendee does not exist %s", extendee_name.c_str());
82 }
83 descriptors_[extendee.value()].AddField(field);
84 return util::OkStatus();
85}
86
Lalit Maganti62211072019-05-10 14:09:58 +010087void DescriptorPool::AddNestedProtoDescriptors(
88 const std::string& package_name,
89 base::Optional<uint32_t> parent_idx,
Primiano Tucci8f7359c2019-10-17 12:59:33 +010090 protozero::ConstBytes descriptor_proto) {
91 protos::pbzero::DescriptorProto::Decoder decoder(descriptor_proto);
Lalit Maganti62211072019-05-10 14:09:58 +010092
93 auto parent_name =
94 parent_idx ? descriptors_[*parent_idx].full_name() : package_name;
95 auto full_name =
96 parent_name + "." + base::StringView(decoder.name()).ToStdString();
97
98 using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
Stephen Nuskobc76a6c2019-12-03 11:55:27 +000099 ProtoDescriptor proto_descriptor(package_name, full_name,
100 ProtoDescriptor::Type::kMessage, parent_idx);
Lalit Maganti62211072019-05-10 14:09:58 +0100101 for (auto it = decoder.field(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100102 FieldDescriptorProto::Decoder f_decoder(*it);
Lalit Magantifaa525d2019-05-28 11:25:59 +0100103 proto_descriptor.AddField(CreateFieldFromDecoder(f_decoder));
Lalit Maganti62211072019-05-10 14:09:58 +0100104 }
105 descriptors_.emplace_back(std::move(proto_descriptor));
106
107 auto idx = static_cast<uint32_t>(descriptors_.size()) - 1;
Stephen Nuskobc76a6c2019-12-03 11:55:27 +0000108 for (auto it = decoder.enum_type(); it; ++it) {
109 AddEnumProtoDescriptors(package_name, idx, *it);
110 }
Lalit Maganti62211072019-05-10 14:09:58 +0100111 for (auto it = decoder.nested_type(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100112 AddNestedProtoDescriptors(package_name, idx, *it);
Lalit Maganti62211072019-05-10 14:09:58 +0100113 }
114}
115
Stephen Nuskobc76a6c2019-12-03 11:55:27 +0000116void DescriptorPool::AddEnumProtoDescriptors(
117 const std::string& package_name,
118 base::Optional<uint32_t> parent_idx,
119 protozero::ConstBytes descriptor_proto) {
120 protos::pbzero::EnumDescriptorProto::Decoder decoder(descriptor_proto);
121
122 auto parent_name =
123 parent_idx ? descriptors_[*parent_idx].full_name() : package_name;
124 auto full_name =
125 parent_name + "." + base::StringView(decoder.name()).ToStdString();
126
127 ProtoDescriptor proto_descriptor(package_name, full_name,
128 ProtoDescriptor::Type::kEnum, base::nullopt);
129 for (auto it = decoder.value(); it; ++it) {
130 protos::pbzero::EnumValueDescriptorProto::Decoder enum_value(it->data(),
131 it->size());
132 proto_descriptor.AddEnumValue(enum_value.number(),
133 enum_value.name().ToStdString());
134 }
135 descriptors_.emplace_back(std::move(proto_descriptor));
136}
137
Lalit Magantifaa525d2019-05-28 11:25:59 +0100138util::Status DescriptorPool::AddFromFileDescriptorSet(
Lalit Maganti62211072019-05-10 14:09:58 +0100139 const uint8_t* file_descriptor_set_proto,
140 size_t size) {
141 // First pass: extract all the message descriptors from the file and add them
142 // to the pool.
143 protos::pbzero::FileDescriptorSet::Decoder proto(file_descriptor_set_proto,
144 size);
145 for (auto it = proto.file(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100146 protos::pbzero::FileDescriptorProto::Decoder file(*it);
Lalit Maganti62211072019-05-10 14:09:58 +0100147 std::string package = "." + base::StringView(file.package()).ToStdString();
148 for (auto message_it = file.message_type(); message_it; ++message_it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100149 AddNestedProtoDescriptors(package, base::nullopt, *message_it);
Lalit Maganti62211072019-05-10 14:09:58 +0100150 }
Stephen Nuskobc76a6c2019-12-03 11:55:27 +0000151 for (auto enum_it = file.enum_type(); enum_it; ++enum_it) {
152 AddEnumProtoDescriptors(package, base::nullopt, *enum_it);
153 }
Lalit Maganti62211072019-05-10 14:09:58 +0100154 }
155
Lalit Magantifaa525d2019-05-28 11:25:59 +0100156 // Second pass: extract all the extension protos and add them to the real
157 // protos.
158 for (auto it = proto.file(); it; ++it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100159 protos::pbzero::FileDescriptorProto::Decoder file(*it);
Lalit Magantifaa525d2019-05-28 11:25:59 +0100160
161 std::string package = "." + base::StringView(file.package()).ToStdString();
162 for (auto ext_it = file.extension(); ext_it; ++ext_it) {
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100163 auto status = AddExtensionField(package, *ext_it);
Lalit Magantifaa525d2019-05-28 11:25:59 +0100164 if (!status.ok())
165 return status;
166 }
167
168 // TODO(lalitm): we don't currently support nested extensions as they are
169 // relatively niche and probably shouldn't be used in metrics because they
170 // are confusing. Add the code for it here if we find a use for them in
171 // the future.
172 }
173
174 // Third pass: resolve the types of all the fields to the correct indiices.
Lalit Maganti62211072019-05-10 14:09:58 +0100175 using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
176 for (auto& descriptor : descriptors_) {
177 for (auto& field : *descriptor.mutable_fields()) {
Lalit Magantica4d5142019-05-28 13:25:47 +0100178 if (!field.resolved_type_name().empty())
179 continue;
180
Lalit Maganti62211072019-05-10 14:09:58 +0100181 if (field.type() == FieldDescriptorProto::TYPE_MESSAGE ||
182 field.type() == FieldDescriptorProto::TYPE_ENUM) {
Lalit Magantifaa525d2019-05-28 11:25:59 +0100183 auto opt_desc =
184 ResolveShortType(descriptor.full_name(), field.raw_type_name());
185 if (!opt_desc.has_value()) {
186 return util::ErrStatus(
187 "Unable to find short type %s in field inside message %s",
188 field.raw_type_name().c_str(), descriptor.full_name().c_str());
189 }
190 field.set_resolved_type_name(
191 descriptors_[opt_desc.value()].full_name());
Lalit Maganti62211072019-05-10 14:09:58 +0100192 }
193 }
194 }
Lalit Magantifaa525d2019-05-28 11:25:59 +0100195 return util::OkStatus();
Lalit Maganti62211072019-05-10 14:09:58 +0100196}
197
198base::Optional<uint32_t> DescriptorPool::FindDescriptorIdx(
199 const std::string& full_name) const {
200 auto it = std::find_if(descriptors_.begin(), descriptors_.end(),
201 [full_name](const ProtoDescriptor& desc) {
202 return desc.full_name() == full_name;
203 });
204 auto idx = static_cast<uint32_t>(std::distance(descriptors_.begin(), it));
205 return idx < descriptors_.size() ? base::Optional<uint32_t>(idx)
206 : base::nullopt;
207}
208
209ProtoDescriptor::ProtoDescriptor(std::string package_name,
210 std::string full_name,
Stephen Nuskobc76a6c2019-12-03 11:55:27 +0000211 Type type,
Lalit Maganti62211072019-05-10 14:09:58 +0100212 base::Optional<uint32_t> parent_id)
213 : package_name_(std::move(package_name)),
214 full_name_(std::move(full_name)),
Stephen Nuskobc76a6c2019-12-03 11:55:27 +0000215 type_(type),
Lalit Maganti62211072019-05-10 14:09:58 +0100216 parent_id_(parent_id) {}
217
218FieldDescriptor::FieldDescriptor(std::string name,
219 uint32_t number,
220 uint32_t type,
Lalit Magantib182d7e2019-05-10 14:13:06 +0100221 std::string raw_type_name,
222 bool is_repeated)
Lalit Maganti62211072019-05-10 14:09:58 +0100223 : name_(std::move(name)),
224 number_(number),
225 type_(type),
Lalit Magantib182d7e2019-05-10 14:13:06 +0100226 raw_type_name_(std::move(raw_type_name)),
227 is_repeated_(is_repeated) {}
Lalit Maganti62211072019-05-10 14:09:58 +0100228
Lalit Maganti62211072019-05-10 14:09:58 +0100229} // namespace trace_processor
230} // namespace perfetto