tp: add ui state proto and expose it in the metadata table

Doc: go/trace-ui-state
Change-Id: Idf8a28d12c2cb2998a623f9f58bb68797484edaa
diff --git a/Android.bp b/Android.bp
index c3e2ce7..d0dc689 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5139,6 +5139,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5152,6 +5153,7 @@
     "external/perfetto/protos/perfetto/trace/trace.gen.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet.gen.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.gen.cc",
+    "external/perfetto/protos/perfetto/trace/ui_state.gen.cc",
   ],
 }
 
@@ -5165,6 +5167,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5178,6 +5181,7 @@
     "external/perfetto/protos/perfetto/trace/trace.gen.h",
     "external/perfetto/protos/perfetto/trace/trace_packet.gen.h",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.gen.h",
+    "external/perfetto/protos/perfetto/trace/ui_state.gen.h",
   ],
   export_include_dirs: [
     ".",
@@ -5195,6 +5199,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5207,6 +5212,7 @@
     "external/perfetto/protos/perfetto/trace/trace.pb.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet.pb.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.pb.cc",
+    "external/perfetto/protos/perfetto/trace/ui_state.pb.cc",
   ],
 }
 
@@ -5220,6 +5226,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5232,6 +5239,7 @@
     "external/perfetto/protos/perfetto/trace/trace.pb.h",
     "external/perfetto/protos/perfetto/trace/trace_packet.pb.h",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.pb.h",
+    "external/perfetto/protos/perfetto/trace/ui_state.pb.h",
   ],
   export_include_dirs: [
     ".",
@@ -5249,6 +5257,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5262,6 +5271,7 @@
     "external/perfetto/protos/perfetto/trace/trace.pbzero.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet.pbzero.cc",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.pbzero.cc",
+    "external/perfetto/protos/perfetto/trace/ui_state.pbzero.cc",
   ],
 }
 
@@ -5275,6 +5285,7 @@
     "protos/perfetto/trace/trace.proto",
     "protos/perfetto/trace/trace_packet.proto",
     "protos/perfetto/trace/trace_packet_defaults.proto",
+    "protos/perfetto/trace/ui_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -5288,6 +5299,7 @@
     "external/perfetto/protos/perfetto/trace/trace.pbzero.h",
     "external/perfetto/protos/perfetto/trace/trace_packet.pbzero.h",
     "external/perfetto/protos/perfetto/trace/trace_packet_defaults.pbzero.h",
+    "external/perfetto/protos/perfetto/trace/ui_state.pbzero.h",
   ],
   export_include_dirs: [
     ".",
@@ -7897,6 +7909,7 @@
     "src/trace_processor/importers/proto/heap_profile_tracker.cc",
     "src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
     "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
+    "src/trace_processor/importers/proto/metadata_module.cc",
     "src/trace_processor/importers/proto/metadata_tracker.cc",
     "src/trace_processor/importers/proto/packet_sequence_state.cc",
     "src/trace_processor/importers/proto/perf_sample_tracker.cc",
diff --git a/BUILD b/BUILD
index 1699bdb..1c6cea7 100644
--- a/BUILD
+++ b/BUILD
@@ -1271,6 +1271,8 @@
         "src/trace_processor/importers/proto/memory_tracker_snapshot_module.h",
         "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
         "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h",
+        "src/trace_processor/importers/proto/metadata_module.cc",
+        "src/trace_processor/importers/proto/metadata_module.h",
         "src/trace_processor/importers/proto/metadata_tracker.cc",
         "src/trace_processor/importers/proto/metadata_tracker.h",
         "src/trace_processor/importers/proto/packet_sequence_state.cc",
@@ -2758,6 +2760,7 @@
         "protos/perfetto/trace/trace.proto",
         "protos/perfetto/trace/trace_packet.proto",
         "protos/perfetto/trace/trace_packet_defaults.proto",
+        "protos/perfetto/trace/ui_state.proto",
     ],
     visibility = PERFETTO_CONFIG.public_visibility,
     deps = [
diff --git a/include/perfetto/ext/base/string_utils.h b/include/perfetto/ext/base/string_utils.h
index b4a8bf9..7310b01 100644
--- a/include/perfetto/ext/base/string_utils.h
+++ b/include/perfetto/ext/base/string_utils.h
@@ -122,6 +122,7 @@
                        const std::string& to_replace,
                        const std::string& replacement);
 std::string TrimLeading(const std::string& str);
+std::string Base64Encode(const void* ptr, size_t size);
 
 }  // namespace base
 }  // namespace perfetto
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index 9c195e4..7861978 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -33,6 +33,7 @@
   "trace.proto",
   "extension_descriptor.proto",
   "memory_graph.proto",
+  "ui_state.proto",
 ]
 
 proto_sources_minimal = [
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 4d0d946..ae2b46c 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -8541,6 +8541,13 @@
 
 // End of protos/perfetto/trace/trigger.proto
 
+// Begin of protos/perfetto/trace/ui_state.proto
+
+// TODO(lalitm): this will be filled in later with definition from
+// go/trace-ui-state.
+message UiState {}
+// End of protos/perfetto/trace/ui_state.proto
+
 // Begin of protos/perfetto/trace/trace_packet.proto
 
 // TracePacket is the root object of a Perfeto trace.
@@ -8563,7 +8570,7 @@
 // See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
 //
 // Next reserved id: 14 (up to 15).
-// Next id: 78.
+// Next id: 79.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -8624,6 +8631,7 @@
     MemoryTrackerSnapshot memory_tracker_snapshot = 73;
     FrameTimelineEvent frame_timeline_event = 76;
     AndroidEnergyEstimationBreakdown android_energy_estimation_breakdown = 77;
+    UiState ui_state = 78;
 
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index 0924313..2428427 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -61,6 +61,7 @@
 import "protos/perfetto/trace/track_event/track_event.proto";
 import "protos/perfetto/trace/trigger.proto";
 import "protos/perfetto/trace/test_event.proto";
+import "protos/perfetto/trace/ui_state.proto";
 
 package perfetto.protos;
 
@@ -84,7 +85,7 @@
 // See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
 //
 // Next reserved id: 14 (up to 15).
-// Next id: 78.
+// Next id: 79.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -145,6 +146,7 @@
     MemoryTrackerSnapshot memory_tracker_snapshot = 73;
     FrameTimelineEvent frame_timeline_event = 76;
     AndroidEnergyEstimationBreakdown android_energy_estimation_breakdown = 77;
+    UiState ui_state = 78;
 
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
diff --git a/protos/perfetto/trace/ui_state.proto b/protos/perfetto/trace/ui_state.proto
new file mode 100644
index 0000000..0e50a6e
--- /dev/null
+++ b/protos/perfetto/trace/ui_state.proto
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+syntax = "proto2";
+
+package perfetto.protos;
+
+// TODO(lalitm): this will be filled in later with definition from
+// go/trace-ui-state.
+message UiState {}
\ No newline at end of file
diff --git a/src/base/string_utils.cc b/src/base/string_utils.cc
index 483f720..ac3b16b 100644
--- a/src/base/string_utils.cc
+++ b/src/base/string_utils.cc
@@ -30,6 +30,11 @@
 
 namespace perfetto {
 namespace base {
+namespace {
+constexpr char kBase64Table[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz0123456789+/";
+}
 
 // Locale-independant as possible version of strtod.
 double StrToD(const char* nptr, char** endptr) {
@@ -234,5 +239,43 @@
   return idx == std::string::npos ? str : str.substr(idx);
 }
 
+std::string Base64Encode(const void* raw, size_t size) {
+  // The following three cases are based on the tables in the example
+  // section in https://en.wikipedia.org/wiki/Base64. We process three
+  // input bytes at a time, emitting 4 output bytes at a time.
+  const uint8_t* ptr = static_cast<const uint8_t*>(raw);
+  size_t ii = 0;
+
+  std::string out;
+  out.reserve((size + 2) * 4 / 3);
+
+  // While possible, process three input bytes.
+  for (; ii + 3 <= size; ii += 3) {
+    uint32_t twentyfour_bits =
+        (uint32_t(ptr[ii]) << 16) | (uint32_t(ptr[ii + 1]) << 8) | ptr[ii + 2];
+    out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out.push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out.push_back(kBase64Table[twentyfour_bits & 0x3f]);
+  }
+  if (ii + 2 <= size) {  // Process two input bytes.
+    uint32_t twentyfour_bits =
+        (uint32_t(ptr[ii]) << 16) | (uint32_t(ptr[ii + 1]) << 8);
+    out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out.push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out.push_back('=');  // Emit padding.
+    return out;
+  }
+  if (ii + 1 <= size) {  // Process a single input byte.
+    uint32_t twentyfour_bits = (uint32_t(ptr[ii]) << 16);
+    out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out.push_back('=');  // Emit padding.
+    out.push_back('=');  // Emit padding.
+  }
+  return out;
+}
+
 }  // namespace base
 }  // namespace perfetto
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index e5164ea..51e2038 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -97,6 +97,8 @@
     "importers/proto/memory_tracker_snapshot_module.h",
     "importers/proto/memory_tracker_snapshot_parser.cc",
     "importers/proto/memory_tracker_snapshot_parser.h",
+    "importers/proto/metadata_module.cc",
+    "importers/proto/metadata_module.h",
     "importers/proto/metadata_tracker.cc",
     "importers/proto/metadata_tracker.h",
     "importers/proto/packet_sequence_state.cc",
diff --git a/src/trace_processor/importers/default_modules.cc b/src/trace_processor/importers/default_modules.cc
index 9e47ddc..19345cf 100644
--- a/src/trace_processor/importers/default_modules.cc
+++ b/src/trace_processor/importers/default_modules.cc
@@ -18,6 +18,7 @@
 #include "src/trace_processor/importers/ftrace/ftrace_module.h"
 #include "src/trace_processor/importers/proto/chrome_system_probes_module.h"
 #include "src/trace_processor/importers/proto/memory_tracker_snapshot_module.h"
+#include "src/trace_processor/importers/proto/metadata_module.h"
 #include "src/trace_processor/importers/proto/profile_module.h"
 #include "src/trace_processor/importers/proto/proto_importer_module.h"
 #include "src/trace_processor/importers/proto/track_event_module.h"
@@ -36,6 +37,7 @@
   context->modules.emplace_back(new ChromeSystemProbesModule(context));
   context->modules.emplace_back(new TrackEventModule(context));
   context->modules.emplace_back(new ProfileModule(context));
+  context->modules.emplace_back(new MetadataModule(context));
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/metadata_module.cc b/src/trace_processor/importers/proto/metadata_module.cc
new file mode 100644
index 0000000..2055261
--- /dev/null
+++ b/src/trace_processor/importers/proto/metadata_module.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/importers/proto/metadata_module.h"
+
+#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/importers/proto/metadata_tracker.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+using perfetto::protos::pbzero::TracePacket;
+
+MetadataModule::MetadataModule(TraceProcessorContext* context)
+    : context_(context) {
+  RegisterForField(TracePacket::kUiStateFieldNumber, context);
+}
+
+ModuleResult MetadataModule::TokenizePacket(
+    const protos::pbzero::TracePacket::Decoder& decoder,
+    TraceBlobView*,
+    int64_t,
+    PacketSequenceState*,
+    uint32_t field_id) {
+  switch (field_id) {
+    // TODO(lalitm): move other metadata field parsing here.
+    case TracePacket::kUiStateFieldNumber: {
+      auto ui_state = decoder.ui_state();
+      std::string base64 = base::Base64Encode(ui_state.data, ui_state.size);
+      StringId id = context_->storage->InternString(base::StringView(base64));
+      context_->metadata_tracker->SetMetadata(metadata::ui_state,
+                                              Variadic::String(id));
+      return ModuleResult::Handled();
+    }
+  }
+  return ModuleResult::Ignored();
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/metadata_module.h b/src/trace_processor/importers/proto/metadata_module.h
new file mode 100644
index 0000000..5182783
--- /dev/null
+++ b/src/trace_processor/importers/proto/metadata_module.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_MODULE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_MODULE_H_
+
+#include "perfetto/base/build_config.h"
+#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
+#include "src/trace_processor/importers/proto/proto_importer_module.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
+
+#include "protos/perfetto/trace/profiling/deobfuscation.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class MetadataModule : public ProtoImporterModule {
+ public:
+  explicit MetadataModule(TraceProcessorContext* context);
+
+  ModuleResult TokenizePacket(
+      const protos::pbzero::TracePacket::Decoder& decoder,
+      TraceBlobView* packet,
+      int64_t packet_timestamp,
+      PacketSequenceState* state,
+      uint32_t field_id) override;
+
+ private:
+  TraceProcessorContext* context_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_METADATA_MODULE_H_
diff --git a/src/trace_processor/storage/metadata.h b/src/trace_processor/storage/metadata.h
index 4f8df9d..ba68793 100644
--- a/src/trace_processor/storage/metadata.h
+++ b/src/trace_processor/storage/metadata.h
@@ -50,7 +50,8 @@
   F(all_data_source_started_ns,        KeyType::kSingle,  Variadic::kInt),    \
   F(tracing_started_ns,                KeyType::kSingle,  Variadic::kInt),    \
   F(tracing_disabled_ns,               KeyType::kSingle,  Variadic::kInt),    \
-  F(trace_config_pbtxt,                KeyType::kSingle,  Variadic::kString)
+  F(trace_config_pbtxt,                KeyType::kSingle,  Variadic::kString), \
+  F(ui_state,                          KeyType::kSingle,  Variadic::kString)
 // clang-format on
 
 // Compile time list of metadata items.