Merge changes I6be837f9,I516669d3

* changes:
  Proto filter: adds plumbing into tracing service
  Proto filtering: add core MessageFilter and FilterUtil
diff --git a/debian/compat b/debian/compat
index f599e28..b1bd38b 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-10
+13
diff --git a/debian/control b/debian/control
index 28fcef2..94a03bb 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@
 Section: kernel
 Priority: optional
 Maintainer: Sami Kyostila <skyostil@google.com>
-Build-Depends: debhelper (>= 10),
+Build-Depends: debhelper (>= 13),
   generate-ninja,
   git,
   libprotoc-dev,
@@ -11,14 +11,15 @@
   python3,
   zlib1g-dev,
   zlib1g
-Standards-Version: 3.9.8
+Standards-Version: 4.5.1
 Homepage: https://perfetto.dev
 Vcs-Git: https://android.googlesource.com/platform/external/perfetto/
 Vcs-Browser: https://android.googlesource.com/platform/external/perfetto/
+Rules-Requires-Root: no
 
 Package: perfetto
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, zlib1g
+Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, zlib1g
 Description: Performance instrumentation and logging framework
  Perfetto is a performance instrumentation and logging framework for POSIX
  systems.
diff --git a/debian/copyright b/debian/copyright
index e23f57d..7b7058c 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,12 +4,12 @@
 
 Files: *
 Copyright: Copyright (C) 2017 The Android Open Source Project
-License: Apache 2
+License: Apache-2
  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
+      /usr/share/common-licenses/Apache-2.0
  .
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/debian/postinst b/debian/postinst
index 7d7e266..e6cdff5 100755
--- a/debian/postinst
+++ b/debian/postinst
@@ -3,3 +3,5 @@
 adduser --home /nonexistent --quiet --system --no-create-home --group traced
 addgroup --quiet --system traced-consumer
 usermod -a -G traced-consumer traced
+
+#DEBHELPER#
diff --git a/debian/postrm b/debian/postrm
index 20c9767..efa1590 100755
--- a/debian/postrm
+++ b/debian/postrm
@@ -1,3 +1,5 @@
 #!/bin/sh
 set -e
 rm -f /tmp/perfetto-consumer /tmp/perfetto-producer
+
+#DEBHELPER#
diff --git a/debian/rules b/debian/rules
index 2b0e32c..a081c5c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,4 +1,9 @@
 #!/usr/bin/make -f
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/buildflags.mk
+
 %:
 	dh $@
 
@@ -24,7 +29,7 @@
 	  enable_perfetto_unittests=false perfetto_use_system_protobuf=true\
 	  perfetto_use_system_zlib=true perfetto_enable_git_rev_version_header=false\
 	  extra_cflags=\"${CFLAGS}\" extra_cxxflags=\"${CXXFLAGS}\"\
-	  extra_ldflags=\"${CXXFLAGS}\" cc=\"${CC}\" cxx=\"${CXX}\"\
+	  extra_ldflags=\"${LDFLAGS}\" cc=\"${CC}\" cxx=\"${CXX}\"\
 	  ${MAYBE_HOST_CPU}"
 
 override_dh_auto_build:
diff --git a/debian/traced-perf.service b/debian/traced-perf.service
index b04463b..73bffb9 100644
--- a/debian/traced-perf.service
+++ b/debian/traced-perf.service
@@ -1,5 +1,6 @@
 [Unit]
 Description=Perfetto sampling and profiling data source
+Documentation=https://perfetto.dev/docs/
 
 [Service]
 ExecStart=/usr/sbin/traced_perf
diff --git a/debian/traced-probes.service b/debian/traced-probes.service
index 81a23f7..1d853b0 100644
--- a/debian/traced-probes.service
+++ b/debian/traced-probes.service
@@ -1,5 +1,6 @@
 [Unit]
 Description=Perfetto data sources for system tracing (ftrace and /proc pollers)
+Documentation=https://perfetto.dev/docs/
 
 [Service]
 ExecStart=/usr/sbin/traced_probes
diff --git a/debian/traced.service b/debian/traced.service
index 6eb7d8a..4ca8d7a 100644
--- a/debian/traced.service
+++ b/debian/traced.service
@@ -1,5 +1,6 @@
 [Unit]
 Description=Perfetto tracing service daemon
+Documentation=https://perfetto.dev/docs/
 
 [Service]
 ExecStart=/usr/sbin/traced \
diff --git a/include/perfetto/ext/base/thread_task_runner.h b/include/perfetto/ext/base/thread_task_runner.h
index d4e672e..5f5947e 100644
--- a/include/perfetto/ext/base/thread_task_runner.h
+++ b/include/perfetto/ext/base/thread_task_runner.h
@@ -32,7 +32,7 @@
 // * the UnixTaskRunner will be constructed and destructed on the task thread.
 // * the task thread will live for the lifetime of the UnixTaskRunner.
 //
-class ThreadTaskRunner : public TaskRunner {
+class PERFETTO_EXPORT ThreadTaskRunner : public TaskRunner {
  public:
   static ThreadTaskRunner CreateAndStart(const std::string& name = "") {
     return ThreadTaskRunner(name);
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 5eec2e2..5b0f2b6 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -621,6 +621,12 @@
   // Introduced in Android 12.
   repeated string heaps = 20;
 
+  // Which heaps not to sample, e.g. "libc.malloc". This is useful when used in
+  // combination with all_heaps;
+  //
+  // Introduced in Android 12.
+  repeated string exclude_heaps = 27;
+
   optional bool stream_allocations = 23;
 
   // If given, needs to be the same length as heaps and gives the sampling
diff --git a/protos/perfetto/config/profiling/heapprofd_config.proto b/protos/perfetto/config/profiling/heapprofd_config.proto
index 2d8654c..00dd692 100644
--- a/protos/perfetto/config/profiling/heapprofd_config.proto
+++ b/protos/perfetto/config/profiling/heapprofd_config.proto
@@ -81,6 +81,12 @@
   // Introduced in Android 12.
   repeated string heaps = 20;
 
+  // Which heaps not to sample, e.g. "libc.malloc". This is useful when used in
+  // combination with all_heaps;
+  //
+  // Introduced in Android 12.
+  repeated string exclude_heaps = 27;
+
   optional bool stream_allocations = 23;
 
   // If given, needs to be the same length as heaps and gives the sampling
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index f9d963a..402fae8 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -621,6 +621,12 @@
   // Introduced in Android 12.
   repeated string heaps = 20;
 
+  // Which heaps not to sample, e.g. "libc.malloc". This is useful when used in
+  // combination with all_heaps;
+  //
+  // Introduced in Android 12.
+  repeated string exclude_heaps = 27;
+
   optional bool stream_allocations = 23;
 
   // If given, needs to be the same length as heaps and gives the sampling
diff --git a/src/profiling/memory/heapprofd_producer.cc b/src/profiling/memory/heapprofd_producer.cc
index 16da1fa..dfc6922 100644
--- a/src/profiling/memory/heapprofd_producer.cc
+++ b/src/profiling/memory/heapprofd_producer.cc
@@ -149,10 +149,13 @@
   cli_config->adaptive_sampling_max_sampling_interval_bytes =
       heapprofd_config.adaptive_sampling_max_sampling_interval_bytes();
   size_t n = 0;
+  const std::vector<std::string>& exclude_heaps = heapprofd_config.exclude_heaps();
+  // heaps[i] and heaps_interval[i] represent that the heap named in heaps[i]
+  // should be sampled with sampling interval of heap_interval[i].
   std::vector<std::string> heaps = heapprofd_config.heaps();
   std::vector<uint64_t> heap_intervals =
       heapprofd_config.heap_sampling_intervals();
-  if (heaps.empty()) {
+  if (heaps.empty() && !cli_config->all_heaps) {
     heaps.push_back("libc.malloc");
   }
 
@@ -169,6 +172,15 @@
     PERFETTO_ELOG("zero sampling interval.");
     return false;
   }
+  if (!exclude_heaps.empty()) {
+    // For disabled heaps, we add explicit entries but with sampling interval
+    // 0. The consumer of the sampling intervals in ClientConfiguration,
+    // GetSamplingInterval in wire_protocol.h, uses 0 to signal a heap is
+    // disabled, either because it isn't enabled (all_heaps is not set, and the
+    // heap isn't named), or because we explicitely set it here.
+    heaps.insert(heaps.end(), exclude_heaps.cbegin(), exclude_heaps.cend());
+    heap_intervals.insert(heap_intervals.end(), exclude_heaps.size(), 0u);
+  }
   if (heaps.size() > base::ArraySize(cli_config->heaps)) {
     heaps.resize(base::ArraySize(cli_config->heaps));
     PERFETTO_ELOG("Too many heaps requested. Truncating.");
diff --git a/src/profiling/memory/heapprofd_producer_unittest.cc b/src/profiling/memory/heapprofd_producer_unittest.cc
index 8a75145..fa08e95 100644
--- a/src/profiling/memory/heapprofd_producer_unittest.cc
+++ b/src/profiling/memory/heapprofd_producer_unittest.cc
@@ -202,5 +202,42 @@
             4 * 4096u);
 }
 
+TEST(HeapprofdConfigToClientConfigurationTest, AllHeaps) {
+  HeapprofdConfig cfg;
+  cfg.set_all_heaps(true);
+  cfg.set_sampling_interval_bytes(4096);
+  ClientConfiguration cli_config;
+  ASSERT_TRUE(HeapprofdConfigToClientConfiguration(cfg, &cli_config));
+  EXPECT_EQ(cli_config.num_heaps, 0u);
+  EXPECT_EQ(cli_config.default_interval, 4096u);
+}
+
+TEST(HeapprofdConfigToClientConfigurationTest, AllHeapsAndExplicit) {
+  HeapprofdConfig cfg;
+  cfg.set_all_heaps(true);
+  cfg.set_sampling_interval_bytes(4096);
+  cfg.add_heaps("foo");
+  cfg.add_heap_sampling_intervals(1024u);
+  ClientConfiguration cli_config;
+  ASSERT_TRUE(HeapprofdConfigToClientConfiguration(cfg, &cli_config));
+  EXPECT_EQ(cli_config.num_heaps, 1u);
+  EXPECT_STREQ(cli_config.heaps[0].name, "foo");
+  EXPECT_EQ(cli_config.heaps[0].interval, 1024u);
+  EXPECT_EQ(cli_config.default_interval, 4096u);
+}
+
+TEST(HeapprofdConfigToClientConfigurationTest, AllHeapsAndDisabled) {
+  HeapprofdConfig cfg;
+  cfg.set_all_heaps(true);
+  cfg.set_sampling_interval_bytes(4096);
+  cfg.add_exclude_heaps("foo");
+  ClientConfiguration cli_config;
+  ASSERT_TRUE(HeapprofdConfigToClientConfiguration(cfg, &cli_config));
+  EXPECT_EQ(cli_config.num_heaps, 1u);
+  EXPECT_STREQ(cli_config.heaps[0].name, "foo");
+  EXPECT_EQ(cli_config.heaps[0].interval, 0u);
+  EXPECT_EQ(cli_config.default_interval, 4096u);
+}
+
 }  // namespace profiling
 }  // namespace perfetto
diff --git a/src/profiling/memory/wire_protocol_unittest.cc b/src/profiling/memory/wire_protocol_unittest.cc
index 69df58f..3f7e494 100644
--- a/src/profiling/memory/wire_protocol_unittest.cc
+++ b/src/profiling/memory/wire_protocol_unittest.cc
@@ -160,6 +160,17 @@
   EXPECT_EQ(GetHeapSamplingInterval(cli_config, "else"), 1u);
 }
 
+TEST(GetHeapSamplingInterval, DisabledAndDefault) {
+  ClientConfiguration cli_config{};
+  cli_config.all_heaps = true;
+  cli_config.num_heaps = 1;
+  cli_config.default_interval = 1;
+  memcpy(cli_config.heaps[0].name, "something", sizeof("something"));
+  cli_config.heaps[0].interval = 0u;
+  EXPECT_EQ(GetHeapSamplingInterval(cli_config, "something"), 0u);
+  EXPECT_EQ(GetHeapSamplingInterval(cli_config, "else"), 1u);
+}
+
 }  // namespace
 }  // namespace profiling
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/common/clock_tracker.cc b/src/trace_processor/importers/common/clock_tracker.cc
index f59fbfc..75518a2 100644
--- a/src/trace_processor/importers/common/clock_tracker.cc
+++ b/src/trace_processor/importers/common/clock_tracker.cc
@@ -41,7 +41,7 @@
 
 ClockTracker::~ClockTracker() = default;
 
-void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
+uint32_t ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
   const auto snapshot_id = cur_snapshot_id_++;
 
   // Clear the cache
@@ -65,7 +65,7 @@
                       "supported for sequence-scoped clocks.",
                       clock_id);
         context_->storage->IncrementStats(stats::invalid_clock_snapshots);
-        return;
+        return snapshot_id;
       }
       domain.unit_multiplier_ns = clock.unit_multiplier_ns;
       domain.is_incremental = clock.is_incremental;
@@ -79,7 +79,7 @@
                     clock_id, clock.unit_multiplier_ns, clock.is_incremental,
                     domain.unit_multiplier_ns, domain.is_incremental);
       context_->storage->IncrementStats(stats::invalid_clock_snapshots);
-      return;
+      return snapshot_id;
     }
     const int64_t timestamp_ns =
         clock.absolute_timestamp * domain.unit_multiplier_ns;
@@ -92,7 +92,7 @@
                     " at snapshot %" PRIu32 ".",
                     clock_id, snapshot_id);
       context_->storage->IncrementStats(stats::invalid_clock_snapshots);
-      return;
+      return snapshot_id;
     }
 
     // Clock ids in the range [64, 128) are sequence-scoped and must be
@@ -116,7 +116,7 @@
                       clock_id, snapshot_id, timestamp_ns,
                       vect.timestamps_ns.back());
         context_->storage->IncrementStats(stats::invalid_clock_snapshots);
-        return;
+        return snapshot_id;
       }
 
       PERFETTO_DLOG("Detected non-monotonic clock with ID %" PRIu64, clock_id);
@@ -159,6 +159,7 @@
         graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
     }
   }
+  return snapshot_id;
 }
 
 // Finds the shortest clock resolution path in the graph that allows to
diff --git a/src/trace_processor/importers/common/clock_tracker.h b/src/trace_processor/importers/common/clock_tracker.h
index 80b2a4e..16b9d79 100644
--- a/src/trace_processor/importers/common/clock_tracker.h
+++ b/src/trace_processor/importers/common/clock_tracker.h
@@ -154,7 +154,8 @@
 
   // Appends a new snapshot for the given clock domains.
   // This is typically called by the code that reads the ClockSnapshot packet.
-  void AddSnapshot(const std::vector<ClockValue>&);
+  // Returns the internal snapshot id of this set of clocks.
+  uint32_t AddSnapshot(const std::vector<ClockValue>&);
 
   // Converts a timestamp between two clock domains. Tries to use the cache
   // first (only for single-path resolutions), then falls back on path finding
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 863d5bd..ee03db3 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -378,10 +378,61 @@
     clocks.emplace_back(clock_id, clk.timestamp(), unit_multiplier_ns,
                         clk.is_incremental());
   }
-  context_->clock_tracker->AddSnapshot(clocks);
+
+  uint32_t snapshot_id = context_->clock_tracker->AddSnapshot(clocks);
+
+  // Add the all the clock values to the clock snapshot table.
+  base::Optional<int64_t> trace_ts_for_check;
+  for (const auto& clock : clocks) {
+    // If the clock is incremental, we need to use 0 to map correctly to
+    // |absolute_timestamp|.
+    int64_t ts_to_convert = clock.is_incremental ? 0 : clock.absolute_timestamp;
+    base::Optional<int64_t> opt_trace_ts =
+        context_->clock_tracker->ToTraceTime(clock.clock_id, ts_to_convert);
+    if (!opt_trace_ts) {
+      // This can happen if |AddSnapshot| failed to resolve this clock. Just
+      // ignore this and move on.
+      continue;
+    }
+
+    // Double check that all the clocks in this snapshot resolve to the same
+    // trace timestamp value.
+    PERFETTO_DCHECK(!trace_ts_for_check || opt_trace_ts == trace_ts_for_check);
+    trace_ts_for_check = *opt_trace_ts;
+
+    tables::ClockSnapshotTable::Row row;
+    row.ts = *opt_trace_ts;
+    row.clock_id = static_cast<int64_t>(clock.clock_id);
+    row.clock_value = clock.absolute_timestamp;
+    row.clock_name = GetBuiltinClockNameOrNull(clock.clock_id);
+    row.snapshot_id = snapshot_id;
+
+    auto* snapshot_table = context_->storage->mutable_clock_snapshot_table();
+    snapshot_table->Insert(row);
+  }
   return util::OkStatus();
 }
 
+base::Optional<StringId> ProtoTraceReader::GetBuiltinClockNameOrNull(
+    uint64_t clock_id) {
+  switch (clock_id) {
+    case protos::pbzero::ClockSnapshot::Clock::REALTIME:
+      return context_->storage->InternString("REALTIME");
+    case protos::pbzero::ClockSnapshot::Clock::REALTIME_COARSE:
+      return context_->storage->InternString("REALTIME_COARSE");
+    case protos::pbzero::ClockSnapshot::Clock::MONOTONIC:
+      return context_->storage->InternString("MONOTONIC");
+    case protos::pbzero::ClockSnapshot::Clock::MONOTONIC_COARSE:
+      return context_->storage->InternString("MONOTONIC_COARSE");
+    case protos::pbzero::ClockSnapshot::Clock::MONOTONIC_RAW:
+      return context_->storage->InternString("MONOTONIC_RAW");
+    case protos::pbzero::ClockSnapshot::Clock::BOOTTIME:
+      return context_->storage->InternString("BOOTTIME");
+    default:
+      return base::nullopt;
+  }
+}
+
 util::Status ProtoTraceReader::ParseServiceEvent(int64_t ts, ConstBytes blob) {
   protos::pbzero::TracingServiceEvent::Decoder tse(blob);
   if (tse.tracing_started()) {
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index b2f4069..1adb841 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -75,6 +75,8 @@
                          TraceBlobView interned_data);
   void ParseTraceConfig(ConstBytes);
 
+  base::Optional<StringId> GetBuiltinClockNameOrNull(uint64_t clock_id);
+
   PacketSequenceState* GetIncrementalStateForPacketSequence(
       uint32_t sequence_id) {
     if (!incremental_state)
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 698aa7c..e2af2ce 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -442,6 +442,13 @@
   }
   tables::MetadataTable* mutable_metadata_table() { return &metadata_table_; }
 
+  const tables::ClockSnapshotTable& clock_snapshot_table() const {
+    return clock_snapshot_table_;
+  }
+  tables::ClockSnapshotTable* mutable_clock_snapshot_table() {
+    return &clock_snapshot_table_;
+  }
+
   const tables::ArgTable& arg_table() const { return arg_table_; }
   tables::ArgTable* mutable_arg_table() { return &arg_table_; }
 
@@ -719,6 +726,9 @@
   // * descriptions of android packages
   tables::MetadataTable metadata_table_{&string_pool_, nullptr};
 
+  // Contains data from all the clock snapshots in the trace.
+  tables::ClockSnapshotTable clock_snapshot_table_{&string_pool_, nullptr};
+
   // Metadata for tracks.
   tables::TrackTable track_table_{&string_pool_, nullptr};
   tables::GpuTrackTable gpu_track_table_{&string_pool_, &track_table_};
diff --git a/src/trace_processor/tables/metadata_tables.h b/src/trace_processor/tables/metadata_tables.h
index fa3136b..3f1bb90 100644
--- a/src/trace_processor/tables/metadata_tables.h
+++ b/src/trace_processor/tables/metadata_tables.h
@@ -113,6 +113,28 @@
 
 PERFETTO_TP_TABLE(PERFETTO_TP_CPU_FREQ_TABLE_DEF);
 
+// Contains all the mapping between clock snapshots and trace time.
+//
+// NOTE: this table is not sorted by timestamp; this is why we omit the
+// sorted flag on the ts column.
+//
+// @param ts            timestamp of the snapshot in trace time.
+// @param clock_id      id of the clock (corresponds to the id in the trace).
+// @param clock_name    the name of the clock for builtin clocks or null
+//                      otherwise.
+// @param clock_value   timestamp of the snapshot in clock time.
+// @param snapshot_id   the index of this snapshot (only useful for debugging)
+#define PERFETTO_TP_CLOCK_SNAPSHOT_TABLE_DEF(NAME, PARENT, C) \
+  NAME(ClockSnapshotTable, "clock_snapshot")                  \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                           \
+  C(int64_t, ts)                                              \
+  C(int64_t, clock_id)                                        \
+  C(base::Optional<StringPool::Id>, clock_name)               \
+  C(int64_t, clock_value)                                     \
+  C(uint32_t, snapshot_id)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_CLOCK_SNAPSHOT_TABLE_DEF);
+
 }  // namespace tables
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/tables/table_destructors.cc b/src/trace_processor/tables/table_destructors.cc
index d57b71b..34206b9 100644
--- a/src/trace_processor/tables/table_destructors.cc
+++ b/src/trace_processor/tables/table_destructors.cc
@@ -45,6 +45,7 @@
 CpuFreqTable::~CpuFreqTable() = default;
 ThreadTable::~ThreadTable() = default;
 ProcessTable::~ProcessTable() = default;
+ClockSnapshotTable::~ClockSnapshotTable() = default;
 
 // profiler_tables.h
 StackProfileMappingTable::~StackProfileMappingTable() = default;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 8893144..0ca05ea 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -825,6 +825,7 @@
   RegisterDbTable(storage->metadata_table());
   RegisterDbTable(storage->cpu_table());
   RegisterDbTable(storage->cpu_freq_table());
+  RegisterDbTable(storage->clock_snapshot_table());
 
   RegisterDbTable(storage->memory_snapshot_table());
   RegisterDbTable(storage->process_memory_snapshot_table());