[Reland] Allow typed proto messages to be written into TracedValue.

This is a reland of r.android.com/1699768, caused by a lack of `const`
modifier on a WriteIntoTrace function in Chrome, which was fixed by
crrev.com/c/3500621.

=====

This patch adds TracedValue::WriteProto<proto::pbzero::MessageType>()
method, which can be used to write structured proto inside TracedValue.

Also TracedProto now gets an implicit constructor from TracedValue,
which means that if a C++ class implements
Foo::WriteIntoTrace(TracedProto<...>) method, it can be used in all
places where a class implementing Foo::WriteIntoTrace(TracedValue) can
be used, including:
- being passed as an untyped argument to TRACE_EVENT:
  TRACE_EVENT(..., "arg", Foo());
- being passed to TracedDictionary::Add / TracedArray::Append.

This patch also adds MessageType::GetName() method to the protozero
bindings, which is needed for implementation of WriteProto method.

R=eseckler@google.com,skyostil@google.com
CC=primiano@google.com

Bug: b/184558843
Change-Id: I85956dd889780efd1ccf8fd943edee76ab99d820
diff --git a/CHANGELOG b/CHANGELOG
index 02ab1f8..95516cd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,7 +8,7 @@
     * Added flow arrows between binder transaction pairs (request/reply
       and async send/async recv).
   SDK:
-    *
+    * Added support for writing typed proto messages inside DebugAnnotations.
 
 
 v24.2 - 2022-02-10:
diff --git a/include/perfetto/tracing/traced_proto.h b/include/perfetto/tracing/traced_proto.h
index a887d96..aa2aa64 100644
--- a/include/perfetto/tracing/traced_proto.h
+++ b/include/perfetto/tracing/traced_proto.h
@@ -50,11 +50,15 @@
 template <typename MessageType>
 class TracedProto {
  public:
+  // implicit
+  TracedProto(TracedValue&& value)
+      : TracedProto(std::move(value).WriteProto<MessageType>()) {}
+  ~TracedProto() = default;
+
   TracedProto(const TracedProto&) = delete;
   TracedProto& operator=(const TracedProto&) = delete;
   TracedProto& operator=(TracedProto&&) = delete;
   TracedProto(TracedProto&&) = default;
-  ~TracedProto() = default;
 
   MessageType* operator->() const { return message_; }
 
@@ -91,10 +95,9 @@
     static_assert(std::is_base_of<MessageType,
                                   typename FieldMetadata::message_type>::value,
                   "Field should belong to the current message");
-    return TracedProto<typename FieldMetadata::cpp_field_type>(
+    return Wrap(
         message_->template BeginNestedMessage<
-            typename FieldMetadata::cpp_field_type>(FieldMetadata::kFieldId),
-        context_);
+            typename FieldMetadata::cpp_field_type>(FieldMetadata::kFieldId));
   }
 
   template <typename FieldMetadata>
@@ -105,6 +108,7 @@
 
  private:
   friend class EventContext;
+  friend class TracedValue;
   // Allow TracedProto<Foo> to create TracedProto<Bar>.
   template <typename T>
   friend class TracedProto;
@@ -112,7 +116,7 @@
   // Wraps a raw protozero message using the same context as the current object.
   template <typename ChildMessageType>
   TracedProto<ChildMessageType> Wrap(ChildMessageType* message) {
-    return TracedProto(message, context_);
+    return TracedProto<ChildMessageType>(message, context_);
   }
 
   // Context might be null here when writing typed message which is
diff --git a/include/perfetto/tracing/traced_value.h b/include/perfetto/tracing/traced_value.h
index 53f1cb6..7bebd25 100644
--- a/include/perfetto/tracing/traced_value.h
+++ b/include/perfetto/tracing/traced_value.h
@@ -141,6 +141,8 @@
   void WriteString(const char*, size_t len) &&;
   void WriteString(const std::string&) &&;
   void WritePointer(const void* value) &&;
+  template <typename MessageType>
+  TracedProto<MessageType> WriteProto() &&;
 
   // Rules for writing nested dictionaries and arrays:
   // - Only one scope (TracedArray, TracedDictionary or TracedValue) can be
@@ -172,6 +174,8 @@
                               internal::CheckedScope* parent_scope)
       : context_(context), checked_scope_(parent_scope) {}
 
+  protozero::Message* WriteProtoInternal(const char* name);
+
   // Temporary support for perfetto::DebugAnnotation C++ class before it's going
   // to be replaced by TracedValue.
   // TODO(altimin): Convert v8 to use TracedValue directly and delete it.
@@ -182,6 +186,13 @@
   internal::CheckedScope checked_scope_;
 };
 
+template <typename MessageType>
+TracedProto<MessageType> TracedValue::WriteProto() && {
+  return TracedProto<MessageType>(
+      static_cast<MessageType*>(WriteProtoInternal(MessageType::GetName())),
+      nullptr);
+}
+
 class PERFETTO_EXPORT TracedArray {
  public:
   TracedArray(const TracedArray&) = delete;
diff --git a/include/perfetto/tracing/traced_value_forward.h b/include/perfetto/tracing/traced_value_forward.h
index 7a91712..a8cbe8e 100644
--- a/include/perfetto/tracing/traced_value_forward.h
+++ b/include/perfetto/tracing/traced_value_forward.h
@@ -22,6 +22,8 @@
 class TracedValue;
 class TracedArray;
 class TracedDictionary;
+template <typename MessageType>
+class TracedProto;
 
 template <typename T>
 void WriteIntoTracedValue(TracedValue context, T&& value);
diff --git a/protos/perfetto/trace/interned_data/interned_data.proto b/protos/perfetto/trace/interned_data/interned_data.proto
index cc9c9e3..86b8a9f 100644
--- a/protos/perfetto/trace/interned_data/interned_data.proto
+++ b/protos/perfetto/trace/interned_data/interned_data.proto
@@ -53,7 +53,7 @@
 // emitted proactively in advance of referring to them in later packets.
 //
 // Next reserved id: 8 (up to 15).
-// Next id: 27.
+// Next id: 28.
 message InternedData {
   // TODO(eseckler): Replace iid fields inside interned messages with
   // map<iid, message> type fields in InternedData.
@@ -68,6 +68,7 @@
   repeated EventCategory event_categories = 1;
   repeated EventName event_names = 2;
   repeated DebugAnnotationName debug_annotation_names = 3;
+  repeated DebugAnnotationValueTypeName debug_annotation_value_type_names = 27;
   repeated SourceLocation source_locations = 4;
   repeated LogMessageBody log_message_body = 20;
   repeated HistogramName histogram_names = 25;
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 39b2ad0..4dee1cf 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -6996,7 +6996,8 @@
 //     }
 //   }
 //
-// Next ID: 13.
+// Next ID: 17.
+// Reserved ID: 15
 message DebugAnnotation {
   // Name fields are set only for dictionary entries.
   oneof name_field {
@@ -7024,6 +7025,18 @@
     string legacy_json_value = 9;
   }
 
+  // Used to embed arbitrary proto messages (which are also typically used to
+  // represent typed TrackEvent arguments). |proto_type_name| or
+  // |proto_type_name_iid| are storing the full name of the proto messages (e.g.
+  // .perfetto.protos.DebugAnnotation) and |proto_value| contains the serialised
+  // proto messages. See |TracedValue::WriteProto| for more details.
+  oneof proto_type_descriptor {
+    string proto_type_name = 16;
+    // interned DebugAnnotationValueTypeName.
+    uint32 proto_type_name_iid = 13;
+  }
+  optional bytes proto_value = 14;
+
   repeated DebugAnnotation dict_entries = 11;
   repeated DebugAnnotation array_values = 12;
 
@@ -7058,6 +7071,12 @@
   optional string name = 2;
 }
 
+// See the |proto_type_descriptor| comment.
+message DebugAnnotationValueTypeName {
+  optional uint64 iid = 1;
+  optional string name = 2;
+}
+
 // End of protos/perfetto/trace/track_event/debug_annotation.proto
 
 // Begin of protos/perfetto/trace/track_event/log_message.proto
@@ -8109,7 +8128,7 @@
 // emitted proactively in advance of referring to them in later packets.
 //
 // Next reserved id: 8 (up to 15).
-// Next id: 27.
+// Next id: 28.
 message InternedData {
   // TODO(eseckler): Replace iid fields inside interned messages with
   // map<iid, message> type fields in InternedData.
@@ -8124,6 +8143,7 @@
   repeated EventCategory event_categories = 1;
   repeated EventName event_names = 2;
   repeated DebugAnnotationName debug_annotation_names = 3;
+  repeated DebugAnnotationValueTypeName debug_annotation_value_type_names = 27;
   repeated SourceLocation source_locations = 4;
   repeated LogMessageBody log_message_body = 20;
   repeated HistogramName histogram_names = 25;
diff --git a/protos/perfetto/trace/track_event/debug_annotation.proto b/protos/perfetto/trace/track_event/debug_annotation.proto
index d6766cb..8881955 100644
--- a/protos/perfetto/trace/track_event/debug_annotation.proto
+++ b/protos/perfetto/trace/track_event/debug_annotation.proto
@@ -57,7 +57,8 @@
 //     }
 //   }
 //
-// Next ID: 13.
+// Next ID: 17.
+// Reserved ID: 15
 message DebugAnnotation {
   // Name fields are set only for dictionary entries.
   oneof name_field {
@@ -85,6 +86,18 @@
     string legacy_json_value = 9;
   }
 
+  // Used to embed arbitrary proto messages (which are also typically used to
+  // represent typed TrackEvent arguments). |proto_type_name| or
+  // |proto_type_name_iid| are storing the full name of the proto messages (e.g.
+  // .perfetto.protos.DebugAnnotation) and |proto_value| contains the serialised
+  // proto messages. See |TracedValue::WriteProto| for more details.
+  oneof proto_type_descriptor {
+    string proto_type_name = 16;
+    // interned DebugAnnotationValueTypeName.
+    uint32 proto_type_name_iid = 13;
+  }
+  optional bytes proto_value = 14;
+
   repeated DebugAnnotation dict_entries = 11;
   repeated DebugAnnotation array_values = 12;
 
@@ -118,3 +131,9 @@
   optional uint64 iid = 1;
   optional string name = 2;
 }
+
+// See the |proto_type_descriptor| comment.
+message DebugAnnotationValueTypeName {
+  optional uint64 iid = 1;
+  optional string name = 2;
+}
diff --git a/src/protozero/protoc_plugin/protozero_plugin.cc b/src/protozero/protoc_plugin/protozero_plugin.cc
index 311672a..feabdf1 100644
--- a/src/protozero/protoc_plugin/protozero_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_plugin.cc
@@ -779,6 +779,10 @@
 
     GenerateConstantsForMessageFields(message);
 
+    stub_h_->Print(
+        "static constexpr const char* GetName() { return \".$name$\"; }\n\n",
+        "name", message->full_name());
+
     // Using statements for nested messages.
     for (int i = 0; i < message->nested_type_count(); ++i) {
       const Descriptor* nested_message = message->nested_type(i);
@@ -848,7 +852,7 @@
 // It is declared as a function to keep protozero bindings header-only as
 // inline constexpr variables are not available until C++17 (while inline
 // functions are).
-// TODO(altimin): Use inline variable instead after adopting C++17.  
+// TODO(altimin): Use inline variable instead after adopting C++17.
 static constexpr $field_metadata_type$ $field_metadata_var$() { return {}; }
 )";
 
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 82b2c7e..07c8d76 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -130,6 +130,7 @@
     "../../../gn:default_deps",
     "../../../gn:gtest_and_gmock",
     "../../../protos/perfetto/common:zero",
+    "../../../protos/perfetto/trace:non_minimal_zero",
     "../../../protos/perfetto/trace/track_event:zero",
     "../../protozero",
     "../../protozero:testing_messages_zero",
diff --git a/src/trace_processor/util/debug_annotation_parser.cc b/src/trace_processor/util/debug_annotation_parser.cc
index 7fa359e..7b49d2d 100644
--- a/src/trace_processor/util/debug_annotation_parser.cc
+++ b/src/trace_processor/util/debug_annotation_parser.cc
@@ -130,6 +130,25 @@
   } else if (annotation.has_nested_value()) {
     return ParseNestedValueArgs(annotation.nested_value(), context_name,
                                 delegate);
+  } else if (annotation.has_proto_value()) {
+    std::string type_name;
+    if (annotation.has_proto_type_name()) {
+      type_name = annotation.proto_type_name().ToStdString();
+    } else if (annotation.has_proto_type_name_iid()) {
+      auto* interned_name = delegate.GetInternedMessage(
+          protos::pbzero::InternedData::kDebugAnnotationValueTypeNames,
+          annotation.proto_type_name_iid());
+      if (!interned_name)
+        return {base::ErrStatus("Interned proto type name not found"), false};
+      type_name = interned_name->name().ToStdString();
+    } else {
+      return {base::ErrStatus("DebugAnnotation has proto_value, but doesn't "
+                              "have proto type name"),
+              false};
+    }
+    return {proto_to_args_parser_.ParseMessage(annotation.proto_value(),
+                                               type_name, nullptr, delegate),
+            true};
   } else {
     return {base::OkStatus(), /*added_entry=*/false};
   }
diff --git a/src/trace_processor/util/debug_annotation_parser_unittest.cc b/src/trace_processor/util/debug_annotation_parser_unittest.cc
index d074e79..55a614f 100644
--- a/src/trace_processor/util/debug_annotation_parser_unittest.cc
+++ b/src/trace_processor/util/debug_annotation_parser_unittest.cc
@@ -20,6 +20,7 @@
 #include "perfetto/protozero/scattered_heap_buffer.h"
 #include "perfetto/trace_processor/trace_blob_view.h"
 #include "protos/perfetto/common/descriptor.pbzero.h"
+#include "protos/perfetto/trace/test_event.pbzero.h"
 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
 #include "src/protozero/test/example_proto/test_messages.pbzero.h"
@@ -237,6 +238,33 @@
                                    "root root[1][0] 3", "root root[1][1] 4"));
 }
 
+TEST_F(DebugAnnotationParserTest, TypedMessageInsideUntyped) {
+  protozero::HeapBuffered<protos::pbzero::DebugAnnotation> msg;
+  msg->set_name("root");
+
+  protozero::HeapBuffered<protozero::test::protos::pbzero::EveryField> message;
+  message->set_field_string("value");
+
+  msg->set_proto_type_name(message->GetName());
+  msg->set_proto_value(message.SerializeAsString());
+
+  DescriptorPool pool;
+  auto status = pool.AddFromFileDescriptorSet(kTestMessagesDescriptor.data(),
+                                              kTestMessagesDescriptor.size());
+  EXPECT_TRUE(status.ok()) << "Failed to parse kTestMessagesDescriptor: "
+                           << status.message();
+
+  ProtoToArgsParser args_parser(pool);
+  DebugAnnotationParser parser(args_parser);
+
+  status = ParseDebugAnnotation(parser, msg, *this);
+  EXPECT_TRUE(status.ok()) << "DebugAnnotationParser::Parse failed with error: "
+                           << status.message();
+
+  EXPECT_THAT(args(), testing::ElementsAre(
+                          "root.field_string root.field_string value"));
+}
+
 }  // namespace
 }  // namespace util
 }  // namespace trace_processor
diff --git a/src/tracing/traced_value.cc b/src/tracing/traced_value.cc
index bd8b1ad..decaf5d 100644
--- a/src/tracing/traced_value.cc
+++ b/src/tracing/traced_value.cc
@@ -99,6 +99,14 @@
   return TracedArray(context_, checked_scope_.parent_scope());
 }
 
+protozero::Message* TracedValue::WriteProtoInternal(const char* name) {
+  // TODO(altimin): Plumb EventContext to TracedValue and support interning
+  // here.
+  context_->set_proto_type_name(name);
+  return context_->template BeginNestedMessage<protozero::Message>(
+      protos::pbzero::DebugAnnotation::kProtoValueFieldNumber);
+}
+
 TracedValue TracedArray::AppendItem() {
   PERFETTO_DCHECK(checked_scope_.is_active());
   return TracedValue(context_->add_array_values(), &checked_scope_);
diff --git a/src/tracing/traced_value_unittest.cc b/src/tracing/traced_value_unittest.cc
index 66c86db..41f6402 100644
--- a/src/tracing/traced_value_unittest.cc
+++ b/src/tracing/traced_value_unittest.cc
@@ -32,6 +32,8 @@
 #include "perfetto/test/traced_value_test_support.h"
 #include "perfetto/tracing/debug_annotation.h"
 #include "perfetto/tracing/track_event.h"
+#include "protos/perfetto/trace/test_event.pb.h"
+#include "protos/perfetto/trace/test_event.pbzero.h"
 #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
 #include "protos/perfetto/trace/track_event/debug_annotation.pb.h"
 #include "test/gtest_and_gmock.h"
@@ -619,4 +621,43 @@
             }));
 }
 
+TEST(TracedValueTest, WriteTypedProto_Explicit) {
+  protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
+  WriteIntoTracedValue(
+      internal::CreateTracedValueFromProto(message.get()),
+      [](perfetto::TracedValue context) {
+        perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> proto =
+            std::move(context)
+                .WriteProto<protos::pbzero::TestEvent::TestPayload>();
+        proto->set_single_string("payload");
+      });
+
+  protos::DebugAnnotation annotation;
+  annotation.ParseFromString(message.SerializeAsString());
+  EXPECT_EQ(annotation.proto_type_name(),
+            ".perfetto.protos.TestEvent.TestPayload");
+
+  protos::TestEvent::TestPayload payload;
+  payload.ParseFromString(annotation.proto_value());
+  EXPECT_EQ(payload.single_string(), "payload");
+}
+
+TEST(TracedValueTest, WriteTypedProto_Implicit) {
+  protozero::HeapBuffered<protos::pbzero::DebugAnnotation> message;
+  WriteIntoTracedValue(
+      internal::CreateTracedValueFromProto(message.get()),
+      [](perfetto::TracedProto<protos::pbzero::TestEvent::TestPayload> proto) {
+        proto->set_single_string("payload");
+      });
+
+  protos::DebugAnnotation annotation;
+  annotation.ParseFromString(message.SerializeAsString());
+  EXPECT_EQ(annotation.proto_type_name(),
+            ".perfetto.protos.TestEvent.TestPayload");
+
+  protos::TestEvent::TestPayload payload;
+  payload.ParseFromString(annotation.proto_value());
+  EXPECT_EQ(payload.single_string(), "payload");
+}
+
 }  // namespace perfetto