Merge "tp: remove machine_id from the counter table" into main
diff --git a/Android.bp b/Android.bp
index eadd00a..0d9015c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5832,6 +5832,7 @@
         "protos/perfetto/trace/android/view/surfacecontrol.proto",
         "protos/perfetto/trace/android/view/viewrootimpl.proto",
         "protos/perfetto/trace/android/view/windowlayoutparams.proto",
+        "protos/perfetto/trace/android/viewcapture.proto",
         "protos/perfetto/trace/android/winscope.proto",
         "protos/perfetto/trace/android/winscope_extensions.proto",
         "protos/perfetto/trace/android/winscope_extensions_impl.proto",
@@ -5871,6 +5872,7 @@
         "protos/perfetto/trace/android/view/surfacecontrol.proto",
         "protos/perfetto/trace/android/view/viewrootimpl.proto",
         "protos/perfetto/trace/android/view/windowlayoutparams.proto",
+        "protos/perfetto/trace/android/viewcapture.proto",
         "protos/perfetto/trace/android/winscope_extensions_impl.proto",
     ],
 }
@@ -5911,6 +5913,7 @@
         "external/perfetto/protos/perfetto/trace/android/view/surfacecontrol.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/android/view/viewrootimpl.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/android/view/windowlayoutparams.pbzero.cc",
+        "external/perfetto/protos/perfetto/trace/android/viewcapture.pbzero.cc",
         "external/perfetto/protos/perfetto/trace/android/winscope_extensions_impl.pbzero.cc",
     ],
 }
@@ -5951,6 +5954,7 @@
         "external/perfetto/protos/perfetto/trace/android/view/surfacecontrol.pbzero.h",
         "external/perfetto/protos/perfetto/trace/android/view/viewrootimpl.pbzero.h",
         "external/perfetto/protos/perfetto/trace/android/view/windowlayoutparams.pbzero.h",
+        "external/perfetto/protos/perfetto/trace/android/viewcapture.pbzero.h",
         "external/perfetto/protos/perfetto/trace/android/winscope_extensions_impl.pbzero.h",
     ],
     export_include_dirs: [
@@ -12498,6 +12502,7 @@
         "src/trace_processor/importers/proto/winscope/shell_transitions_tracker.cc",
         "src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.cc",
         "src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.cc",
+        "src/trace_processor/importers/proto/winscope/viewcapture_args_parser.cc",
         "src/trace_processor/importers/proto/winscope/winscope_module.cc",
     ],
 }
@@ -13090,6 +13095,7 @@
         "src/trace_processor/perfetto_sql/stdlib/android/suspend.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/thread.sql",
         "src/trace_processor/perfetto_sql/stdlib/android/winscope/inputmethod.sql",
+        "src/trace_processor/perfetto_sql/stdlib/android/winscope/viewcapture.sql",
         "src/trace_processor/perfetto_sql/stdlib/chrome/**/*.sql",
         "src/trace_processor/perfetto_sql/stdlib/common/args.sql",
         "src/trace_processor/perfetto_sql/stdlib/common/counters.sql",
@@ -13148,6 +13154,7 @@
         "src/trace_processor/perfetto_sql/stdlib/stack_trace/jit.sql",
         "src/trace_processor/perfetto_sql/stdlib/time/conversion.sql",
         "src/trace_processor/perfetto_sql/stdlib/v8/jit.sql",
+        "src/trace_processor/perfetto_sql/stdlib/viz/summary/counters.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql",
@@ -15821,6 +15828,7 @@
         "protos/perfetto/trace/android/view/surfacecontrol.proto",
         "protos/perfetto/trace/android/view/viewrootimpl.proto",
         "protos/perfetto/trace/android/view/windowlayoutparams.proto",
+        "protos/perfetto/trace/android/viewcapture.proto",
         "protos/perfetto/trace/android/winscope_extensions.proto",
         "protos/perfetto/trace/android/winscope_extensions_impl.proto",
         "protos/perfetto/trace/chrome/chrome_benchmark_metadata.proto",
@@ -17341,7 +17349,7 @@
     cmd: "mkdir -p $(genDir)/$(in) " +
         "&& $(location aprotoc) " +
         "--plugin=$(location protoc-gen-javastream) " +
-        "--javastream_opt=include_filter:perfetto.protos.TracePacket,perfetto.protos.ShellTransition,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogMessage,perfetto.protos.ProtoLogViewerConfig,perfetto.protos.ShellHandlerMapping,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogGroup,perfetto.protos.ProtoLogConfig,perfetto.protos.DataSourceConfig,perfetto.protos.InternedString,perfetto.protos.InternedData,perfetto.protos.ProtoLogLevel,perfetto.protos.TestEvent,perfetto.protos.TestEvent.TestPayload,perfetto.protos.TestConfig,perfetto.protos.TestConfig.DummyFields,perfetto.protos.WinscopeExtensionsImpl,perfetto.protos.InputMethodClientsTraceProto,perfetto.protos.InputMethodManagerServiceTraceProto,perfetto.protos.InputMethodServiceTraceProto " +
+        "--javastream_opt=include_filter:perfetto.protos.TracePacket,perfetto.protos.ShellTransition,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogMessage,perfetto.protos.ProtoLogViewerConfig,perfetto.protos.ShellHandlerMapping,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogGroup,perfetto.protos.ProtoLogConfig,perfetto.protos.DataSourceConfig,perfetto.protos.InternedString,perfetto.protos.InternedData,perfetto.protos.ProtoLogLevel,perfetto.protos.TestEvent,perfetto.protos.TestEvent.TestPayload,perfetto.protos.TestConfig,perfetto.protos.TestConfig.DummyFields,perfetto.protos.WinscopeExtensionsImpl,perfetto.protos.InputMethodClientsTraceProto,perfetto.protos.InputMethodManagerServiceTraceProto,perfetto.protos.InputMethodServiceTraceProto,perfetto.protos.ViewCapture " +
         "--javastream_out=$(genDir)/$(in) " +
         "-Iexternal/protobuf/src " +
         "-Iexternal/perfetto " +
diff --git a/Android.bp.extras b/Android.bp.extras
index 56cfcdd..c822224 100644
--- a/Android.bp.extras
+++ b/Android.bp.extras
@@ -185,7 +185,7 @@
     cmd: "mkdir -p $(genDir)/$(in) " +
         "&& $(location aprotoc) " +
         "--plugin=$(location protoc-gen-javastream) " +
-        "--javastream_opt=include_filter:perfetto.protos.TracePacket,perfetto.protos.ShellTransition,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogMessage,perfetto.protos.ProtoLogViewerConfig,perfetto.protos.ShellHandlerMapping,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogGroup,perfetto.protos.ProtoLogConfig,perfetto.protos.DataSourceConfig,perfetto.protos.InternedString,perfetto.protos.InternedData,perfetto.protos.ProtoLogLevel,perfetto.protos.TestEvent,perfetto.protos.TestEvent.TestPayload,perfetto.protos.TestConfig,perfetto.protos.TestConfig.DummyFields,perfetto.protos.WinscopeExtensionsImpl,perfetto.protos.InputMethodClientsTraceProto,perfetto.protos.InputMethodManagerServiceTraceProto,perfetto.protos.InputMethodServiceTraceProto " +
+        "--javastream_opt=include_filter:perfetto.protos.TracePacket,perfetto.protos.ShellTransition,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogMessage,perfetto.protos.ProtoLogViewerConfig,perfetto.protos.ShellHandlerMapping,perfetto.protos.ShellHandlerMappings,perfetto.protos.ProtoLogGroup,perfetto.protos.ProtoLogConfig,perfetto.protos.DataSourceConfig,perfetto.protos.InternedString,perfetto.protos.InternedData,perfetto.protos.ProtoLogLevel,perfetto.protos.TestEvent,perfetto.protos.TestEvent.TestPayload,perfetto.protos.TestConfig,perfetto.protos.TestConfig.DummyFields,perfetto.protos.WinscopeExtensionsImpl,perfetto.protos.InputMethodClientsTraceProto,perfetto.protos.InputMethodManagerServiceTraceProto,perfetto.protos.InputMethodServiceTraceProto,perfetto.protos.ViewCapture " +
         "--javastream_out=$(genDir)/$(in) " +
         "-Iexternal/protobuf/src " +
         "-Iexternal/perfetto " +
diff --git a/BUILD b/BUILD
index e4e8e81..3153aaf 100644
--- a/BUILD
+++ b/BUILD
@@ -1777,6 +1777,8 @@
         "src/trace_processor/importers/proto/winscope/surfaceflinger_layers_parser.h",
         "src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.cc",
         "src/trace_processor/importers/proto/winscope/surfaceflinger_transactions_parser.h",
+        "src/trace_processor/importers/proto/winscope/viewcapture_args_parser.cc",
+        "src/trace_processor/importers/proto/winscope/viewcapture_args_parser.h",
         "src/trace_processor/importers/proto/winscope/winscope_module.cc",
         "src/trace_processor/importers/proto/winscope/winscope_module.h",
     ],
@@ -2509,6 +2511,7 @@
     name = "src_trace_processor_perfetto_sql_stdlib_android_winscope_winscope",
     srcs = [
         "src/trace_processor/perfetto_sql/stdlib/android/winscope/inputmethod.sql",
+        "src/trace_processor/perfetto_sql/stdlib/android/winscope/viewcapture.sql",
     ],
 )
 
@@ -2751,6 +2754,7 @@
 perfetto_filegroup(
     name = "src_trace_processor_perfetto_sql_stdlib_viz_summary_summary",
     srcs = [
+        "src/trace_processor/perfetto_sql/stdlib/viz/summary/counters.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/processes.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/slices.sql",
         "src/trace_processor/perfetto_sql/stdlib/viz/summary/threads.sql",
@@ -4848,6 +4852,7 @@
         "protos/perfetto/trace/android/view/surfacecontrol.proto",
         "protos/perfetto/trace/android/view/viewrootimpl.proto",
         "protos/perfetto/trace/android/view/windowlayoutparams.proto",
+        "protos/perfetto/trace/android/viewcapture.proto",
         "protos/perfetto/trace/android/winscope_extensions_impl.proto",
     ],
     visibility = [
diff --git a/protos/perfetto/trace/android/BUILD.gn b/protos/perfetto/trace/android/BUILD.gn
index 90234da..0902ceb 100644
--- a/protos/perfetto/trace/android/BUILD.gn
+++ b/protos/perfetto/trace/android/BUILD.gn
@@ -89,6 +89,7 @@
     "view/surfacecontrol.proto",
     "view/viewrootimpl.proto",
     "view/windowlayoutparams.proto",
+    "viewcapture.proto",
     "winscope_extensions_impl.proto",
   ]
   import_dirs = [ "${perfetto_protobuf_src_dir}" ]
diff --git a/protos/perfetto/trace/android/viewcapture.proto b/protos/perfetto/trace/android/viewcapture.proto
new file mode 100644
index 0000000..d5efb6c
--- /dev/null
+++ b/protos/perfetto/trace/android/viewcapture.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 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;
+
+message ViewCapture {
+  optional int32 package_name_iid = 1;
+  optional int32 window_name_iid = 2;
+  repeated View views = 3;
+
+  message View {
+    optional int32 id = 1;
+    optional int32 parent_id = 2;
+    optional int32 hashcode = 3;
+    optional int32 view_id_iid = 4;
+    optional int32 class_name_iid = 5;
+
+    optional int32 left = 6;
+    optional int32 top = 7;
+    optional int32 width = 8;
+    optional int32 height = 9;
+    optional int32 scroll_x = 10;
+    optional int32 scroll_y = 11;
+
+    optional float translation_x = 12;
+    optional float translation_y = 13;
+    optional float scale_x = 14;
+    optional float scale_y = 15;
+    optional float alpha = 16;
+
+    optional bool will_not_draw = 17;
+    optional bool clip_children = 18;
+    optional int32 visibility = 19;
+
+    optional float elevation = 20;
+  }
+}
diff --git a/protos/perfetto/trace/android/winscope.proto b/protos/perfetto/trace/android/winscope.proto
index d7927d8..50723ee 100644
--- a/protos/perfetto/trace/android/winscope.proto
+++ b/protos/perfetto/trace/android/winscope.proto
@@ -22,6 +22,7 @@
 import "protos/perfetto/trace/android/shell_transition.proto";
 import "protos/perfetto/trace/android/surfaceflinger_layers.proto";
 import "protos/perfetto/trace/android/surfaceflinger_transactions.proto";
+import "protos/perfetto/trace/android/viewcapture.proto";
 import "protos/perfetto/trace/android/winscope_extensions_impl.proto";
 
 // This file is used to generated descriptors for all the winscope protos.
@@ -32,4 +33,5 @@
   optional ShellTransition shell_transition = 3;
   optional ProtoLogMessage protolog_message = 4;
   optional WinscopeExtensionsImpl winscope_extensions = 5;
+  optional ViewCapture viewcapture = 6;
 }
diff --git a/protos/perfetto/trace/android/winscope_extensions.proto b/protos/perfetto/trace/android/winscope_extensions.proto
index 76e6c9e..a27a5c5 100644
--- a/protos/perfetto/trace/android/winscope_extensions.proto
+++ b/protos/perfetto/trace/android/winscope_extensions.proto
@@ -19,5 +19,5 @@
 package perfetto.protos;
 
 message WinscopeExtensions {
-  extensions 1 to 3;
+  extensions 1 to 4;
 }
diff --git a/protos/perfetto/trace/android/winscope_extensions_impl.proto b/protos/perfetto/trace/android/winscope_extensions_impl.proto
index bfc18e9..0d33163 100644
--- a/protos/perfetto/trace/android/winscope_extensions_impl.proto
+++ b/protos/perfetto/trace/android/winscope_extensions_impl.proto
@@ -20,6 +20,7 @@
 
 import public "protos/perfetto/trace/android/winscope_extensions.proto";
 import "protos/perfetto/trace/android/inputmethodeditor.proto";
+import "protos/perfetto/trace/android/viewcapture.proto";
 
 message WinscopeExtensionsImpl {
   extend WinscopeExtensions {
@@ -27,5 +28,6 @@
     optional InputMethodServiceTraceProto inputmethod_service = 2;
     optional InputMethodManagerServiceTraceProto inputmethod_manager_service =
         3;
+    optional ViewCapture viewcapture = 4;
   }
 }
diff --git a/protos/perfetto/trace/interned_data/interned_data.proto b/protos/perfetto/trace/interned_data/interned_data.proto
index 2cae9c6..6c11be8 100644
--- a/protos/perfetto/trace/interned_data/interned_data.proto
+++ b/protos/perfetto/trace/interned_data/interned_data.proto
@@ -55,7 +55,7 @@
 // emitted proactively in advance of referring to them in later packets.
 //
 // Next reserved id: 8 (up to 15).
-// Next id: 36.
+// Next id: 42.
 message InternedData {
   // TODO(eseckler): Replace iid fields inside interned messages with
   // map<iid, message> type fields in InternedData.
@@ -137,4 +137,10 @@
   repeated InternedString protolog_string_args = 36;
   // Interned protolog stacktraces.
   repeated InternedString protolog_stacktrace = 37;
+
+  // viewcapture
+  repeated InternedString viewcapture_package_name = 38;
+  repeated InternedString viewcapture_window_name = 39;
+  repeated InternedString viewcapture_view_id = 40;
+  repeated InternedString viewcapture_class_name = 41;
 }
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 20612e4..dc213d7 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -5819,7 +5819,7 @@
 // Begin of protos/perfetto/trace/android/winscope_extensions.proto
 
 message WinscopeExtensions {
-  extensions 1 to 3;
+  extensions 1 to 4;
 }
 
 // End of protos/perfetto/trace/android/winscope_extensions.proto
@@ -12820,7 +12820,7 @@
 // emitted proactively in advance of referring to them in later packets.
 //
 // Next reserved id: 8 (up to 15).
-// Next id: 36.
+// Next id: 42.
 message InternedData {
   // TODO(eseckler): Replace iid fields inside interned messages with
   // map<iid, message> type fields in InternedData.
@@ -12902,6 +12902,12 @@
   repeated InternedString protolog_string_args = 36;
   // Interned protolog stacktraces.
   repeated InternedString protolog_stacktrace = 37;
+
+  // viewcapture
+  repeated InternedString viewcapture_package_name = 38;
+  repeated InternedString viewcapture_window_name = 39;
+  repeated InternedString viewcapture_view_id = 40;
+  repeated InternedString viewcapture_class_name = 41;
 }
 
 // End of protos/perfetto/trace/interned_data/interned_data.proto
diff --git a/src/trace_processor/importers/common/args_tracker.h b/src/trace_processor/importers/common/args_tracker.h
index 964a6ad..8b8d35c 100644
--- a/src/trace_processor/importers/common/args_tracker.h
+++ b/src/trace_processor/importers/common/args_tracker.h
@@ -154,6 +154,10 @@
         context_->storage->mutable_surfaceflinger_transactions_table(), id);
   }
 
+  BoundInserter AddArgsTo(tables::ViewCaptureTable::Id id) {
+    return AddArgsTo(context_->storage->mutable_viewcapture_table(), id);
+  }
+
   BoundInserter AddArgsTo(tables::WindowManagerShellTransitionsTable::Id id) {
     return AddArgsTo(
         context_->storage->mutable_window_manager_shell_transitions_table(),
diff --git a/src/trace_processor/importers/proto/winscope/BUILD.gn b/src/trace_processor/importers/proto/winscope/BUILD.gn
index 593b749..d22dee0 100644
--- a/src/trace_processor/importers/proto/winscope/BUILD.gn
+++ b/src/trace_processor/importers/proto/winscope/BUILD.gn
@@ -16,6 +16,8 @@
 
 source_set("full") {
   sources = [
+    "viewcapture_args_parser.cc",
+    "viewcapture_args_parser.h",
     "protolog_messages_tracker.cc",
     "protolog_messages_tracker.h",
     "protolog_parser.cc",
diff --git a/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.cc b/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.cc
new file mode 100644
index 0000000..ed88163
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2024 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/winscope/viewcapture_args_parser.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+ViewCaptureArgsParser::ViewCaptureArgsParser(
+    int64_t packet_timestamp,
+    ArgsTracker::BoundInserter& inserter,
+    TraceStorage& storage,
+    PacketSequenceStateGeneration* sequence_state)
+    : ArgsParser(packet_timestamp, inserter, storage, sequence_state),
+      storage_{storage} {}
+
+void ViewCaptureArgsParser::AddInteger(const Key& key, int64_t value) {
+  if (TryAddDeinternedString(key, static_cast<uint64_t>(value))) {
+    return;
+  }
+  ArgsParser::AddInteger(key, value);
+}
+
+void ViewCaptureArgsParser::AddUnsignedInteger(const Key& key, uint64_t value) {
+  if (TryAddDeinternedString(key, value)) {
+    return;
+  }
+  ArgsParser::AddUnsignedInteger(key, value);
+}
+
+bool ViewCaptureArgsParser::TryAddDeinternedString(const Key& key,
+                                                   uint64_t iid) {
+  bool is_interned_field = base::EndsWith(key.key, "_iid");
+  if (!is_interned_field) {
+    return false;
+  }
+
+  const auto deintern_key = key.key.substr(0, key.key.size() - 4);
+  const auto deintern_flat_key =
+      key.flat_key.substr(0, key.flat_key.size() - 4);
+  const auto deintern_key_combined = Key{deintern_flat_key, deintern_key};
+  const auto deintern_val = TryDeinternString(key, iid);
+
+  if (!deintern_val) {
+    ArgsParser::AddString(
+        deintern_key_combined,
+        protozero::ConstChars{ERROR_MSG.data(), ERROR_MSG.size()});
+    storage_.IncrementStats(
+        stats::winscope_viewcapture_missing_interned_string_parse_errors);
+    return false;
+  }
+
+  ArgsParser::AddString(deintern_key_combined, *deintern_val);
+  return true;
+}
+
+std::optional<protozero::ConstChars> ViewCaptureArgsParser::TryDeinternString(
+    const Key& key,
+    uint64_t iid) {
+  if (base::EndsWith(key.key, "class_name_iid")) {
+    auto* decoder =
+        seq_state()
+            ->LookupInternedMessage<
+                protos::pbzero::InternedData::kViewcaptureClassNameFieldNumber,
+                protos::pbzero::InternedString>(iid);
+    if (decoder) {
+      return protozero::ConstChars{
+          reinterpret_cast<const char*>(decoder->str().data),
+          decoder->str().size};
+    }
+  } else if (base::EndsWith(key.key, "package_name_iid")) {
+    auto* decoder =
+        seq_state()
+            ->LookupInternedMessage<protos::pbzero::InternedData::
+                                        kViewcapturePackageNameFieldNumber,
+                                    protos::pbzero::InternedString>(iid);
+    if (decoder) {
+      return protozero::ConstChars{
+          reinterpret_cast<const char*>(decoder->str().data),
+          decoder->str().size};
+    }
+  } else if (base::EndsWith(key.key, "view_id_iid")) {
+    auto* decoder =
+        seq_state()
+            ->LookupInternedMessage<
+                protos::pbzero::InternedData::kViewcaptureViewIdFieldNumber,
+                protos::pbzero::InternedString>(iid);
+    if (decoder) {
+      return protozero::ConstChars{
+          reinterpret_cast<const char*>(decoder->str().data),
+          decoder->str().size};
+    }
+  } else if (base::EndsWith(key.key, "window_name_iid")) {
+    auto* decoder =
+        seq_state()
+            ->LookupInternedMessage<
+                protos::pbzero::InternedData::kViewcaptureWindowNameFieldNumber,
+                protos::pbzero::InternedString>(iid);
+    if (decoder) {
+      return protozero::ConstChars{
+          reinterpret_cast<const char*>(decoder->str().data),
+          decoder->str().size};
+    }
+  }
+
+  return std::nullopt;
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.h b/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.h
new file mode 100644
index 0000000..32b76b6
--- /dev/null
+++ b/src/trace_processor/importers/proto/winscope/viewcapture_args_parser.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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_WINSCOPE_VIEWCAPTURE_ARGS_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_VIEWCAPTURE_ARGS_PARSER_H_
+
+#include <optional>
+
+#include "src/trace_processor/importers/proto/args_parser.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Specialized args parser to de-intern ViewCapture strings
+class ViewCaptureArgsParser : public ArgsParser {
+ public:
+  using Key = ArgsParser::Key;
+
+  ViewCaptureArgsParser(int64_t packet_timestamp,
+                        ArgsTracker::BoundInserter& inserter,
+                        TraceStorage& storage,
+                        PacketSequenceStateGeneration* sequence_state);
+  void AddInteger(const Key&, int64_t) override;
+  void AddUnsignedInteger(const Key&, uint64_t) override;
+
+ private:
+  bool TryAddDeinternedString(const Key&, uint64_t);
+  std::optional<protozero::ConstChars> TryDeinternString(const Key&, uint64_t);
+
+  const base::StringView ERROR_MSG{"STRING DE-INTERNING ERROR"};
+  TraceStorage& storage_;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_WINSCOPE_VIEWCAPTURE_ARGS_PARSER_H_
diff --git a/src/trace_processor/importers/proto/winscope/winscope_module.cc b/src/trace_processor/importers/proto/winscope/winscope_module.cc
index 4bf2723..81c7a59 100644
--- a/src/trace_processor/importers/proto/winscope/winscope_module.cc
+++ b/src/trace_processor/importers/proto/winscope/winscope_module.cc
@@ -18,6 +18,7 @@
 #include "protos/perfetto/trace/android/winscope_extensions.pbzero.h"
 #include "protos/perfetto/trace/android/winscope_extensions_impl.pbzero.h"
 #include "src/trace_processor/importers/proto/args_parser.h"
+#include "src/trace_processor/importers/proto/winscope/viewcapture_args_parser.h"
 #include "src/trace_processor/importers/proto/winscope/winscope.descriptor.h"
 
 namespace perfetto {
@@ -76,13 +77,15 @@
           decoder.protolog_viewer_config());
       return;
     case TracePacket::kWinscopeExtensionsFieldNumber:
-      ParseWinscopeExtensionsData(decoder.winscope_extensions(), timestamp);
+      ParseWinscopeExtensionsData(decoder.winscope_extensions(), timestamp,
+                                  data);
       return;
   }
 }
 
 void WinscopeModule::ParseWinscopeExtensionsData(protozero::ConstBytes blob,
-                                                 int64_t timestamp) {
+                                                 int64_t timestamp,
+                                                 const TracePacketData& data) {
   WinscopeExtensionsImpl::Decoder decoder(blob.data, blob.size);
 
   if (auto field =
@@ -97,6 +100,11 @@
                  WinscopeExtensionsImpl::kInputmethodServiceFieldNumber);
              field.valid()) {
     ParseInputMethodServiceData(timestamp, field.as_bytes());
+  } else if (field =
+                 decoder.Get(WinscopeExtensionsImpl::kViewcaptureFieldNumber);
+             field.valid()) {
+    ParseViewCaptureData(timestamp, field.as_bytes(),
+                         data.sequence_state.get());
   }
 }
 
@@ -159,5 +167,24 @@
   }
 }
 
+void WinscopeModule::ParseViewCaptureData(
+    int64_t timestamp,
+    protozero::ConstBytes blob,
+    PacketSequenceStateGeneration* sequence_state) {
+  tables::ViewCaptureTable::Row row;
+  row.ts = timestamp;
+  auto rowId = context_->storage->mutable_viewcapture_table()->Insert(row).id;
+
+  ArgsTracker tracker(context_);
+  auto inserter = tracker.AddArgsTo(rowId);
+  ViewCaptureArgsParser writer(timestamp, inserter, *context_->storage.get(),
+                               sequence_state);
+  base::Status status = args_parser_.ParseMessage(
+      blob, kViewCaptureProtoName, nullptr /* parse all fields */, writer);
+  if (!status.ok()) {
+    context_->storage->IncrementStats(stats::winscope_viewcapture_parse_errors);
+  }
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/proto/winscope/winscope_module.h b/src/trace_processor/importers/proto/winscope/winscope_module.h
index c77fcb4..7f6ae08 100644
--- a/src/trace_processor/importers/proto/winscope/winscope_module.h
+++ b/src/trace_processor/importers/proto/winscope/winscope_module.h
@@ -42,21 +42,25 @@
 
  private:
   void ParseWinscopeExtensionsData(protozero::ConstBytes blob,
-                                   int64_t timestamp);
+                                   int64_t timestamp,
+                                   const TracePacketData&);
   void ParseInputMethodClientsData(int64_t timestamp,
                                    protozero::ConstBytes blob);
   void ParseInputMethodManagerServiceData(int64_t timestamp,
                                           protozero::ConstBytes blob);
   void ParseInputMethodServiceData(int64_t timestamp,
                                    protozero::ConstBytes blob);
+  void ParseViewCaptureData(int64_t timestamp,
+                            protozero::ConstBytes blob,
+                            PacketSequenceStateGeneration* sequence_state);
 
   static constexpr auto* kInputMethodClientsProtoName =
       ".perfetto.protos.InputMethodClientsTraceProto";
   static constexpr auto* kInputMethodManagerServiceProtoName =
       ".perfetto.protos.InputMethodManagerServiceTraceProto";
-
   static constexpr auto* kInputMethodServiceProtoName =
       ".perfetto.protos.InputMethodServiceTraceProto";
+  static constexpr auto* kViewCaptureProtoName = ".perfetto.protos.ViewCapture";
 
   TraceProcessorContext* const context_;
   DescriptorPool pool_;
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/winscope/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/winscope/BUILD.gn
index 93abe35..ff7e3ef 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/winscope/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/winscope/BUILD.gn
@@ -17,5 +17,6 @@
 perfetto_sql_source_set("winscope") {
   sources = [
     "inputmethod.sql",
+    "viewcapture.sql",
   ]
 }
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/winscope/viewcapture.sql b/src/trace_processor/perfetto_sql/stdlib/android/winscope/viewcapture.sql
new file mode 100644
index 0000000..77e68b5
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/winscope/viewcapture.sql
@@ -0,0 +1,29 @@
+--
+-- Copyright 2024 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
+--
+--     https://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.
+
+-- Android viewcapture (from android.viewcapture data source).
+CREATE PERFETTO VIEW android_viewcapture(
+  -- Snapshot id
+  id INT,
+  -- Timestamp when the snapshot was triggered
+  ts INT,
+  -- Extra args parsed from the proto message
+  arg_set_id INT
+) AS
+SELECT
+  id,
+  ts,
+  arg_set_id
+FROM __intrinsic_viewcapture;
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
index 3f664bd..b02d5a7 100644
--- a/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/BUILD.gn
@@ -16,6 +16,7 @@
 
 perfetto_sql_source_set("summary") {
   sources = [
+    "counters.sql",
     "processes.sql",
     "slices.sql",
     "threads.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/viz/summary/counters.sql b/src/trace_processor/perfetto_sql/stdlib/viz/summary/counters.sql
new file mode 100644
index 0000000..7ae6d13
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/viz/summary/counters.sql
@@ -0,0 +1,18 @@
+--
+-- Copyright 2024 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
+--
+--     https://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.
+
+CREATE PERFETTO TABLE _counter_track_summary AS
+SELECT DISTINCT track_id as id
+FROM counter;
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index c8d58ca..6238455 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -349,6 +349,14 @@
   F(winscope_protolog_missing_interned_stacktrace_parse_errors,                \
                                           kSingle,  kInfo,     kAnalysis,      \
       "Failed to find interned ProtoLog stacktrace."),                         \
+  F(winscope_viewcapture_parse_errors,                                         \
+                                          kSingle,  kInfo,     kAnalysis,      \
+      "ViewCapture packet has unknown fields, which results in some "          \
+      "arguments missing. You may need a newer version of trace processor "    \
+      "to parse them."),                                                       \
+  F(winscope_viewcapture_missing_interned_string_parse_errors,                 \
+                                          kSingle,  kInfo,     kAnalysis,      \
+      "Failed to find interned ViewCapture string."),                          \
   F(jit_unknown_frame,                    kSingle,  kDataLoss, kTrace,         \
       "Indicates that we were unable to determine the function for a frame in "\
       "a jitted memory region"),                                               \
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index ff280e1..efc667e 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -845,6 +845,13 @@
     return &surfaceflinger_transactions_table_;
   }
 
+  const tables::ViewCaptureTable& viewcapture_table() const {
+    return viewcapture_table_;
+  }
+  tables::ViewCaptureTable* mutable_viewcapture_table() {
+    return &viewcapture_table_;
+  }
+
   const tables::WindowManagerShellTransitionsTable&
   window_manager_shell_transitions_table() const {
     return window_manager_shell_transitions_table_;
@@ -1147,6 +1154,7 @@
   tables::SurfaceFlingerLayerTable surfaceflinger_layer_table_{&string_pool_};
   tables::SurfaceFlingerTransactionsTable surfaceflinger_transactions_table_{
       &string_pool_};
+  tables::ViewCaptureTable viewcapture_table_{&string_pool_};
   tables::WindowManagerShellTransitionsTable
       window_manager_shell_transitions_table_{&string_pool_};
   tables::WindowManagerShellTransitionHandlersTable
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index 6093c83..2902edc 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -139,15 +139,16 @@
 InputMethodClientsTable::~InputMethodClientsTable() = default;
 InputMethodManagerServiceTable::~InputMethodManagerServiceTable() = default;
 InputMethodServiceTable::~InputMethodServiceTable() = default;
+ProtoLogTable::~ProtoLogTable() = default;
 SurfaceFlingerLayersSnapshotTable::~SurfaceFlingerLayersSnapshotTable() =
     default;
 SurfaceFlingerLayerTable::~SurfaceFlingerLayerTable() = default;
 SurfaceFlingerTransactionsTable::~SurfaceFlingerTransactionsTable() = default;
+ViewCaptureTable::~ViewCaptureTable() = default;
 WindowManagerShellTransitionsTable::~WindowManagerShellTransitionsTable() =
     default;
 WindowManagerShellTransitionHandlersTable::
     ~WindowManagerShellTransitionHandlersTable() = default;
-ProtoLogTable::~ProtoLogTable() = default;
 
 }  // namespace tables
 
diff --git a/src/trace_processor/tables/winscope_tables.py b/src/trace_processor/tables/winscope_tables.py
index 8c058aa..15b93bb 100644
--- a/src/trace_processor/tables/winscope_tables.py
+++ b/src/trace_processor/tables/winscope_tables.py
@@ -117,6 +117,22 @@
             'arg_set_id': 'Extra args parsed from the proto message',
         }))
 
+VIEWCAPTURE_TABLE = Table(
+    python_module=__file__,
+    class_name='ViewCaptureTable',
+    sql_name='__intrinsic_viewcapture',
+    columns=[
+        C('ts', CppInt64()),
+        C('arg_set_id', CppUint32()),
+    ],
+    tabledoc=TableDoc(
+        doc='ViewCapture',
+        group='Winscope',
+        columns={
+            'ts': 'The timestamp the views were captured',
+            'arg_set_id': 'Extra args parsed from the proto message',
+        }))
+
 WINDOW_MANAGER_SHELL_TRANSITIONS_TABLE = Table(
     python_module=__file__,
     class_name='WindowManagerShellTransitionsTable',
@@ -182,6 +198,7 @@
     SURFACE_FLINGER_LAYERS_SNAPSHOT_TABLE,
     SURFACE_FLINGER_LAYER_TABLE,
     SURFACE_FLINGER_TRANSACTIONS_TABLE,
+    VIEWCAPTURE_TABLE,
     WINDOW_MANAGER_SHELL_TRANSITIONS_TABLE,
     WINDOW_MANAGER_SHELL_TRANSITION_HANDLERS_TABLE,
 ]
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 17b47e1..337512d 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -892,6 +892,8 @@
   RegisterStaticTable(storage->surfaceflinger_layer_table());
   RegisterStaticTable(storage->surfaceflinger_transactions_table());
 
+  RegisterStaticTable(storage->viewcapture_table());
+
   RegisterStaticTable(storage->window_manager_shell_transitions_table());
   RegisterStaticTable(
       storage->window_manager_shell_transition_handlers_table());
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index f75e689..a531d3a 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -57,6 +57,7 @@
 from diff_tests.parser.android.tests_shell_transitions import ShellTransitions
 from diff_tests.parser.android.tests_surfaceflinger_layers import SurfaceFlingerLayers
 from diff_tests.parser.android.tests_surfaceflinger_transactions import SurfaceFlingerTransactions
+from diff_tests.parser.android.tests_viewcapture import ViewCapture
 from diff_tests.parser.atrace.tests import Atrace
 from diff_tests.parser.atrace.tests_error_handling import AtraceErrorHandling
 from diff_tests.parser.chrome.tests import ChromeParser
@@ -207,6 +208,7 @@
       *ShellTransitions(index_path, 'parser/android',
                         'ShellTransitions').fetch(),
       *ProtoLog(index_path, 'parser/android', 'ProtoLog').fetch(),
+      *ViewCapture(index_path, 'parser/android', 'ViewCapture').fetch(),
       *TrackEvent(index_path, 'parser/track_event', 'TrackEvent').fetch(),
       *TranslatedArgs(index_path, 'parser/translated_args',
                       'TranslatedArgs').fetch(),
diff --git a/test/trace_processor/diff_tests/parser/android/tests_viewcapture.py b/test/trace_processor/diff_tests/parser/android/tests_viewcapture.py
new file mode 100644
index 0000000..e089ecb
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/android/tests_viewcapture.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# Copyright (C) 2024 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 a
+#
+#      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.
+
+from python.generators.diff_tests.testing import Path
+from python.generators.diff_tests.testing import Csv
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class ViewCapture(TestSuite):
+
+  def test_has_expected_rows(self):
+    return DiffTestBlueprint(
+        trace=Path('viewcapture.textproto'),
+        query="""
+        INCLUDE PERFETTO MODULE android.winscope.viewcapture;
+        SELECT
+          id, ts
+        FROM
+          android_viewcapture;
+        """,
+        out=Csv("""
+        "id","ts"
+        0,448881087865
+        1,448883575576
+        """))
+
+  def test_has_expected_args(self):
+    return DiffTestBlueprint(
+        trace=Path('viewcapture.textproto'),
+        query="""
+        INCLUDE PERFETTO MODULE android.winscope.viewcapture;
+        SELECT
+          args.key, args.display_value
+        FROM
+          android_viewcapture AS vc JOIN args ON vc.arg_set_id = args.arg_set_id
+        WHERE vc.id = 0
+        ORDER BY args.key
+        LIMIT 10;
+        """,
+        out=Csv("""
+        "key","display_value"
+        "package_name","com.google.android.apps.nexuslauncher"
+        "views[0].alpha","1.0"
+        "views[0].class_name","com.android.internal.policy.PhoneWindow@6cec234"
+        "views[0].hashcode","182652084"
+        "views[0].height","2400"
+        "views[0].parent_id","-1"
+        "views[0].scale_x","1.0"
+        "views[0].scale_y","1.0"
+        "views[0].view_id","NO_ID"
+        "views[0].width","1080"
+        """))
+
+  def test_handle_string_deinterning_errors(self):
+    return DiffTestBlueprint(
+        trace=Path('viewcapture.textproto'),
+        query="""
+        INCLUDE PERFETTO MODULE android.winscope.viewcapture;
+        SELECT
+          args.key, args.display_value
+        FROM
+          android_viewcapture AS vc JOIN args ON vc.arg_set_id = args.arg_set_id
+        WHERE vc.id = 1 and args.key = 'views[1].class_name';
+        """,
+        out=Csv("""
+        "key","display_value"
+        "views[1].class_name","STRING DE-INTERNING ERROR"
+        """))
diff --git a/test/trace_processor/diff_tests/parser/android/viewcapture.textproto b/test/trace_processor/diff_tests/parser/android/viewcapture.textproto
new file mode 100644
index 0000000..7f484b8
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/android/viewcapture.textproto
@@ -0,0 +1,128 @@
+packet {
+  clock_snapshot {
+    primary_trace_clock: BUILTIN_CLOCK_BOOTTIME
+    clocks {
+      clock_id: 6
+      timestamp: 448243204726
+    }
+    clocks {
+      clock_id: 2
+      timestamp: 1716366701256000218
+    }
+    clocks {
+      clock_id: 4
+      timestamp: 448237110366
+    }
+    clocks {
+      clock_id: 1
+      timestamp: 1716366701262094741
+    }
+    clocks {
+      clock_id: 3
+      timestamp: 448243204971
+    }
+    clocks {
+      clock_id: 5
+      timestamp: 448243205052
+    }
+  }
+  trusted_uid: 9999
+  trusted_packet_sequence_id: 1
+}
+
+packet {
+  first_packet_on_sequence: true
+  timestamp: 448881087865
+  winscope_extensions {
+    [perfetto.protos.WinscopeExtensionsImpl.viewcapture] {
+      package_name_iid: 1
+      window_name_iid: 1
+      views {
+        parent_id: -1
+        hashcode: 182652084
+        view_id_iid: 1
+        class_name_iid: 1
+        width: 1080
+        height: 2400
+        scale_x: 1.000000
+        scale_y: 1.000000
+        alpha: 1.000000
+        will_not_draw: true
+      }
+      views {
+        id: 1
+        hashcode: 130248925
+        view_id_iid: 3
+        class_name_iid: 2
+        width: 1080
+        height: 2400
+        scale_x: 1.000000
+        scale_y: 1.000000
+        alpha: 1.000000
+        will_not_draw: true
+      }
+    }
+  }
+  sequence_flags: 3
+  interned_data {
+    viewcapture_class_name {
+      iid: 1
+      str: "com.android.internal.policy.PhoneWindow@6cec234"
+    }
+    viewcapture_class_name {
+      iid: 2
+      str: "com.android.internal.policy.DecorView"
+    }
+    viewcapture_package_name {
+      iid: 1
+      str: "com.google.android.apps.nexuslauncher"
+    }
+    viewcapture_view_id {
+      iid: 1
+      str: "NO_ID"
+    }
+  }
+  trusted_uid: 10230
+  trusted_packet_sequence_id: 2
+  trusted_pid: 2688
+  previous_packet_dropped: true
+}
+
+packet {
+  timestamp: 448883575576
+  winscope_extensions {
+    [perfetto.protos.WinscopeExtensionsImpl.viewcapture] {
+      package_name_iid: 1
+      window_name_iid: 1
+      views {
+        parent_id: -1
+        hashcode: 182652084
+        view_id_iid: 1
+        class_name_iid: 1
+        width: 1080
+        height: 2400
+        scale_x: 1.000000
+        scale_y: 1.000000
+        alpha: 1.000000
+        will_not_draw: true
+      }
+      views {
+        id: 1
+        hashcode: 130248925
+        view_id_iid: 1
+        # triggers de-interning error because of unavailable iid-to-string mapping
+        class_name_iid: 3
+        width: 1080
+        height: 2400
+        scale_x: 1.000000
+        scale_y: 1.000000
+        alpha: 1.000000
+        will_not_draw: true
+      }
+    }
+  }
+  sequence_flags: 2
+  trusted_uid: 10230
+  trusted_packet_sequence_id: 2
+  trusted_pid: 2688
+}
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index a3e6a59..c0957e2 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -1025,6 +1025,9 @@
     this.updateStatus('Creating slice summaries');
     await engine.query(`include perfetto module viz.summary.slices;`);
 
+    this.updateStatus('Creating counter summaries');
+    await engine.query(`include perfetto module viz.summary.counters;`);
+
     this.updateStatus('Creating thread summaries');
     await engine.query(`include perfetto module viz.summary.threads;`);
 
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index a9b186d..709c9dc 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -96,10 +96,12 @@
   async guessCpuSizes(): Promise<Map<number, string>> {
     const cpuToSize = new Map<number, string>();
     await this.engine.query(`
-      INCLUDE PERFETTO MODULE cpu.size;
+      include perfetto module cpu.size;
     `);
     const result = await this.engine.query(`
-      SELECT cpu, cpu_guess_core_type(cpu) as size FROM cpu_counter_track;
+      select cpu, cpu_guess_core_type(cpu) as size
+      from cpu_counter_track
+      join _counter_track_summary using (id);
     `);
 
     const it = result.iter({
@@ -152,6 +154,7 @@
             limit 1
           ) as cpuIdleId
         from cpu_counter_track
+        join _counter_track_summary using (id)
         where name = 'cpufreq' and cpu = ${cpu}
         limit 1;
       `);
@@ -236,6 +239,7 @@
       const freqExistsResult = await engine.query(`
         select *
         from gpu_counter_track
+        join _counter_track_summary using (id)
         where name = 'gpufreq' and gpu_id = ${gpu}
         limit 1;
       `);
@@ -254,6 +258,7 @@
     const cpuFreqLimitCounterTracksSql = `
       select name, id
       from cpu_counter_track
+      join _counter_track_summary using (id)
       where name glob "Cpu * Freq Limit"
       order by name asc
     `;
@@ -271,6 +276,7 @@
     const addCpuPerfCounterTracksSql = `
       select printf("Cpu %u %s", cpu, name) as name, id
       from perf_counter_track as pct
+      join _counter_track_summary using (id)
       order by perf_session_id asc, pct.name asc, cpu asc
     `;
     this.addCpuCounterTracks(engine, addCpuPerfCounterTracksSql);
@@ -707,7 +713,8 @@
         thread.name as threadName,
         thread_counter_track.id as trackId
       from thread_counter_track
-      join thread using(utid)
+      join _counter_track_summary using (id)
+      join thread using (utid)
       where thread_counter_track.name != 'thread_time'
   `);
 
@@ -1001,6 +1008,7 @@
         process.pid,
         process.name as processName
       from process_counter_track
+      join _counter_track_summary using (id)
       join process using(upid);
   `);
     const it = result.iter({
@@ -1332,12 +1340,13 @@
 
   private async computeThreadOrderingMetadata(): Promise<UtidToTrackSortKey> {
     const result = await this.engine.query(`
-    select
-      utid,
-      tid,
-      (select pid from process p where t.upid = p.upid) as pid,
-      t.name as threadName
-    from thread t`);
+      select
+        utid,
+        tid,
+        (select pid from process p where t.upid = p.upid) as pid,
+        t.name as threadName
+      from thread t
+    `);
 
     const it = result.iter({
       utid: NUM,
@@ -1549,9 +1558,9 @@
       return PrimaryTrackSortKey.COUNTER_TRACK;
     }
     const result = await this.engine.query(`
-    select utid
-    from thread
-    where upid=${upid} and name=${sqliteString(threadName)}
+      select utid
+      from thread
+      where upid=${upid} and name=${sqliteString(threadName)}
     `);
     const it = result.iter({
       utid: NUM,
diff --git a/ui/src/core_plugins/counter/index.ts b/ui/src/core_plugins/counter/index.ts
index 7ac31d0..40865fa 100644
--- a/ui/src/core_plugins/counter/index.ts
+++ b/ui/src/core_plugins/counter/index.ts
@@ -131,10 +131,12 @@
       from (
         select name, id, unit
         from counter_track
+        join _counter_track_summary using (id)
         where type = 'counter_track'
         union
         select name, id, unit
         from gpu_counter_track
+        join _counter_track_summary using (id)
         where name != 'gpufreq'
       )
       order by name
@@ -176,6 +178,7 @@
     const cpuFreqLimitCounterTracksSql = `
       select name, id
       from cpu_counter_track
+      join _counter_track_summary using (id)
       where name glob "Cpu * Freq Limit"
       order by name asc
     `;
@@ -193,6 +196,7 @@
     const addCpuPerfCounterTracksSql = `
       select printf("Cpu %u %s", cpu, name) as name, id
       from perf_counter_track as pct
+      join _counter_track_summary using (id)
       order by perf_session_id asc, pct.name asc, cpu asc
     `;
     this.addCpuCounterTracks(ctx, addCpuPerfCounterTracksSql);
@@ -241,6 +245,7 @@
         thread.start_ts as startTs,
         thread.end_ts as endTs
       from thread_counter_track
+      join _counter_track_summary using (id)
       join thread using(utid)
       where thread_counter_track.name != 'thread_time'
     `);
@@ -296,6 +301,7 @@
       process.pid,
       process.name as processName
     from process_counter_track
+    join _counter_track_summary using (id)
     join process using(upid);
   `);
     const it = result.iter({
@@ -344,11 +350,12 @@
       // Only add a gpu freq track if we have
       // gpu freq data.
       const freqExistsResult = await engine.query(`
-      select id
-      from gpu_counter_track
-      where name = 'gpufreq' and gpu_id = ${gpu}
-      limit 1;
-    `);
+        select id
+        from gpu_counter_track
+        join _counter_track_summary using (id)
+        where name = 'gpufreq' and gpu_id = ${gpu}
+        limit 1;
+      `);
       if (freqExistsResult.numRows() > 0) {
         const trackId = freqExistsResult.firstRow({id: NUM}).id;
         const uri = `perfetto.Counter#gpu_freq${gpu}`;
diff --git a/ui/src/core_plugins/cpu_freq/index.ts b/ui/src/core_plugins/cpu_freq/index.ts
index a1d3947..7d0b8f7 100644
--- a/ui/src/core_plugins/cpu_freq/index.ts
+++ b/ui/src/core_plugins/cpu_freq/index.ts
@@ -411,6 +411,7 @@
       select ifnull(max(value), 0) as freq
       from counter c
       join cpu_counter_track t on c.track_id = t.id
+      join _counter_track_summary s on t.id = s.id
       where name = 'cpufreq';
     `);
     const maxCpuFreq = maxCpuFreqResult.firstRow({freq: NUM}).freq;
@@ -428,6 +429,7 @@
             limit 1
           ) as cpuIdleId
         from cpu_counter_track
+        join _counter_track_summary using (id)
         where name = 'cpufreq' and cpu = ${cpu}
         limit 1;
       `);
diff --git a/ui/src/core_plugins/cpu_slices/index.ts b/ui/src/core_plugins/cpu_slices/index.ts
index 3f456a3..0edddb7 100644
--- a/ui/src/core_plugins/cpu_slices/index.ts
+++ b/ui/src/core_plugins/cpu_slices/index.ts
@@ -56,11 +56,12 @@
   async guessCpuSizes(engine: Engine): Promise<Map<number, string>> {
     const cpuToSize = new Map<number, string>();
     await engine.query(`
-      INCLUDE PERFETTO MODULE cpu.size;
+      include perfetto module cpu.size;
     `);
     const result = await engine.query(`
-      SELECT cpu, cpu_guess_core_type(cpu) as size
-      FROM cpu_counter_track;
+      select cpu, cpu_guess_core_type(cpu) as size
+      from cpu_counter_track
+      join _counter_track_summary using (id);
     `);
 
     const it = result.iter({