Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 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 | |
Lalit Maganti | 3d9bbff | 2020-04-15 13:40:58 +0100 | [diff] [blame] | 17 | #include "src/trace_processor/util/descriptors.h" |
Primiano Tucci | 2c5488f | 2019-06-01 03:27:28 +0100 | [diff] [blame] | 18 | #include "perfetto/ext/base/string_view.h" |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 19 | #include "perfetto/protozero/field.h" |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 20 | |
Primiano Tucci | 355b8c8 | 2019-08-29 08:37:51 +0200 | [diff] [blame] | 21 | #include "protos/perfetto/common/descriptor.pbzero.h" |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 22 | |
| 23 | namespace perfetto { |
| 24 | namespace trace_processor { |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 25 | |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 26 | FieldDescriptor 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 Tucci | 335412d | 2019-05-30 16:29:16 +0100 | [diff] [blame] | 34 | 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 Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 38 | 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 Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 44 | base::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 Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 66 | util::Status DescriptorPool::AddExtensionField( |
| 67 | const std::string& package_name, |
| 68 | protozero::ConstBytes field_desc_proto) { |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 69 | using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 70 | FieldDescriptorProto::Decoder f_decoder(field_desc_proto); |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 71 | auto field = CreateFieldFromDecoder(f_decoder); |
| 72 | |
Ioannis Ilkos | cea99d4 | 2020-05-31 12:03:53 +0100 | [diff] [blame] | 73 | 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 Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 79 | 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 Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 87 | void DescriptorPool::AddNestedProtoDescriptors( |
| 88 | const std::string& package_name, |
| 89 | base::Optional<uint32_t> parent_idx, |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 90 | protozero::ConstBytes descriptor_proto) { |
| 91 | protos::pbzero::DescriptorProto::Decoder decoder(descriptor_proto); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 92 | |
| 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 Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 99 | ProtoDescriptor proto_descriptor(package_name, full_name, |
| 100 | ProtoDescriptor::Type::kMessage, parent_idx); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 101 | for (auto it = decoder.field(); it; ++it) { |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 102 | FieldDescriptorProto::Decoder f_decoder(*it); |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 103 | proto_descriptor.AddField(CreateFieldFromDecoder(f_decoder)); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 104 | } |
| 105 | descriptors_.emplace_back(std::move(proto_descriptor)); |
| 106 | |
| 107 | auto idx = static_cast<uint32_t>(descriptors_.size()) - 1; |
Stephen Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 108 | for (auto it = decoder.enum_type(); it; ++it) { |
| 109 | AddEnumProtoDescriptors(package_name, idx, *it); |
| 110 | } |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 111 | for (auto it = decoder.nested_type(); it; ++it) { |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 112 | AddNestedProtoDescriptors(package_name, idx, *it); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
Stephen Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 116 | void 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 Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 138 | util::Status DescriptorPool::AddFromFileDescriptorSet( |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 139 | 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 Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 146 | protos::pbzero::FileDescriptorProto::Decoder file(*it); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 147 | std::string package = "." + base::StringView(file.package()).ToStdString(); |
| 148 | for (auto message_it = file.message_type(); message_it; ++message_it) { |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 149 | AddNestedProtoDescriptors(package, base::nullopt, *message_it); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 150 | } |
Stephen Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 151 | for (auto enum_it = file.enum_type(); enum_it; ++enum_it) { |
| 152 | AddEnumProtoDescriptors(package, base::nullopt, *enum_it); |
| 153 | } |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 154 | } |
| 155 | |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 156 | // Second pass: extract all the extension protos and add them to the real |
| 157 | // protos. |
| 158 | for (auto it = proto.file(); it; ++it) { |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 159 | protos::pbzero::FileDescriptorProto::Decoder file(*it); |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 160 | |
| 161 | std::string package = "." + base::StringView(file.package()).ToStdString(); |
| 162 | for (auto ext_it = file.extension(); ext_it; ++ext_it) { |
Primiano Tucci | 8f7359c | 2019-10-17 12:59:33 +0100 | [diff] [blame] | 163 | auto status = AddExtensionField(package, *ext_it); |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 164 | 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 Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 175 | using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto; |
| 176 | for (auto& descriptor : descriptors_) { |
| 177 | for (auto& field : *descriptor.mutable_fields()) { |
Lalit Maganti | ca4d514 | 2019-05-28 13:25:47 +0100 | [diff] [blame] | 178 | if (!field.resolved_type_name().empty()) |
| 179 | continue; |
| 180 | |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 181 | if (field.type() == FieldDescriptorProto::TYPE_MESSAGE || |
| 182 | field.type() == FieldDescriptorProto::TYPE_ENUM) { |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 183 | 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 Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 192 | } |
| 193 | } |
| 194 | } |
Lalit Maganti | faa525d | 2019-05-28 11:25:59 +0100 | [diff] [blame] | 195 | return util::OkStatus(); |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | base::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 | |
| 209 | ProtoDescriptor::ProtoDescriptor(std::string package_name, |
| 210 | std::string full_name, |
Stephen Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 211 | Type type, |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 212 | base::Optional<uint32_t> parent_id) |
| 213 | : package_name_(std::move(package_name)), |
| 214 | full_name_(std::move(full_name)), |
Stephen Nusko | bc76a6c | 2019-12-03 11:55:27 +0000 | [diff] [blame] | 215 | type_(type), |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 216 | parent_id_(parent_id) {} |
| 217 | |
| 218 | FieldDescriptor::FieldDescriptor(std::string name, |
| 219 | uint32_t number, |
| 220 | uint32_t type, |
Lalit Maganti | b182d7e | 2019-05-10 14:13:06 +0100 | [diff] [blame] | 221 | std::string raw_type_name, |
| 222 | bool is_repeated) |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 223 | : name_(std::move(name)), |
| 224 | number_(number), |
| 225 | type_(type), |
Lalit Maganti | b182d7e | 2019-05-10 14:13:06 +0100 | [diff] [blame] | 226 | raw_type_name_(std::move(raw_type_name)), |
| 227 | is_repeated_(is_repeated) {} |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 228 | |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame] | 229 | } // namespace trace_processor |
| 230 | } // namespace perfetto |