Merge "Add Chrome metadata parsing for the new field_trial_hashes field." into main
diff --git a/src/trace_processor/importers/proto/metadata_minimal_module.cc b/src/trace_processor/importers/proto/metadata_minimal_module.cc
index 099cdac..df4dd3f 100644
--- a/src/trace_processor/importers/proto/metadata_minimal_module.cc
+++ b/src/trace_processor/importers/proto/metadata_minimal_module.cc
@@ -17,6 +17,7 @@
 #include "src/trace_processor/importers/proto/metadata_minimal_module.h"
 
 #include "perfetto/ext/base/base64.h"
+#include "perfetto/ext/base/string_utils.h"
 #include "src/trace_processor/importers/common/metadata_tracker.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 
@@ -106,6 +107,15 @@
   TraceStorage* storage = context_->storage.get();
   MetadataTracker* metadata = context_->metadata_tracker.get();
 
+  // TODO(b/322298334): There is no easy way to associate ChromeMetadataPacket
+  // with ChromeMetadata for the same instance, so we have opted for letters to
+  // differentiate Chrome instances for ChromeMetadataPacket. When a unifying
+  // Chrome instance ID is in place, update this code to use the same counter
+  // as ChromeMetadata values.
+  base::StackString<6> metadata_prefix(
+      "cr-%c-", static_cast<char>('a' + (chrome_metadata_count_ % 26)));
+  chrome_metadata_count_++;
+
   // Typed chrome metadata proto. The untyped metadata is parsed below in
   // ParseChromeEvents().
   protos::pbzero::ChromeMetadataPacket::Decoder packet_decoder(blob.data,
@@ -113,14 +123,48 @@
 
   if (packet_decoder.has_chrome_version_code()) {
     metadata->SetDynamicMetadata(
-        storage->InternString("cr-playstore_version_code"),
+        storage->InternString(base::StringView(metadata_prefix.ToStdString() +
+                                               "playstore_version_code")),
         Variadic::Integer(packet_decoder.chrome_version_code()));
   }
   if (packet_decoder.has_enabled_categories()) {
     auto categories_id =
         storage->InternString(packet_decoder.enabled_categories());
-    metadata->SetDynamicMetadata(storage->InternString("cr-enabled_categories"),
-                                 Variadic::String(categories_id));
+    metadata->SetDynamicMetadata(
+        storage->InternString(base::StringView(metadata_prefix.ToStdString() +
+                                               "enabled_categories")),
+        Variadic::String(categories_id));
+  }
+
+  if (packet_decoder.has_field_trial_hashes()) {
+    std::string field_trials;
+
+    // Add  a line break after every 2 field trial hashes to better utilize the
+    // UI space.
+    int line_size = 0;
+    for (auto it = packet_decoder.field_trial_hashes(); it; ++it) {
+      if (line_size == 2) {
+        field_trials.append("\n");
+        line_size = 1;
+      } else {
+        line_size++;
+      }
+
+      perfetto::protos::pbzero::ChromeMetadataPacket::FinchHash::Decoder
+          field_trial(*it);
+
+      base::StackString<45> field_trial_string(
+          "{ name: %u, group: %u } ", field_trial.name(), field_trial.group());
+
+      field_trials.append(field_trial_string.ToStdString());
+    }
+
+    StringId field_trials_string =
+        context_->storage->InternString(base::StringView(field_trials));
+    metadata->SetDynamicMetadata(
+        storage->InternString(base::StringView(metadata_prefix.ToStdString() +
+                                               "field_trial_hashes")),
+        Variadic::String(field_trials_string));
   }
 
   if (packet_decoder.has_background_tracing_metadata()) {
diff --git a/src/trace_processor/importers/proto/metadata_minimal_module.h b/src/trace_processor/importers/proto/metadata_minimal_module.h
index b12eed9..3ffdf62 100644
--- a/src/trace_processor/importers/proto/metadata_minimal_module.h
+++ b/src/trace_processor/importers/proto/metadata_minimal_module.h
@@ -44,6 +44,8 @@
   void ParseChromeMetadataPacket(ConstBytes);
 
   TraceProcessorContext* context_;
+
+  uint32_t chrome_metadata_count_ = 0;
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql b/src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql
index 968159b..05a9ae6 100644
--- a/src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql
+++ b/src/trace_processor/metrics/sql/chrome/chrome_slice_names.sql
@@ -21,7 +21,7 @@
   'chrome_version_code', (
     SELECT RepeatedField(int_value)
     FROM metadata
-    WHERE name = 'cr-playstore_version_code'
+    WHERE name GLOB 'cr-*playstore_version_code'
     ORDER BY int_value
   ),
   'slice_name', (
diff --git a/test/trace_processor/diff_tests/parser/parsing/chrome_metadata.out b/test/trace_processor/diff_tests/parser/parsing/chrome_metadata.out
index 873e349..5635f53 100644
--- a/test/trace_processor/diff_tests/parser/parsing/chrome_metadata.out
+++ b/test/trace_processor/diff_tests/parser/parsing/chrome_metadata.out
@@ -1,10 +1,11 @@
 "id","type","name","key_type","int_value","str_value"
-0,"metadata","trace_uuid","single","[NULL]","00000000-0000-0000-dcce-849205cfb03e" 
+0,"metadata","trace_uuid","single","[NULL]","00000000-0000-0000-afe8-083bd6899d9d"
 1,"metadata","trace_time_clock_id","single",6,"[NULL]"
-2,"metadata","cr-playstore_version_code","single",101,"[NULL]"
-3,"metadata","cr-enabled_categories","single","[NULL]","cat1,cat2,cat3"
-4,"metadata","cr-background_tracing_metadata","single","[NULL]","CgUlDsAbXx2RziSz"
-5,"metadata","cr-scenario_name_hash","single",3005533841,"[NULL]"
-6,"metadata","cr-triggered_rule_name_hash","single",1595654158,"[NULL]"
-7,"metadata","trace_size_bytes","single",64,"[NULL]"
-8,"metadata","trace_type","single","[NULL]","proto"
+2,"metadata","cr-a-playstore_version_code","single",101,"[NULL]"
+3,"metadata","cr-a-enabled_categories","single","[NULL]","cat1,cat2,cat3"
+4,"metadata","cr-a-field_trial_hashes","single","[NULL]","{ name: 123, group: 456 } { name: 789, group: 120 } "
+5,"metadata","cr-background_tracing_metadata","single","[NULL]","CgUlDsAbXx2RziSz"
+6,"metadata","cr-scenario_name_hash","single",3005533841,"[NULL]"
+7,"metadata","cr-triggered_rule_name_hash","single",1595654158,"[NULL]"
+8,"metadata","trace_size_bytes","single",78,"[NULL]"
+9,"metadata","trace_type","single","[NULL]","proto"
diff --git a/test/trace_processor/diff_tests/parser/parsing/tests.py b/test/trace_processor/diff_tests/parser/parsing/tests.py
index 90067a7..5df7a52 100644
--- a/test/trace_processor/diff_tests/parser/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parser/parsing/tests.py
@@ -643,6 +643,14 @@
             }
             chrome_version_code: 101
             enabled_categories: "cat1,cat2,cat3"
+            field_trial_hashes {
+              name: 123
+              group: 456
+            }
+            field_trial_hashes {
+              name: 789
+              group: 120
+            }
           }
         }
         """),
@@ -651,6 +659,69 @@
         """,
         out=Path('chrome_metadata.out'))
 
+  def test_chrome_metadata_multiple(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          clock_snapshot {
+            clocks {
+              clock_id: 6
+              timestamp: 101000002
+            }
+          }
+          trusted_packet_sequence_id: 1
+          timestamp: 101000002
+        }
+        packet {
+          trusted_packet_sequence_id: 1
+          timestamp: 101000002
+          chrome_metadata {
+            chrome_version_code: 101
+            enabled_categories: "cat1,cat2,cat3"
+            field_trial_hashes {
+              name: 123
+              group: 456
+            }
+            field_trial_hashes {
+              name: 789
+              group: 120
+            }
+          }
+        }
+        packet {
+          trusted_packet_sequence_id: 1
+          timestamp: 101000002
+          chrome_metadata {
+            chrome_version_code: 102
+            enabled_categories: "cat3,cat4,cat5"
+            field_trial_hashes {
+              name: 1234
+              group: 5678
+            }
+            field_trial_hashes {
+              name: 9012
+              group: 3456
+            }
+          }
+        }
+        """),
+        query="""
+        SELECT * FROM metadata;
+        """,
+        out=Csv("""
+        "id","type","name","key_type","int_value","str_value"
+        0,"metadata","trace_uuid","single","[NULL]","00000000-0000-0000-0de8-df55233147f0"
+        1,"metadata","trace_time_clock_id","single",6,"[NULL]"
+        2,"metadata","cr-a-playstore_version_code","single",101,"[NULL]"
+        3,"metadata","cr-a-enabled_categories","single","[NULL]","cat1,cat2,cat3"
+        4,"metadata","cr-a-field_trial_hashes","single","[NULL]","{ name: 123, group: 456 } { name: 789, group: 120 } "
+        5,"metadata","cr-b-playstore_version_code","single",102,"[NULL]"
+        6,"metadata","cr-b-enabled_categories","single","[NULL]","cat3,cat4,cat5"
+        7,"metadata","cr-b-field_trial_hashes","single","[NULL]","{ name: 1234, group: 5678 } { name: 9012, group: 3456 } "
+        8,"metadata","trace_size_bytes","single",110,"[NULL]"
+        9,"metadata","trace_type","single","[NULL]","proto"
+        """))
+
   # CPU info
   def test_cpu(self):
     return DiffTestBlueprint(