xref: /aosp_15_r20/external/perfetto/src/trace_processor/util/protozero_to_json.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 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 #include "src/trace_processor/util/protozero_to_json.h"
18 
19 #include <optional>
20 #include <unordered_set>
21 #include <utility>
22 #include <vector>
23 
24 #include "perfetto/ext/base/string_utils.h"
25 #include "perfetto/ext/base/string_view.h"
26 #include "perfetto/protozero/field.h"
27 #include "perfetto/protozero/proto_decoder.h"
28 #include "perfetto/protozero/proto_utils.h"
29 #include "protos/perfetto/common/descriptor.pbzero.h"
30 #include "src/trace_processor/util/descriptors.h"
31 
32 namespace perfetto {
33 namespace trace_processor {
34 namespace protozero_to_json {
35 
36 namespace {
37 
38 using protos::pbzero::FieldDescriptorProto;
39 using protozero::PackedRepeatedFieldIterator;
40 using protozero::proto_utils::ProtoWireType;
41 
42 class JsonBuilder {
43  public:
JsonBuilder(int flags)44   explicit JsonBuilder(int flags) : flags_(flags) {}
45 
OpenObject()46   void OpenObject() {
47     if (is_array_scope()) {
48       if (!is_empty_scope()) {
49         Append(",");
50       }
51       MaybeAppendNewline();
52       MaybeAppendIndent();
53     }
54     Append("{");
55     stack_.push_back(Scope{ScopeContext::kObject});
56   }
57 
CloseObject()58   void CloseObject() {
59     bool needs_newline = !is_empty_scope();
60     stack_.pop_back();
61     if (needs_newline) {
62       MaybeAppendNewline();
63       MaybeAppendIndent();
64     }
65 
66     MarkScopeAsNonEmpty();
67     Append("}");
68   }
69 
OpenArray()70   void OpenArray() {
71     Append("[");
72     stack_.push_back(Scope{ScopeContext::kArray});
73   }
74 
CloseArray()75   void CloseArray() {
76     bool needs_newline = !is_empty_scope();
77     stack_.pop_back();
78     if (needs_newline) {
79       MaybeAppendNewline();
80       MaybeAppendIndent();
81     }
82     Append("]");
83     if (is_array_scope() && !is_empty_scope()) {
84       Append(",");
85     }
86   }
87 
Key(const std::string & key)88   void Key(const std::string& key) {
89     if (is_object_scope() && !is_empty_scope()) {
90       Append(",");
91     }
92     MaybeAppendNewline();
93     MaybeAppendIndent();
94     Append(EscapeString(base::StringView(key)));
95     Append(":");
96     MaybeAppendSpace();
97     MarkScopeAsNonEmpty();
98   }
99 
100   template <typename T>
NumberValue(T v)101   void NumberValue(T v) {
102     AppendValue(std::to_string(v));
103   }
104 
BoolValue(bool v)105   void BoolValue(bool v) { AppendValue(v ? "true" : "false"); }
106 
FloatValue(float v)107   void FloatValue(float v) { NumberValue(v); }
108 
DoubleValue(double v)109   void DoubleValue(double v) { NumberValue(v); }
110 
StringValue(base::StringView v)111   void StringValue(base::StringView v) { AppendValue(EscapeString(v)); }
112 
AddError(const std::string & s)113   void AddError(const std::string& s) { errors_.push_back(s); }
114 
ToString()115   std::string ToString() { return base::Join(parts_, ""); }
116 
is_empty_scope()117   bool is_empty_scope() { return !stack_.empty() && stack_.back().is_empty; }
118 
is_pretty() const119   bool is_pretty() const { return flags_ & Flags::kPretty; }
120 
is_inline_errors() const121   bool is_inline_errors() const { return flags_ & Flags::kInlineErrors; }
122 
errors() const123   const std::vector<std::string>& errors() const { return errors_; }
124 
125  private:
126   enum class ScopeContext {
127     kObject,
128     kArray,
129   };
130 
131   struct Scope {
132     ScopeContext ctx;
133     bool is_empty = true;
134   };
135 
136   int flags_;
137   std::vector<std::string> parts_;
138   std::vector<Scope> stack_;
139   std::vector<std::string> errors_;
140 
is_object_scope()141   bool is_object_scope() {
142     return !stack_.empty() && stack_.back().ctx == ScopeContext::kObject;
143   }
144 
is_array_scope()145   bool is_array_scope() {
146     return !stack_.empty() && stack_.back().ctx == ScopeContext::kArray;
147   }
148 
MarkScopeAsNonEmpty()149   void MarkScopeAsNonEmpty() {
150     if (!stack_.empty()) {
151       stack_.back().is_empty = false;
152     }
153   }
154 
MaybeAppendSpace()155   void MaybeAppendSpace() {
156     if (is_pretty()) {
157       Append(" ");
158     }
159   }
160 
MaybeAppendIndent()161   void MaybeAppendIndent() {
162     if (is_pretty()) {
163       Append(std::string(stack_.size() * 2, ' '));
164     }
165   }
166 
MaybeAppendNewline()167   void MaybeAppendNewline() {
168     if (is_pretty()) {
169       Append("\n");
170     }
171   }
172 
AppendValue(const std::string & s)173   void AppendValue(const std::string& s) {
174     if (is_array_scope() && !is_empty_scope()) {
175       Append(",");
176     }
177     if (is_array_scope()) {
178       MaybeAppendNewline();
179       MaybeAppendIndent();
180     }
181     Append(s);
182     MarkScopeAsNonEmpty();
183   }
184 
Append(const std::string & s)185   void Append(const std::string& s) { parts_.push_back(s); }
186 
EscapeString(base::StringView raw)187   std::string EscapeString(base::StringView raw) {
188     std::string result;
189     result.reserve(raw.size() + 2);
190     result += "\"";
191     for (size_t i = 0; i < raw.size(); ++i) {
192       char c = *(raw.begin() + i);
193       switch (c) {
194         case '"':
195         case '\\':
196           result += '\\';
197           result += c;
198           break;
199         case '\n':
200           result += R"(\n)";
201           break;
202         case '\b':
203           result += R"(\b)";
204           break;
205         case '\f':
206           result += R"(\f)";
207           break;
208         case '\r':
209           result += R"(\r)";
210           break;
211         case '\t':
212           result += R"(\t)";
213           break;
214         default:
215           // ASCII characters between 0x20 (space) and 0x7e (tilde) are
216           // inserted directly. All others are escaped.
217           if (c >= 0x20 && c <= 0x7e) {
218             result += c;
219           } else {
220             unsigned char uc = static_cast<unsigned char>(c);
221             uint32_t codepoint = 0;
222 
223             // Compute the number of bytes:
224             size_t extra = 1 + (uc >= 0xc0u) + (uc >= 0xe0u) + (uc >= 0xf0u);
225 
226             // We want to consume |extra| bytes but also need to not
227             // read out of bounds:
228             size_t stop = std::min(raw.size(), i + extra);
229 
230             // Manually insert the bits from first byte:
231             codepoint |= uc & (0xff >> (extra + 1));
232 
233             // Insert remaining bits:
234             for (size_t j = i + 1; j < stop; ++j) {
235               uc = static_cast<unsigned char>(*(raw.begin() + j));
236               codepoint = (codepoint << 6) | (uc & 0x3f);
237             }
238 
239             // Update i to show the consumed chars:
240             i = stop - 1;
241 
242             static const char hex_chars[] = "0123456789abcdef";
243             // JSON does not have proper utf-8 escapes. Instead you
244             // have to use utf-16 codes. For the low codepoints
245             // \uXXXX and for the high codepoints a surrogate pair:
246             // \uXXXX\uYYYY
247             if (codepoint <= 0xffff) {
248               result += R"(\u)";
249               result += hex_chars[(codepoint >> 12) & 0xf];
250               result += hex_chars[(codepoint >> 8) & 0xf];
251               result += hex_chars[(codepoint >> 4) & 0xf];
252               result += hex_chars[(codepoint >> 0) & 0xf];
253             } else {
254               uint32_t high = ((codepoint - 0x10000) >> 10) + 0xD800;
255               uint32_t low = (codepoint & 0x4fff) + 0xDC00;
256               result += R"(\u)";
257               result += hex_chars[(high >> 12) & 0xf];
258               result += hex_chars[(high >> 8) & 0xf];
259               result += hex_chars[(high >> 4) & 0xf];
260               result += hex_chars[(high >> 0) & 0xf];
261               result += R"(\u)";
262               result += hex_chars[(low >> 12) & 0xf];
263               result += hex_chars[(low >> 8) & 0xf];
264               result += hex_chars[(low >> 4) & 0xf];
265               result += hex_chars[(low >> 0) & 0xf];
266             }
267           }
268           break;
269       }
270     }
271     result += "\"";
272     return result;
273   }
274 };
275 
HasFieldOptions(const FieldDescriptor & field_desc)276 bool HasFieldOptions(const FieldDescriptor& field_desc) {
277   return !field_desc.options().empty();
278 }
279 
FulllyQualifiedFieldName(const ProtoDescriptor & desc,const FieldDescriptor & field_desc)280 std::string FulllyQualifiedFieldName(const ProtoDescriptor& desc,
281                                      const FieldDescriptor& field_desc) {
282   return desc.package_name().substr(1) + "." + field_desc.name();
283 }
284 
IsTypeMatch(ProtoWireType wire,uint32_t type)285 bool IsTypeMatch(ProtoWireType wire, uint32_t type) {
286   switch (wire) {
287     case ProtoWireType::kVarInt:
288       switch (type) {
289         case FieldDescriptorProto::TYPE_INT32:
290         case FieldDescriptorProto::TYPE_SINT32:
291         case FieldDescriptorProto::TYPE_UINT32:
292         case FieldDescriptorProto::TYPE_INT64:
293         case FieldDescriptorProto::TYPE_SINT64:
294         case FieldDescriptorProto::TYPE_UINT64:
295         case FieldDescriptorProto::TYPE_BOOL:
296         case FieldDescriptorProto::TYPE_ENUM:
297           return true;
298         default:
299           return false;
300       }
301     case ProtoWireType::kLengthDelimited:
302       switch (type) {
303         case FieldDescriptorProto::TYPE_BYTES:
304         case FieldDescriptorProto::TYPE_MESSAGE:
305         case FieldDescriptorProto::TYPE_STRING:
306           // The normal case.
307           return true;
308         case FieldDescriptorProto::TYPE_INT32:
309         case FieldDescriptorProto::TYPE_SINT32:
310         case FieldDescriptorProto::TYPE_UINT32:
311         case FieldDescriptorProto::TYPE_INT64:
312         case FieldDescriptorProto::TYPE_SINT64:
313         case FieldDescriptorProto::TYPE_UINT64:
314         case FieldDescriptorProto::TYPE_BOOL:
315         case FieldDescriptorProto::TYPE_ENUM:
316         case FieldDescriptorProto::TYPE_FIXED32:
317         case FieldDescriptorProto::TYPE_SFIXED32:
318         case FieldDescriptorProto::TYPE_FLOAT:
319         case FieldDescriptorProto::TYPE_FIXED64:
320         case FieldDescriptorProto::TYPE_SFIXED64:
321         case FieldDescriptorProto::TYPE_DOUBLE:
322           // Packed repeated fields.
323           return true;
324         default:
325           return false;
326       }
327     case ProtoWireType::kFixed32:
328       switch (type) {
329         case FieldDescriptorProto::TYPE_FIXED32:
330         case FieldDescriptorProto::TYPE_SFIXED32:
331         case FieldDescriptorProto::TYPE_FLOAT:
332           return true;
333         default:
334           return false;
335       }
336     case ProtoWireType::kFixed64:
337       switch (type) {
338         case FieldDescriptorProto::TYPE_FIXED64:
339         case FieldDescriptorProto::TYPE_SFIXED64:
340         case FieldDescriptorProto::TYPE_DOUBLE:
341           return true;
342         default:
343           return false;
344       }
345   }
346   PERFETTO_FATAL("For GCC");
347 }
348 
IsNumericFieldType(uint32_t type)349 bool IsNumericFieldType(uint32_t type) {
350   switch (type) {
351     case FieldDescriptorProto::TYPE_BYTES:
352     case FieldDescriptorProto::TYPE_MESSAGE:
353     case FieldDescriptorProto::TYPE_STRING:
354       return false;
355     case FieldDescriptorProto::TYPE_INT32:
356     case FieldDescriptorProto::TYPE_SINT32:
357     case FieldDescriptorProto::TYPE_UINT32:
358     case FieldDescriptorProto::TYPE_INT64:
359     case FieldDescriptorProto::TYPE_SINT64:
360     case FieldDescriptorProto::TYPE_UINT64:
361     case FieldDescriptorProto::TYPE_BOOL:
362     case FieldDescriptorProto::TYPE_ENUM:
363     case FieldDescriptorProto::TYPE_FIXED32:
364     case FieldDescriptorProto::TYPE_SFIXED32:
365     case FieldDescriptorProto::TYPE_FLOAT:
366     case FieldDescriptorProto::TYPE_FIXED64:
367     case FieldDescriptorProto::TYPE_SFIXED64:
368     case FieldDescriptorProto::TYPE_DOUBLE:
369     default:
370       return true;
371   }
372 }
373 
374 void MessageField(const DescriptorPool& pool,
375                   const std::string& type,
376                   protozero::ConstBytes protobytes,
377                   bool fully_qualify_extensions,
378                   JsonBuilder* out);
379 void EnumField(const DescriptorPool& pool,
380                const FieldDescriptor& fd,
381                int32_t value,
382                JsonBuilder* out);
383 
384 template <ProtoWireType W, typename T>
PackedField(const DescriptorPool & pool,const FieldDescriptor & fd,const protozero::Field & field,JsonBuilder * out)385 void PackedField(const DescriptorPool& pool,
386                  const FieldDescriptor& fd,
387                  const protozero::Field& field,
388                  JsonBuilder* out) {
389   out->OpenArray();
390   bool e = false;
391   for (PackedRepeatedFieldIterator<W, T> it(field.data(), field.size(), &e); it;
392        it++) {
393     T value = *it;
394     if (fd.type() == FieldDescriptorProto::TYPE_ENUM) {
395       EnumField(pool, fd, static_cast<int32_t>(value), out);
396     } else {
397       out->NumberValue<T>(value);
398     }
399   }
400   out->CloseArray();
401   if (e) {
402     out->AddError(
403         std::string("Decoding failure for field '" + fd.name() + "'"));
404   }
405 }
406 
407 template <ProtoWireType W>
PackedBoolField(const DescriptorPool &,const FieldDescriptor & fd,const protozero::Field & field,JsonBuilder * out)408 void PackedBoolField(const DescriptorPool&,
409                      const FieldDescriptor& fd,
410                      const protozero::Field& field,
411                      JsonBuilder* out) {
412   out->OpenArray();
413   bool e = false;
414   for (PackedRepeatedFieldIterator<W, int32_t> it(field.data(), field.size(),
415                                                   &e);
416        it; it++) {
417     bool value = *it;
418     out->BoolValue(value);
419   }
420   out->CloseArray();
421   if (e) {
422     out->AddError(
423         std::string("Decoding failure for field '" + fd.name() + "'"));
424   }
425 }
426 
LengthField(const DescriptorPool & pool,const FieldDescriptor * fd,const protozero::Field & field,bool fully_qualify_extensions,JsonBuilder * out)427 void LengthField(const DescriptorPool& pool,
428                  const FieldDescriptor* fd,
429                  const protozero::Field& field,
430                  bool fully_qualify_extensions,
431                  JsonBuilder* out) {
432   uint32_t type = fd ? fd->type() : 0;
433   switch (type) {
434     case FieldDescriptorProto::TYPE_BYTES:
435       out->StringValue(field.as_string());
436       return;
437     case FieldDescriptorProto::TYPE_STRING:
438       out->StringValue(field.as_string());
439       return;
440     case FieldDescriptorProto::TYPE_MESSAGE:
441       MessageField(pool, fd->resolved_type_name(), field.as_bytes(),
442                    fully_qualify_extensions, out);
443       return;
444     case FieldDescriptorProto::TYPE_DOUBLE:
445       PackedField<ProtoWireType::kFixed64, double>(pool, *fd, field, out);
446       return;
447     case FieldDescriptorProto::TYPE_FLOAT:
448       PackedField<ProtoWireType::kFixed32, float>(pool, *fd, field, out);
449       return;
450     case FieldDescriptorProto::TYPE_FIXED32:
451       PackedField<ProtoWireType::kFixed32, uint32_t>(pool, *fd, field, out);
452       return;
453     case FieldDescriptorProto::TYPE_SFIXED32:
454       PackedField<ProtoWireType::kFixed32, int32_t>(pool, *fd, field, out);
455       return;
456     case FieldDescriptorProto::TYPE_INT32:
457       PackedField<ProtoWireType::kVarInt, int32_t>(pool, *fd, field, out);
458       return;
459     case FieldDescriptorProto::TYPE_SINT32:
460       PackedField<ProtoWireType::kVarInt, int32_t>(pool, *fd, field, out);
461       return;
462     case FieldDescriptorProto::TYPE_UINT32:
463       PackedField<ProtoWireType::kVarInt, uint32_t>(pool, *fd, field, out);
464       return;
465     case FieldDescriptorProto::TYPE_FIXED64:
466       PackedField<ProtoWireType::kFixed64, uint64_t>(pool, *fd, field, out);
467       return;
468     case FieldDescriptorProto::TYPE_SFIXED64:
469       PackedField<ProtoWireType::kFixed64, int64_t>(pool, *fd, field, out);
470       return;
471     case FieldDescriptorProto::TYPE_INT64:
472       PackedField<ProtoWireType::kVarInt, int64_t>(pool, *fd, field, out);
473       return;
474     case FieldDescriptorProto::TYPE_SINT64:
475       PackedField<ProtoWireType::kVarInt, int64_t>(pool, *fd, field, out);
476       return;
477     case FieldDescriptorProto::TYPE_UINT64:
478       PackedField<ProtoWireType::kVarInt, uint64_t>(pool, *fd, field, out);
479       return;
480     case FieldDescriptorProto::TYPE_ENUM:
481       PackedField<ProtoWireType::kVarInt, int32_t>(pool, *fd, field, out);
482       return;
483     case FieldDescriptorProto::TYPE_BOOL:
484       PackedBoolField<ProtoWireType::kVarInt>(pool, *fd, field, out);
485       return;
486     case 0:
487     default:
488       // In the absence of specific information display bytes.
489       out->StringValue(field.as_string());
490       return;
491   }
492 }
493 
EnumField(const DescriptorPool & pool,const FieldDescriptor & fd,int32_t value,JsonBuilder * out)494 void EnumField(const DescriptorPool& pool,
495                const FieldDescriptor& fd,
496                int32_t value,
497                JsonBuilder* out) {
498   auto opt_enum_descriptor_idx =
499       pool.FindDescriptorIdx(fd.resolved_type_name());
500   if (!opt_enum_descriptor_idx) {
501     out->NumberValue(value);
502     return;
503   }
504   auto opt_enum_string =
505       pool.descriptors()[*opt_enum_descriptor_idx].FindEnumString(value);
506   // If the enum value is unknown, treat it like a completely unknown field.
507   if (!opt_enum_string) {
508     out->NumberValue(value);
509     return;
510   }
511 
512   out->StringValue(base::StringView(*opt_enum_string));
513 }
514 
VarIntField(const DescriptorPool & pool,const FieldDescriptor * fd,const protozero::Field & field,JsonBuilder * out)515 void VarIntField(const DescriptorPool& pool,
516                  const FieldDescriptor* fd,
517                  const protozero::Field& field,
518                  JsonBuilder* out) {
519   uint32_t type = fd ? fd->type() : 0;
520   switch (type) {
521     case FieldDescriptorProto::TYPE_INT32:
522       out->NumberValue(field.as_int32());
523       return;
524     case FieldDescriptorProto::TYPE_SINT32:
525       out->NumberValue(field.as_sint32());
526       return;
527     case FieldDescriptorProto::TYPE_UINT32:
528       out->NumberValue(field.as_uint32());
529       return;
530     case FieldDescriptorProto::TYPE_INT64:
531       out->NumberValue(field.as_int64());
532       return;
533     case FieldDescriptorProto::TYPE_SINT64:
534       out->NumberValue(field.as_sint64());
535       return;
536     case FieldDescriptorProto::TYPE_UINT64:
537       out->NumberValue(field.as_uint64());
538       return;
539     case FieldDescriptorProto::TYPE_BOOL:
540       out->BoolValue(field.as_bool());
541       return;
542     case FieldDescriptorProto::TYPE_ENUM:
543       EnumField(pool, *fd, field.as_int32(), out);
544       return;
545     case 0:
546     default:
547       out->NumberValue(field.as_int64());
548       return;
549   }
550 }
551 
Fixed32Field(const FieldDescriptor * fd,const protozero::Field & field,JsonBuilder * out)552 void Fixed32Field(const FieldDescriptor* fd,
553                   const protozero::Field& field,
554                   JsonBuilder* out) {
555   uint32_t type = fd ? fd->type() : 0;
556   switch (type) {
557     case FieldDescriptorProto::TYPE_SFIXED32:
558       out->NumberValue(field.as_int32());
559       break;
560     case FieldDescriptorProto::TYPE_FIXED32:
561       out->NumberValue(field.as_uint32());
562       break;
563     case FieldDescriptorProto::TYPE_FLOAT:
564       out->FloatValue(field.as_float());
565       break;
566     case 0:
567     default:
568       out->NumberValue(field.as_uint32());
569       break;
570   }
571 }
572 
Fixed64Field(const FieldDescriptor * fd,const protozero::Field & field,JsonBuilder * out)573 void Fixed64Field(const FieldDescriptor* fd,
574                   const protozero::Field& field,
575                   JsonBuilder* out) {
576   uint64_t type = fd ? fd->type() : 0;
577   switch (type) {
578     case FieldDescriptorProto::TYPE_SFIXED64:
579       out->NumberValue(field.as_int64());
580       break;
581     case FieldDescriptorProto::TYPE_FIXED64:
582       out->NumberValue(field.as_uint64());
583       break;
584     case FieldDescriptorProto::TYPE_DOUBLE:
585       out->DoubleValue(field.as_double());
586       break;
587     case 0:
588     default:
589       out->NumberValue(field.as_uint64());
590       break;
591   }
592 }
593 
RepeatedVarInt(const DescriptorPool & pool,protozero::ConstBytes protobytes,const FieldDescriptor * fd,uint32_t id,JsonBuilder * out)594 void RepeatedVarInt(const DescriptorPool& pool,
595                     protozero::ConstBytes protobytes,
596                     const FieldDescriptor* fd,
597                     uint32_t id,
598                     JsonBuilder* out) {
599   out->OpenArray();
600   protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
601   for (auto field = decoder.ReadField(); field.valid();
602        field = decoder.ReadField()) {
603     if (field.id() == id) {
604       VarIntField(pool, fd, field, out);
605     }
606   }
607   out->CloseArray();
608 }
609 
RepeatedLengthField(const DescriptorPool & pool,protozero::ConstBytes protobytes,const FieldDescriptor * fd,uint32_t id,bool fully_qualify_extensions,JsonBuilder * out)610 void RepeatedLengthField(const DescriptorPool& pool,
611                          protozero::ConstBytes protobytes,
612                          const FieldDescriptor* fd,
613                          uint32_t id,
614                          bool fully_qualify_extensions,
615                          JsonBuilder* out) {
616   out->OpenArray();
617   protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
618   for (auto field = decoder.ReadField(); field.valid();
619        field = decoder.ReadField()) {
620     if (field.id() == id) {
621       LengthField(pool, fd, field, fully_qualify_extensions, out);
622     }
623   }
624   out->CloseArray();
625 }
626 
RepeatedFixed64(protozero::ConstBytes protobytes,const FieldDescriptor * fd,uint32_t id,JsonBuilder * out)627 void RepeatedFixed64(protozero::ConstBytes protobytes,
628                      const FieldDescriptor* fd,
629                      uint32_t id,
630                      JsonBuilder* out) {
631   out->OpenArray();
632   protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
633   for (auto field = decoder.ReadField(); field.valid();
634        field = decoder.ReadField()) {
635     if (field.id() == id) {
636       Fixed64Field(fd, field, out);
637     }
638   }
639   out->CloseArray();
640 }
641 
RepeatedFixed32(protozero::ConstBytes protobytes,const FieldDescriptor * fd,uint32_t id,JsonBuilder * out)642 void RepeatedFixed32(protozero::ConstBytes protobytes,
643                      const FieldDescriptor* fd,
644                      uint32_t id,
645                      JsonBuilder* out) {
646   out->OpenArray();
647   protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
648   for (auto field = decoder.ReadField(); field.valid();
649        field = decoder.ReadField()) {
650     if (field.id() == id) {
651       Fixed32Field(fd, field, out);
652     }
653   }
654   out->CloseArray();
655 }
656 
InnerMessageField(const DescriptorPool & pool,const std::string & type,protozero::ConstBytes protobytes,bool fully_qualify_extensions,JsonBuilder * out)657 void InnerMessageField(const DescriptorPool& pool,
658                        const std::string& type,
659                        protozero::ConstBytes protobytes,
660                        bool fully_qualify_extensions,
661                        JsonBuilder* out) {
662   std::optional<uint32_t> opt_proto_desc_idx = pool.FindDescriptorIdx(type);
663   const ProtoDescriptor* opt_proto_descriptor =
664       opt_proto_desc_idx ? &pool.descriptors()[*opt_proto_desc_idx] : nullptr;
665 
666   protozero::ProtoDecoder decoder(protobytes.data, protobytes.size);
667   std::unordered_set<uint32_t> fields_seen;
668 
669   for (auto field = decoder.ReadField(); field.valid();
670        field = decoder.ReadField()) {
671     auto* opt_field_descriptor =
672         opt_proto_descriptor ? opt_proto_descriptor->FindFieldByTag(field.id())
673                              : nullptr;
674     bool is_repeated = false;
675     if (opt_field_descriptor &&
676         IsTypeMatch(field.type(), opt_field_descriptor->type())) {
677       is_repeated = opt_field_descriptor->is_repeated();
678       // The first time we see a repeated field we consume them all:
679       if (fields_seen.count(field.id())) {
680         continue;
681       }
682       if (opt_field_descriptor->is_extension() && fully_qualify_extensions) {
683         out->Key(FulllyQualifiedFieldName(*opt_proto_descriptor,
684                                           *opt_field_descriptor));
685       } else {
686         out->Key(opt_field_descriptor->name());
687       }
688     } else {
689       out->Key(std::to_string(field.id()));
690     }
691     if (is_repeated) {
692       fields_seen.insert(field.id());
693 
694       switch (field.type()) {
695         case ProtoWireType::kVarInt:
696           RepeatedVarInt(pool, protobytes, opt_field_descriptor, field.id(),
697                          out);
698           break;
699         case ProtoWireType::kLengthDelimited:
700           if (opt_field_descriptor &&
701               IsNumericFieldType(opt_field_descriptor->type())) {
702             // wire_type = length + field_type in
703             // {u,s,}int{32,64}, float, double etc means this is the
704             // packed case:
705             LengthField(pool, opt_field_descriptor, field,
706                         fully_qualify_extensions, out);
707           } else {
708             RepeatedLengthField(pool, protobytes, opt_field_descriptor,
709                                 field.id(), fully_qualify_extensions, out);
710           }
711           break;
712         case ProtoWireType::kFixed32:
713           RepeatedFixed32(protobytes, opt_field_descriptor, field.id(), out);
714           break;
715         case ProtoWireType::kFixed64:
716           RepeatedFixed64(protobytes, opt_field_descriptor, field.id(), out);
717           break;
718       }
719     } else {
720       switch (field.type()) {
721         case ProtoWireType::kVarInt:
722           VarIntField(pool, opt_field_descriptor, field, out);
723           break;
724         case ProtoWireType::kLengthDelimited:
725           LengthField(pool, opt_field_descriptor, field,
726                       fully_qualify_extensions, out);
727           break;
728         case ProtoWireType::kFixed32:
729           Fixed32Field(opt_field_descriptor, field, out);
730           break;
731         case ProtoWireType::kFixed64:
732           Fixed64Field(opt_field_descriptor, field, out);
733           break;
734       }
735     }
736   }
737 
738   if (decoder.bytes_left() != 0) {
739     out->AddError(std::to_string(decoder.bytes_left()) + " extra bytes");
740   }
741 }
742 
MessageField(const DescriptorPool & pool,const std::string & type,protozero::ConstBytes protobytes,bool fully_qualify_extensions,JsonBuilder * out)743 void MessageField(const DescriptorPool& pool,
744                   const std::string& type,
745                   protozero::ConstBytes protobytes,
746                   bool fully_qualify_extensions,
747                   JsonBuilder* out) {
748   out->OpenObject();
749   InnerMessageField(pool, type, protobytes, fully_qualify_extensions, out);
750   out->CloseObject();
751 }
752 
753 // Prints all field options for non-empty fields of a message. Example:
754 // --- Message definitions ---
755 // FooMessage {
756 //   repeated int64 foo = 1 [op1 = val1, op2 = val2];
757 //   optional BarMessage bar = 2 [op3 = val3];
758 // }
759 //
760 // BarMessage {
761 //   optional int64 baz = 1 [op4 = val4];
762 // }
763 // --- MessageInstance ---
764 // foo_msg = {  // (As JSON)
765 //   foo: [23, 24, 25],
766 //   bar: {
767 //     baz: 42
768 //   }
769 // }
770 // --- Output of MessageFieldOptionsToJson(foo_msg) ---
771 //   foo: {
772 //     __field_options: {
773 //       op1: val1,
774 //       op2: val2,
775 //     },
776 //     __repeated: true
777 //   }
778 //   bar: {
779 //     __field_options: {
780 //       op3 = val3,
781 //     },
782 //     baz: {
783 //       __field_options: {
784 //         op4 = val4
785 //       },
786 //     }
787 //   }
MessageFieldOptionsToJson(const DescriptorPool & pool,const std::string & type,const std::string & field_prefix,const std::unordered_set<std::string> & allowed_fields,JsonBuilder * out)788 void MessageFieldOptionsToJson(
789     const DescriptorPool& pool,
790     const std::string& type,
791     const std::string& field_prefix,
792     const std::unordered_set<std::string>& allowed_fields,
793     JsonBuilder* out) {
794   std::optional<uint32_t> opt_proto_desc_idx = pool.FindDescriptorIdx(type);
795   if (!opt_proto_desc_idx) {
796     return;
797   }
798   const ProtoDescriptor& desc = pool.descriptors()[*opt_proto_desc_idx];
799   for (const auto& id_and_field : desc.fields()) {
800     const FieldDescriptor& field_desc = id_and_field.second;
801     std::string full_field_name = field_prefix + field_desc.name();
802     if (allowed_fields.find(full_field_name) == allowed_fields.end()) {
803       continue;
804     }
805     if (field_desc.is_extension()) {
806       out->Key(FulllyQualifiedFieldName(desc, field_desc));
807     } else {
808       out->Key(field_desc.name());
809     }
810     out->OpenObject();
811     if (HasFieldOptions(field_desc)) {
812       out->Key("__field_options");
813       MessageField(pool, ".google.protobuf.FieldOptions",
814                    protozero::ConstBytes{field_desc.options().data(),
815                                          field_desc.options().size()},
816                    false, out);
817     }
818     if (field_desc.type() == FieldDescriptorProto::Type::TYPE_MESSAGE) {
819       MessageFieldOptionsToJson(pool, field_desc.resolved_type_name(),
820                                 full_field_name + ".", allowed_fields, out);
821     }
822     if (field_desc.is_repeated()) {
823       out->Key("__repeated");
824       out->BoolValue(true);
825     }
826     out->CloseObject();
827   }
828 }
829 
PopulateAllowedFieldOptionsSet(const DescriptorPool & pool,const std::string & type,const std::string & field_prefix,protozero::ConstBytes protobytes,std::unordered_set<std::string> & allowed_fields)830 bool PopulateAllowedFieldOptionsSet(
831     const DescriptorPool& pool,
832     const std::string& type,
833     const std::string& field_prefix,
834     protozero::ConstBytes protobytes,
835     std::unordered_set<std::string>& allowed_fields) {
836   std::optional<uint32_t> opt_proto_desc_idx = pool.FindDescriptorIdx(type);
837   if (!opt_proto_desc_idx) {
838     return false;
839   }
840   const ProtoDescriptor& desc = pool.descriptors()[*opt_proto_desc_idx];
841   protozero::ProtoDecoder decoder(protobytes);
842   bool allowed = false;
843   for (auto field = decoder.ReadField(); field.valid();
844        field = decoder.ReadField()) {
845     auto* opt_field_descriptor = desc.FindFieldByTag(field.id());
846     if (!opt_field_descriptor) {
847       continue;
848     }
849     std::string full_field_name = field_prefix + opt_field_descriptor->name();
850     bool nested = false;
851     if (opt_field_descriptor->type() ==
852         protos::pbzero::FieldDescriptorProto::TYPE_MESSAGE) {
853       nested = PopulateAllowedFieldOptionsSet(
854           pool, opt_field_descriptor->resolved_type_name(),
855           full_field_name + ".", field.as_bytes(), allowed_fields);
856     }
857     if (nested || HasFieldOptions(*opt_field_descriptor)) {
858       allowed_fields.emplace(full_field_name);
859       allowed = true;
860     }
861   }
862   return allowed;
863 }
864 
865 }  // namespace
866 
ProtozeroToJson(const DescriptorPool & pool,const std::string & type,protozero::ConstBytes protobytes,int flags)867 std::string ProtozeroToJson(const DescriptorPool& pool,
868                             const std::string& type,
869                             protozero::ConstBytes protobytes,
870                             int flags) {
871   JsonBuilder builder(flags);
872   builder.OpenObject();
873   InnerMessageField(pool, type, protobytes, true, &builder);
874   if (builder.is_inline_errors() && !builder.errors().empty()) {
875     builder.Key("__error");
876     builder.StringValue(base::StringView(base::Join(builder.errors(), "\n")));
877   }
878   if (flags & kInlineAnnotations) {
879     std::unordered_set<std::string> allowed_fields;
880     PopulateAllowedFieldOptionsSet(pool, type, "", protobytes, allowed_fields);
881     if (!allowed_fields.empty()) {
882       builder.Key("__annotations");
883       builder.OpenObject();
884       MessageFieldOptionsToJson(pool, type, "", allowed_fields, &builder);
885       builder.CloseObject();
886     }
887   }
888   builder.CloseObject();
889   return builder.ToString();
890 }
891 
ProtozeroToJson(const DescriptorPool & pool,const std::string & type,const std::vector<uint8_t> & protobytes,int flags)892 std::string ProtozeroToJson(const DescriptorPool& pool,
893                             const std::string& type,
894                             const std::vector<uint8_t>& protobytes,
895                             int flags) {
896   return ProtozeroToJson(
897       pool, type, protozero::ConstBytes{protobytes.data(), protobytes.size()},
898       flags);
899 }
900 
901 }  // namespace protozero_to_json
902 }  // namespace trace_processor
903 }  // namespace perfetto
904