Merge "processor: Support pid reuse in ProcessTracker without Start/EndThread"
diff --git a/Android.bp b/Android.bp
index d721882..45bb558 100644
--- a/Android.bp
+++ b/Android.bp
@@ -994,6 +994,10 @@
     ":perfetto_src_tracing_tracing",
     ":perfetto_test_test_helper",
   ],
+  static_libs: [
+    "libgmock",
+    "libgtest",
+  ],
   export_include_dirs: [
     "include",
     "include/perfetto/base/build_configs/android_tree",
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index cb35cd0..3440b62 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -85,6 +85,7 @@
     "PERFETTO_TP_JSON_IMPORT=$enable_perfetto_trace_processor_json_import",
     "PERFETTO_TP_FUCHSIA=$enable_perfetto_trace_processor_fuchsia",
     "PERFETTO_LOCAL_SYMBOLIZER=$perfetto_local_symbolizer",
+    "PERFETTO_ZLIB=$enable_perfetto_zlib",
   ]
 
   rel_out_path = rebase_path(gen_header_path, "$root_build_dir")
@@ -306,7 +307,7 @@
 }
 
 # Zlib is used both by trace_processor and by perfetto_cmd.
-if (enable_perfetto_trace_processor || enable_perfetto_platform_services) {
+if (enable_perfetto_zlib) {
   group("zlib") {
     if (perfetto_root_path == "//") {
       public_configs = [ "//buildtools:zlib_config" ]
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index b479435..563db03 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -223,6 +223,11 @@
   # Further per-OS conditionals are applied in gn/BUILD.gn.
   enable_perfetto_trace_processor_httpd =
       enable_perfetto_trace_processor && perfetto_build_standalone
+
+  # Enables Zlib support. This is used both by the "perfetto" cmdline client
+  # (for compressing traces) and by trace processor (for compressed traces).
+  enable_perfetto_zlib =
+      enable_perfetto_trace_processor || enable_perfetto_platform_services
 }
 
 declare_args() {
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index 0c77eca..c52b7c1 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -20,6 +20,7 @@
   cflags = [
     "-Wall",
     "-Wextra",
+    "-Wpedantic",
   ]
 
   # Disable Weverything on fuzzers to avoid breakages when new versions of clang
diff --git a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
index 259721b..dbc68b7 100644
--- a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
@@ -39,6 +39,7 @@
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_JSON_IMPORT() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_FUCHSIA() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LOCAL_SYMBOLIZER() (PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_LINUX())
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_ZLIB() (1)
 
 // clang-format on
 #endif  // GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index 7919b4d..ce91468 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -39,6 +39,7 @@
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_JSON_IMPORT() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_FUCHSIA() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LOCAL_SYMBOLIZER() (PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_LINUX())
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_ZLIB() (1)
 
 // clang-format on
 #endif  // GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/base/logging.h b/include/perfetto/base/logging.h
index 2691438..aeebf0b 100644
--- a/include/perfetto/base/logging.h
+++ b/include/perfetto/base/logging.h
@@ -24,6 +24,9 @@
 #include "perfetto/base/compiler.h"
 #include "perfetto/base/export.h"
 
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
 // TODO(primiano): move this to base/build_config.h, turn into
 // PERFETTO_BUILDFLAG(DCHECK_IS_ON) and update call sites to use that instead.
 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
diff --git a/include/perfetto/ext/base/unix_socket.h b/include/perfetto/ext/base/unix_socket.h
index a0dac27..07e0f58 100644
--- a/include/perfetto/ext/base/unix_socket.h
+++ b/include/perfetto/ext/base/unix_socket.h
@@ -48,9 +48,7 @@
 class UnixSocketRaw {
  public:
   // Creates a new unconnected unix socket.
-  static UnixSocketRaw CreateMayFail(SockFamily family, SockType type) {
-    return UnixSocketRaw(family, type);
-  }
+  static UnixSocketRaw CreateMayFail(SockFamily family, SockType type);
 
   // Crates a pair of connected sockets.
   static std::pair<UnixSocketRaw, UnixSocketRaw> CreatePair(SockFamily,
diff --git a/include/perfetto/ext/base/utils.h b/include/perfetto/ext/base/utils.h
index f7bfdcd..aadded6 100644
--- a/include/perfetto/ext/base/utils.h
+++ b/include/perfetto/ext/base/utils.h
@@ -28,13 +28,13 @@
 #endif
 
 #define PERFETTO_EINTR(x)                                   \
-  ({                                                        \
+  ([&] {                                                    \
     decltype(x) eintr_wrapper_result;                       \
     do {                                                    \
       eintr_wrapper_result = (x);                           \
     } while (eintr_wrapper_result == -1 && errno == EINTR); \
-    eintr_wrapper_result;                                   \
-  })
+    return eintr_wrapper_result;                            \
+  }())
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 // TODO(brucedawson) - create a ::perfetto::base::IOSize to replace this.
diff --git a/include/perfetto/tracing/data_source.h b/include/perfetto/tracing/data_source.h
index e283737..1a2f57e 100644
--- a/include/perfetto/tracing/data_source.h
+++ b/include/perfetto/tracing/data_source.h
@@ -453,12 +453,20 @@
 
 }  // namespace perfetto
 
-// Not needed -- only here for backwards compatibility.
-// TODO(skyostil): Remove this macro.
-#define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(...)
+// If placed at the end of a macro declaration, eats the semicolon at the end of
+// the macro invocation (e.g., "MACRO(...);") to avoid warnings about extra
+// semicolons.
+#define PERFETTO_INTERNAL_SWALLOW_SEMICOLON() \
+  extern int perfetto_internal_unused
 
 // Not needed -- only here for backwards compatibility.
 // TODO(skyostil): Remove this macro.
-#define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(...)
+#define PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(...) \
+  PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
+
+// Not needed -- only here for backwards compatibility.
+// TODO(skyostil): Remove this macro.
+#define PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(...) \
+  PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
 
 #endif  // INCLUDE_PERFETTO_TRACING_DATA_SOURCE_H_
diff --git a/include/perfetto/tracing/internal/track_event_macros.h b/include/perfetto/tracing/internal/track_event_macros.h
index f291186..bfe6692 100644
--- a/include/perfetto/tracing/internal/track_event_macros.h
+++ b/include/perfetto/tracing/internal/track_event_macros.h
@@ -25,6 +25,9 @@
 #include "perfetto/tracing/internal/track_event_data_source.h"
 #include "perfetto/tracing/track_event_category_registry.h"
 
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
 // Defines data structures for backing a category registry.
 //
 // Each category has one enabled/disabled bit per possible data source instance.
diff --git a/include/perfetto/tracing/track_event.h b/include/perfetto/tracing/track_event.h
index 95c2923..3d8e02f 100644
--- a/include/perfetto/tracing/track_event.h
+++ b/include/perfetto/tracing/track_event.h
@@ -138,14 +138,19 @@
   PERFETTO_INTERNAL_DECLARE_CATEGORIES(__VA_ARGS__)            \
   /* The track event data source for this set of categories */ \
   PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE();         \
-  }  // namespace PERFETTO_TRACK_EVENT_NAMESPACE
+  } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */             \
+  PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
 
 // Allocate storage for each category by using this macro once per track event
 // namespace.
-#define PERFETTO_TRACK_EVENT_STATIC_STORAGE() \
-  namespace PERFETTO_TRACK_EVENT_NAMESPACE {  \
-  PERFETTO_INTERNAL_CATEGORY_STORAGE()        \
-  }  // namespace PERFETTO_TRACK_EVENT_NAMESPACE
+#define PERFETTO_TRACK_EVENT_STATIC_STORAGE()      \
+  namespace PERFETTO_TRACK_EVENT_NAMESPACE {       \
+  PERFETTO_INTERNAL_CATEGORY_STORAGE()             \
+  } /* namespace PERFETTO_TRACK_EVENT_NAMESPACE */ \
+  PERFETTO_INTERNAL_SWALLOW_SEMICOLON()
+
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
 
 // Begin a slice under |category| with the title |name|. Both strings must be
 // static constants. The track event is only recorded if |category| is enabled
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index c786391..53681bc 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -95,6 +95,7 @@
   deps = [
     ":base",
     "../../gn:default_deps",
+    "../../gn:gtest_and_gmock",
   ]
   sources = [
     "test/utils.cc",
diff --git a/src/base/task_runner_unittest.cc b/src/base/task_runner_unittest.cc
index a8368b5..10f047b 100644
--- a/src/base/task_runner_unittest.cc
+++ b/src/base/task_runner_unittest.cc
@@ -30,16 +30,11 @@
 namespace base {
 namespace {
 
-template <typename T>
 class TaskRunnerTest : public ::testing::Test {
  public:
-  T task_runner;
+  UnixTaskRunner task_runner;
 };
 
-using TaskRunnerTypes = ::testing::Types<UnixTaskRunner>;
-
-TYPED_TEST_SUITE(TaskRunnerTest, TaskRunnerTypes);
-
 struct TestPipe : Pipe {
   TestPipe() : Pipe(Pipe::Create()) {
     // Make the pipe initially readable.
@@ -59,7 +54,7 @@
   }
 };
 
-TYPED_TEST(TaskRunnerTest, PostImmediateTask) {
+TEST_F(TaskRunnerTest, PostImmediateTask) {
   auto& task_runner = this->task_runner;
   int counter = 0;
   task_runner.PostTask([&counter] { counter = (counter << 4) | 1; });
@@ -71,7 +66,7 @@
   EXPECT_EQ(0x1234, counter);
 }
 
-TYPED_TEST(TaskRunnerTest, PostDelayedTask) {
+TEST_F(TaskRunnerTest, PostDelayedTask) {
   auto& task_runner = this->task_runner;
   int counter = 0;
   task_runner.PostDelayedTask([&counter] { counter = (counter << 4) | 1; }, 5);
@@ -83,7 +78,7 @@
   EXPECT_EQ(0x1234, counter);
 }
 
-TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromTask) {
+TEST_F(TaskRunnerTest, PostImmediateTaskFromTask) {
   auto& task_runner = this->task_runner;
   task_runner.PostTask([&task_runner] {
     task_runner.PostTask([&task_runner] { task_runner.Quit(); });
@@ -91,7 +86,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromTask) {
+TEST_F(TaskRunnerTest, PostDelayedTaskFromTask) {
   auto& task_runner = this->task_runner;
   task_runner.PostTask([&task_runner] {
     task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
@@ -99,7 +94,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, PostImmediateTaskFromOtherThread) {
+TEST_F(TaskRunnerTest, PostImmediateTaskFromOtherThread) {
   auto& task_runner = this->task_runner;
   ThreadChecker thread_checker;
   int counter = 0;
@@ -118,7 +113,7 @@
   EXPECT_EQ(0x1234, counter);
 }
 
-TYPED_TEST(TaskRunnerTest, PostDelayedTaskFromOtherThread) {
+TEST_F(TaskRunnerTest, PostDelayedTaskFromOtherThread) {
   auto& task_runner = this->task_runner;
   std::thread thread([&task_runner] {
     task_runner.PostDelayedTask([&task_runner] { task_runner.Quit(); }, 10);
@@ -127,7 +122,7 @@
   thread.join();
 }
 
-TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatch) {
+TEST_F(TaskRunnerTest, AddFileDescriptorWatch) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   task_runner.AddFileDescriptorWatch(pipe.rd.get(),
@@ -135,7 +130,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatch) {
+TEST_F(TaskRunnerTest, RemoveFileDescriptorWatch) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
 
@@ -149,7 +144,7 @@
   EXPECT_FALSE(watch_ran);
 }
 
-TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromTask) {
+TEST_F(TaskRunnerTest, RemoveFileDescriptorWatchFromTask) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
 
@@ -165,7 +160,7 @@
   EXPECT_FALSE(watch_ran);
 }
 
-TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherWatch) {
+TEST_F(TaskRunnerTest, AddFileDescriptorWatchFromAnotherWatch) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   TestPipe pipe2;
@@ -179,7 +174,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, RemoveFileDescriptorWatchFromAnotherWatch) {
+TEST_F(TaskRunnerTest, RemoveFileDescriptorWatchFromAnotherWatch) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   TestPipe pipe2;
@@ -198,7 +193,7 @@
   EXPECT_FALSE(watch_ran);
 }
 
-TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromAnotherWatch) {
+TEST_F(TaskRunnerTest, ReplaceFileDescriptorWatchFromAnotherWatch) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   TestPipe pipe2;
@@ -216,7 +211,7 @@
   EXPECT_FALSE(watch_ran);
 }
 
-TYPED_TEST(TaskRunnerTest, AddFileDescriptorWatchFromAnotherThread) {
+TEST_F(TaskRunnerTest, AddFileDescriptorWatchFromAnotherThread) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
 
@@ -228,7 +223,7 @@
   thread.join();
 }
 
-TYPED_TEST(TaskRunnerTest, FileDescriptorWatchWithMultipleEvents) {
+TEST_F(TaskRunnerTest, FileDescriptorWatchWithMultipleEvents) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
 
@@ -246,7 +241,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, FileDescriptorClosedEvent) {
+TEST_F(TaskRunnerTest, FileDescriptorClosedEvent) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   pipe.wr.reset();
@@ -255,7 +250,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, PostManyDelayedTasks) {
+TEST_F(TaskRunnerTest, PostManyDelayedTasks) {
   // Check that PostTask doesn't start failing if there are too many scheduled
   // wake-ups.
   auto& task_runner = this->task_runner;
@@ -265,7 +260,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, RunAgain) {
+TEST_F(TaskRunnerTest, RunAgain) {
   auto& task_runner = this->task_runner;
   int counter = 0;
   task_runner.PostTask([&task_runner, &counter] {
@@ -281,31 +276,28 @@
   EXPECT_EQ(2, counter);
 }
 
-template <typename TaskRunner>
-void RepeatingTask(TaskRunner* task_runner) {
-  task_runner->PostTask(std::bind(&RepeatingTask<TaskRunner>, task_runner));
+void RepeatingTask(UnixTaskRunner* task_runner) {
+  task_runner->PostTask(std::bind(&RepeatingTask, task_runner));
 }
 
-TYPED_TEST(TaskRunnerTest, FileDescriptorWatchesNotStarved) {
+TEST_F(TaskRunnerTest, FileDescriptorWatchesNotStarved) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
-  task_runner.PostTask(std::bind(&RepeatingTask<TypeParam>, &task_runner));
+  task_runner.PostTask(std::bind(&RepeatingTask, &task_runner));
   task_runner.AddFileDescriptorWatch(pipe.rd.get(),
                                      [&task_runner] { task_runner.Quit(); });
   task_runner.Run();
 }
 
-template <typename TaskRunner>
-void CountdownTask(TaskRunner* task_runner, int* counter) {
+void CountdownTask(UnixTaskRunner* task_runner, int* counter) {
   if (!--(*counter)) {
     task_runner->Quit();
     return;
   }
-  task_runner->PostTask(
-      std::bind(&CountdownTask<TaskRunner>, task_runner, counter));
+  task_runner->PostTask(std::bind(&CountdownTask, task_runner, counter));
 }
 
-TYPED_TEST(TaskRunnerTest, NoDuplicateFileDescriptorWatchCallbacks) {
+TEST_F(TaskRunnerTest, NoDuplicateFileDescriptorWatchCallbacks) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
   bool watch_called = 0;
@@ -315,12 +307,11 @@
     pipe.Read();
     watch_called = true;
   });
-  task_runner.PostTask(
-      std::bind(&CountdownTask<TypeParam>, &task_runner, &counter));
+  task_runner.PostTask(std::bind(&CountdownTask, &task_runner, &counter));
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, ReplaceFileDescriptorWatchFromOtherThread) {
+TEST_F(TaskRunnerTest, ReplaceFileDescriptorWatchFromOtherThread) {
   auto& task_runner = this->task_runner;
   TestPipe pipe;
 
@@ -339,7 +330,7 @@
   thread.join();
 }
 
-TYPED_TEST(TaskRunnerTest, IsIdleForTesting) {
+TEST_F(TaskRunnerTest, IsIdleForTesting) {
   auto& task_runner = this->task_runner;
   task_runner.PostTask(
       [&task_runner] { EXPECT_FALSE(task_runner.IsIdleForTesting()); });
@@ -350,7 +341,7 @@
   task_runner.Run();
 }
 
-TYPED_TEST(TaskRunnerTest, RunsTasksOnCurrentThread) {
+TEST_F(TaskRunnerTest, RunsTasksOnCurrentThread) {
   auto& main_tr = this->task_runner;
 
   EXPECT_TRUE(main_tr.RunsTasksOnCurrentThread());
diff --git a/src/base/test/benchmark_main.cc b/src/base/test/benchmark_main.cc
index e410e52..3a3feaa 100644
--- a/src/base/test/benchmark_main.cc
+++ b/src/base/test/benchmark_main.cc
@@ -14,4 +14,4 @@
 
 #include <benchmark/benchmark.h>
 
-BENCHMARK_MAIN();
+BENCHMARK_MAIN()
diff --git a/src/base/test/utils.h b/src/base/test/utils.h
index 673362a..a064fa2 100644
--- a/src/base/test/utils.h
+++ b/src/base/test/utils.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "perfetto/base/logging.h"
+#include "test/gtest_and_gmock.h"
 
 #if PERFETTO_DCHECK_IS_ON()
 
@@ -30,11 +31,20 @@
 
 #else  // PERFETTO_DCHECK_IS_ON()
 
+// Since PERFETTO_DCHECK_IS_ON() is false these statements should not die (if
+// they should/do we should use EXPECT/ASSERT DEATH_TEST_IF_SUPPORTED directly).
+// Therefore if the platform supports DEATH_TESTS we can use the handy
+// GTEST_EXECUTE_STATEMENT_ which prevents optimizing the code away, and if not
+// we just fall back on executing the code directly.
+#if GTEST_HAS_DEATH_TEST
 #define EXPECT_DCHECK_DEATH(statement) \
     GTEST_EXECUTE_STATEMENT_(statement, "PERFETTO_CHECK")
 #define ASSERT_DCHECK_DEATH(statement) \
     GTEST_EXECUTE_STATEMENT_(statement, "PERFETTO_CHECK")
-
+#else
+#define EXPECT_DCHECK_DEATH(statement) statement
+#define ASSERT_DCHECK_DEATH(statement) statement
+#endif  // GTEST_HAS_DEATH_TEST
 #endif  // PERFETTO_DCHECK_IS_ON()
 
 namespace perfetto {
diff --git a/src/base/unix_socket.cc b/src/base/unix_socket.cc
index e63f978..f6db62a 100644
--- a/src/base/unix_socket.cc
+++ b/src/base/unix_socket.cc
@@ -172,6 +172,15 @@
 }
 
 // static
+UnixSocketRaw UnixSocketRaw::CreateMayFail(SockFamily family, SockType type) {
+  auto fd = ScopedFile(socket(GetSockFamily(family), GetSockType(type), 0));
+  if (!fd) {
+    return UnixSocketRaw();
+  }
+  return UnixSocketRaw(std::move(fd), family, type);
+}
+
+// static
 std::pair<UnixSocketRaw, UnixSocketRaw> UnixSocketRaw::CreatePair(
     SockFamily family,
     SockType type) {
diff --git a/src/perfetto_cmd/BUILD.gn b/src/perfetto_cmd/BUILD.gn
index 969b732..6e920a9 100644
--- a/src/perfetto_cmd/BUILD.gn
+++ b/src/perfetto_cmd/BUILD.gn
@@ -61,7 +61,6 @@
     ":perfetto_atoms",
     ":trigger_producer",
     "../../gn:default_deps",
-    "../../gn:zlib",
     "../../protos/perfetto/common:cpp",
     "../../protos/perfetto/config:cpp",
     "../../protos/perfetto/config/ftrace:cpp",
@@ -70,6 +69,9 @@
     "../protozero",
     "../tracing:ipc",
   ]
+  if (enable_perfetto_zlib) {
+    deps += [ "../../gn:zlib" ]
+  }
   sources = [
     "config.cc",
     "config.h",
@@ -131,7 +133,6 @@
     ":perfetto_cmd",
     "../../gn:default_deps",
     "../../gn:gtest_and_gmock",
-    "../../gn:zlib",
     "../../include/perfetto/base",
     "../../include/perfetto/ext/base",
     "../../protos/perfetto/config:cpp",
@@ -139,6 +140,9 @@
     "../../protos/perfetto/trace:cpp",
     "../tracing",
   ]
+  if (enable_perfetto_zlib) {
+    deps += [ "../../gn:zlib" ]
+  }
   sources = [
     "config_unittest.cc",
     "packet_writer_unittest.cc",
diff --git a/src/perfetto_cmd/packet_writer.cc b/src/perfetto_cmd/packet_writer.cc
index 9d5a8d6..2fb0562 100644
--- a/src/perfetto_cmd/packet_writer.cc
+++ b/src/perfetto_cmd/packet_writer.cc
@@ -24,13 +24,17 @@
 #include <stdio.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <zlib.h>
 
+#include "perfetto/base/build_config.h"
 #include "perfetto/ext/base/paged_memory.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/protozero/proto_utils.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#endif
+
 namespace perfetto {
 namespace {
 
@@ -43,14 +47,20 @@
 // ID of the |packet| field in trace.proto. Hardcoded as this we don't
 // want to depend on protos/trace:lite for binary size saving reasons.
 constexpr uint32_t kPacketId = 1;
+
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 // ID of |compressed_packets| in trace_packet.proto.
 constexpr uint32_t kCompressedPacketsId = 50;
 
 // Maximum allowable size for a single packet.
 const size_t kMaxPacketSize = 500 * 1024;
+
 // After every kPendingBytesLimit we do a Z_SYNC_FLUSH in the zlib stream.
 const size_t kPendingBytesLimit = 32 * 1024;
 
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 template <uint32_t id>
 size_t GetPreamble(size_t sz, Preamble* preamble) {
   uint8_t* ptr = reinterpret_cast<uint8_t*>(preamble->data());
@@ -73,6 +83,31 @@
   FILE* fd_;
 };
 
+FilePacketWriter::FilePacketWriter(FILE* fd) : fd_(fd) {}
+
+FilePacketWriter::~FilePacketWriter() {
+  fflush(fd_);
+}
+
+bool FilePacketWriter::WritePackets(const std::vector<TracePacket>& packets) {
+  for (const TracePacket& packet : packets) {
+    Preamble preamble;
+    size_t size = GetPreamble<kPacketId>(packet.size(), &preamble);
+    if (fwrite(preamble.data(), 1, size, fd_) != size)
+      return false;
+    for (const Slice& slice : packet.slices()) {
+      if (fwrite(reinterpret_cast<const char*>(slice.start), 1, slice.size,
+                 fd_) != slice.size) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 class ZipPacketWriter : public PacketWriter {
  public:
   ZipPacketWriter(std::unique_ptr<PacketWriter>);
@@ -102,29 +137,6 @@
   size_t pending_bytes_ = 0;
 };
 
-FilePacketWriter::FilePacketWriter(FILE* fd) : fd_(fd) {}
-
-FilePacketWriter::~FilePacketWriter() {
-  fflush(fd_);
-}
-
-bool FilePacketWriter::WritePackets(const std::vector<TracePacket>& packets) {
-  for (const TracePacket& packet : packets) {
-    Preamble preamble;
-    size_t size = GetPreamble<kPacketId>(packet.size(), &preamble);
-    if (fwrite(preamble.data(), 1, size, fd_) != size)
-      return false;
-    for (const Slice& slice : packet.slices()) {
-      if (fwrite(reinterpret_cast<const char*>(slice.start), 1, slice.size,
-                 fd_) != slice.size) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 ZipPacketWriter::ZipPacketWriter(std::unique_ptr<PacketWriter> writer)
     : writer_(std::move(writer)),
       buf_(base::PagedMemory::Allocate(kMaxPacketSize)),
@@ -237,6 +249,8 @@
   pending_bytes_ += size;
 }
 
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 }  // namespace
 
 PacketWriter::PacketWriter() {}
@@ -247,9 +261,11 @@
   return std::unique_ptr<PacketWriter>(new FilePacketWriter(fd));
 }
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 std::unique_ptr<PacketWriter> CreateZipPacketWriter(
     std::unique_ptr<PacketWriter> writer) {
   return std::unique_ptr<PacketWriter>(new ZipPacketWriter(std::move(writer)));
 }
+#endif
 
 }  // namespace perfetto
diff --git a/src/perfetto_cmd/packet_writer_unittest.cc b/src/perfetto_cmd/packet_writer_unittest.cc
index c1fab21..fbf9603 100644
--- a/src/perfetto_cmd/packet_writer_unittest.cc
+++ b/src/perfetto_cmd/packet_writer_unittest.cc
@@ -21,8 +21,7 @@
 
 #include <random>
 
-#include <zlib.h>
-
+#include "perfetto/base/build_config.h"
 #include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/scoped_file.h"
 #include "perfetto/ext/base/temp_file.h"
@@ -34,6 +33,10 @@
 #include "protos/perfetto/trace/trace.gen.h"
 #include "protos/perfetto/trace/trace_packet.gen.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#endif
+
 namespace perfetto {
 namespace {
 
@@ -51,6 +54,7 @@
   return packet;
 }
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 std::string Decompress(const std::string& data) {
   uint8_t out[1024];
 
@@ -76,6 +80,7 @@
   inflateEnd(&stream);
   return s;
 }
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 
 TEST(PacketWriterTest, FilePacketWriter) {
   base::TempFile tmp = base::TempFile::Create();
@@ -105,6 +110,8 @@
   EXPECT_EQ(trace.packet()[0].for_testing().str(), "abc");
 }
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 TEST(PacketWriterTest, ZipPacketWriter) {
   base::TempFile tmp = base::TempFile::Create();
   base::ScopedResource<FILE*, fclose, nullptr> f(
@@ -281,5 +288,7 @@
   EXPECT_EQ(packet_count, 1000u);
 }
 
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 }  // namespace
 }  // namespace perfetto
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 638112f..bb48f6f 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -603,7 +603,11 @@
   if (trace_config_->compression_type() ==
       TraceConfig::COMPRESSION_TYPE_DEFLATE) {
     if (packet_writer_) {
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
       packet_writer_ = CreateZipPacketWriter(std::move(packet_writer_));
+#else
+      PERFETTO_ELOG("Cannot compress. Zlib not enabled in the build config");
+#endif
     } else {
       PERFETTO_ELOG("Cannot compress when tracing directly to file.");
     }
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 0455917..ebabeb3 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -88,8 +88,6 @@
     "ftrace_utils.h",
     "global_args_tracker.cc",
     "global_args_tracker.h",
-    "gzip_trace_parser.cc",
-    "gzip_trace_parser.h",
     "heap_profile_tracker.cc",
     "heap_profile_tracker.h",
     "importers/ftrace/ftrace_module.cc",
@@ -140,11 +138,9 @@
     "track_tracker.h",
     "virtual_destructors.cc",
   ]
-
   deps = [
     ":descriptors",
     "../../gn:default_deps",
-    "../../gn:zlib",
     "../base",
     "../protozero",
     "containers",
@@ -167,6 +163,13 @@
     "../../protos/perfetto/trace/sys_stats:zero",
     "../../protos/perfetto/trace/track_event:zero",
   ]
+  if (enable_perfetto_zlib) {
+    sources += [
+      "gzip_trace_parser.cc",
+      "gzip_trace_parser.h",
+    ]
+    deps += [ "../../gn:zlib" ]
+  }
   if (enable_perfetto_trace_processor_json_import) {
     sources += [
       "importers/json/json_trace_parser.cc",
diff --git a/src/trace_processor/containers/string_pool.cc b/src/trace_processor/containers/string_pool.cc
index 167d285..ac45ceb 100644
--- a/src/trace_processor/containers/string_pool.cc
+++ b/src/trace_processor/containers/string_pool.cc
@@ -81,7 +81,7 @@
 
   // Compute the id from the block index and offset and add a mapping from the
   // hash to the id.
-  Id string_id = BlockIndexAndOffsetToId(blocks_.size() - 1, offset);
+  Id string_id = Id::BlockString(blocks_.size() - 1, offset);
   string_index_.emplace(hash, string_id);
   return string_id;
 }
@@ -90,7 +90,7 @@
                                              uint64_t hash) {
   large_strings_.emplace_back(new std::string(str.begin(), str.size()));
   // Compute id from the index and add a mapping from the hash to the id.
-  Id string_id = LargeStringIndexToId(large_strings_.size() - 1);
+  Id string_id = Id::LargeString(large_strings_.size() - 1);
   string_index_.emplace(hash, string_id);
   return string_id;
 }
@@ -172,11 +172,11 @@
 
     // If we're at (0, 0), we have the null string which has id 0.
     if (block_index_ == 0 && block_offset_ == 0)
-      return 0;
-    return BlockIndexAndOffsetToId(block_index_, block_offset_);
+      return Id::Null();
+    return Id::BlockString(block_index_, block_offset_);
   }
   PERFETTO_DCHECK(large_strings_index_ < pool_->large_strings_.size());
-  return LargeStringIndexToId(large_strings_index_);
+  return Id::LargeString(large_strings_index_);
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/containers/string_pool.h b/src/trace_processor/containers/string_pool.h
index 0f50bcc..154bfb2 100644
--- a/src/trace_processor/containers/string_pool.h
+++ b/src/trace_processor/containers/string_pool.h
@@ -37,7 +37,6 @@
  public:
   struct Id {
     Id() = default;
-    constexpr Id(uint32_t i) : id(i) {}
 
     bool operator==(const Id& other) const { return other.id == id; }
     bool operator!=(const Id& other) const { return !(other == *this); }
@@ -45,6 +44,42 @@
 
     bool is_null() const { return id == 0u; }
 
+    bool is_large_string() const { return id & kLargeStringFlagBitMask; }
+
+    uint32_t block_offset() const { return id & kBlockOffsetBitMask; }
+
+    uint32_t block_index() const {
+      return (id & kBlockIndexBitMask) >> kNumBlockOffsetBits;
+    }
+
+    uint32_t large_string_index() const {
+      PERFETTO_DCHECK(is_large_string());
+      return id & ~kLargeStringFlagBitMask;
+    }
+
+    uint32_t raw_id() const { return id; }
+
+    static Id LargeString(size_t index) {
+      PERFETTO_DCHECK(index <= static_cast<uint32_t>(index));
+      PERFETTO_DCHECK(!(index & kLargeStringFlagBitMask));
+      return Id(kLargeStringFlagBitMask | static_cast<uint32_t>(index));
+    }
+
+    static Id BlockString(size_t index, uint32_t offset) {
+      PERFETTO_DCHECK(index < (1u << (kNumBlockIndexBits + 1)));
+      PERFETTO_DCHECK(offset < (1u << (kNumBlockOffsetBits + 1)));
+      return Id(~kLargeStringFlagBitMask &
+                (static_cast<uint32_t>(index << kNumBlockOffsetBits) |
+                 (offset & kBlockOffsetBitMask)));
+    }
+
+    static constexpr Id Raw(uint32_t raw) { return Id(raw); }
+
+    static constexpr Id Null() { return Id(0u); }
+
+   private:
+    constexpr Id(uint32_t i) : id(i) {}
+
     uint32_t id;
   };
 
@@ -79,7 +114,7 @@
 
   Id InternString(base::StringView str) {
     if (str.data() == nullptr)
-      return Id(0);
+      return Id::Null();
 
     auto hash = str.Hash();
     auto id_it = string_index_.find(hash);
@@ -92,7 +127,7 @@
 
   base::Optional<Id> GetId(base::StringView str) const {
     if (str.data() == nullptr)
-      return Id(0u);
+      return Id::Null();
 
     auto hash = str.Hash();
     auto id_it = string_index_.find(hash);
@@ -104,9 +139,9 @@
   }
 
   NullTermStringView Get(Id id) const {
-    if (id.id == 0)
+    if (id.is_null())
       return NullTermStringView();
-    if (id.id & kLargeStringFlagBitMask)
+    if (id.is_large_string())
       return GetLargeString(id);
     return GetFromBlockPtr(IdToPtr(id));
   }
@@ -199,10 +234,10 @@
   const uint8_t* IdToPtr(Id id) const {
     // If the MSB is set, the ID represents an index into |large_strings_|, so
     // shouldn't be converted into a block pointer.
-    PERFETTO_DCHECK(!(id.id & kLargeStringFlagBitMask));
+    PERFETTO_DCHECK(!id.is_large_string());
 
-    size_t block_index = (id.id & kBlockIndexBitMask) >> kNumBlockOffsetBits;
-    uint32_t block_offset = id.id & kBlockOffsetBitMask;
+    size_t block_index = id.block_index();
+    uint32_t block_offset = id.block_offset();
 
     PERFETTO_DCHECK(block_index < blocks_.size());
     PERFETTO_DCHECK(block_offset < blocks_[block_index].pos());
@@ -210,20 +245,6 @@
     return blocks_[block_index].Get(block_offset);
   }
 
-  static Id BlockIndexAndOffsetToId(size_t index, uint32_t offset) {
-    PERFETTO_DCHECK(index < (1u << (kNumBlockIndexBits + 1)));
-    PERFETTO_DCHECK(offset < (1u << (kNumBlockOffsetBits + 1)));
-    return Id(~kLargeStringFlagBitMask &
-              (static_cast<uint32_t>(index << kNumBlockOffsetBits) |
-               (offset & kBlockOffsetBitMask)));
-  }
-
-  static Id LargeStringIndexToId(size_t index) {
-    PERFETTO_DCHECK(index <= static_cast<uint32_t>(index) &&
-                    !(index & kLargeStringFlagBitMask));
-    return Id(kLargeStringFlagBitMask | static_cast<uint32_t>(index));
-  }
-
   // |ptr| should point to the start of the string metadata (i.e. the first byte
   // of the size).
   // Returns pointer to the start of the string.
@@ -248,8 +269,8 @@
   // Lookup a string in the |large_strings_| vector. |id| should have the MSB
   // set.
   NullTermStringView GetLargeString(Id id) const {
-    PERFETTO_DCHECK(id.id & kLargeStringFlagBitMask);
-    size_t index = id.id & ~kLargeStringFlagBitMask;
+    PERFETTO_DCHECK(id.is_large_string());
+    size_t index = id.large_string_index();
     PERFETTO_DCHECK(index < large_strings_.size());
     const std::string* str = large_strings_[index].get();
     return NullTermStringView(str->c_str(), str->size());
@@ -280,7 +301,7 @@
   using result_type = size_t;
 
   result_type operator()(const argument_type& r) const {
-    return std::hash<uint32_t>{}(r.id);
+    return std::hash<uint32_t>{}(r.raw_id());
   }
 };
 
diff --git a/src/trace_processor/containers/string_pool_unittest.cc b/src/trace_processor/containers/string_pool_unittest.cc
index 37d85d8..eb6dc1b 100644
--- a/src/trace_processor/containers/string_pool_unittest.cc
+++ b/src/trace_processor/containers/string_pool_unittest.cc
@@ -27,8 +27,6 @@
 class StringPoolTest : public testing::Test {
  protected:
   static constexpr size_t kNumBlockOffsetBits = StringPool::kNumBlockOffsetBits;
-  static constexpr size_t kLargeStringFlagBitMask =
-      StringPool::kLargeStringFlagBitMask;
   static constexpr size_t kBlockIndexBitMask = StringPool::kBlockIndexBitMask;
   static constexpr size_t kBlockSizeBytes = StringPool::kBlockSizeBytes;
   static constexpr size_t kMinLargeStringSizeBytes =
@@ -40,7 +38,7 @@
 namespace {
 
 TEST_F(StringPoolTest, EmptyPool) {
-  ASSERT_EQ(pool_.Get(0).c_str(), nullptr);
+  ASSERT_EQ(pool_.Get(StringPool::Id::Null()).c_str(), nullptr);
 
   auto it = pool_.CreateIterator();
   ASSERT_TRUE(it);
@@ -58,7 +56,7 @@
 
 TEST_F(StringPoolTest, NullPointerHandling) {
   auto id = pool_.InternString(NullTermStringView());
-  ASSERT_EQ(id, 0u);
+  ASSERT_TRUE(id.is_null());
   ASSERT_EQ(pool_.Get(id).c_str(), nullptr);
 }
 
@@ -122,7 +120,7 @@
     auto it_pair = string_map.equal_range(it.StringId());
     for (auto in_it = it_pair.first; in_it != it_pair.second; ++in_it) {
       ASSERT_EQ(it.StringView(), in_it->second)
-          << it.StringId().id << ": " << it.StringView().Hash() << " vs "
+          << it.StringId().raw_id() << ": " << it.StringView().Hash() << " vs "
           << in_it->second.Hash();
     }
     string_map.erase(it_pair.first, it_pair.second);
@@ -178,21 +176,21 @@
                                  big_strings[i].get(), kStringSizes[i])));
   }
 
-  ASSERT_FALSE(string_ids[0].id & kLargeStringFlagBitMask);
-  ASSERT_FALSE(string_ids[1].id & kLargeStringFlagBitMask);
-  ASSERT_TRUE(string_ids[2].id & kLargeStringFlagBitMask);
-  ASSERT_FALSE(string_ids[3].id & kLargeStringFlagBitMask);
-  ASSERT_FALSE(string_ids[4].id & kLargeStringFlagBitMask);
-  ASSERT_FALSE(string_ids[5].id & kLargeStringFlagBitMask);
-  ASSERT_TRUE(string_ids[6].id & kLargeStringFlagBitMask);
-  ASSERT_FALSE(string_ids[7].id & kLargeStringFlagBitMask);
+  ASSERT_FALSE(string_ids[0].is_large_string());
+  ASSERT_FALSE(string_ids[1].is_large_string());
+  ASSERT_TRUE(string_ids[2].is_large_string());
+  ASSERT_FALSE(string_ids[3].is_large_string());
+  ASSERT_FALSE(string_ids[4].is_large_string());
+  ASSERT_FALSE(string_ids[5].is_large_string());
+  ASSERT_TRUE(string_ids[6].is_large_string());
+  ASSERT_FALSE(string_ids[7].is_large_string());
 
-  ASSERT_EQ(string_ids[0].id & kBlockIndexBitMask, 0u << kNumBlockOffsetBits);
-  ASSERT_EQ(string_ids[1].id & kBlockIndexBitMask, 0u << kNumBlockOffsetBits);
-  ASSERT_EQ(string_ids[3].id & kBlockIndexBitMask, 0u << kNumBlockOffsetBits);
-  ASSERT_EQ(string_ids[4].id & kBlockIndexBitMask, 0u << kNumBlockOffsetBits);
-  ASSERT_EQ(string_ids[5].id & kBlockIndexBitMask, 1u << kNumBlockOffsetBits);
-  ASSERT_EQ(string_ids[7].id & kBlockIndexBitMask, 1u << kNumBlockOffsetBits);
+  ASSERT_EQ(string_ids[0].block_index(), 0u);
+  ASSERT_EQ(string_ids[1].block_index(), 0u);
+  ASSERT_EQ(string_ids[3].block_index(), 0u);
+  ASSERT_EQ(string_ids[4].block_index(), 0u);
+  ASSERT_EQ(string_ids[5].block_index(), 1u);
+  ASSERT_EQ(string_ids[7].block_index(), 1u);
 
   for (size_t i = 0; i < big_strings.size(); i++) {
     ASSERT_EQ(big_strings[i].get(), pool_.Get(string_ids[i]));
diff --git a/src/trace_processor/db/typed_column.h b/src/trace_processor/db/typed_column.h
index a7183f6..9a3dd5e 100644
--- a/src/trace_processor/db/typed_column.h
+++ b/src/trace_processor/db/typed_column.h
@@ -189,7 +189,7 @@
     // TODO(lalitm): remove this special casing if we migrate all tables over
     // to macro tables and find that we can remove support for null stringids
     // in the stringpool.
-    return TypedColumn<StringPool::Id>::Append(v ? *v : StringPool::Id(0u));
+    return TypedColumn<StringPool::Id>::Append(v ? *v : StringPool::Id::Null());
   }
 
   // Implements equality between two items of type |T|.
diff --git a/src/trace_processor/event_tracker.h b/src/trace_processor/event_tracker.h
index 983dad0..bde0588 100644
--- a/src/trace_processor/event_tracker.h
+++ b/src/trace_processor/event_tracker.h
@@ -76,7 +76,7 @@
   // Represents a counter event which is currently pending upid resolution.
   struct PendingUpidResolutionCounter {
     uint32_t row = 0;
-    StringId name_id = 0;
+    StringId name_id = kNullStringId;
     UniqueTid utid = 0;
   };
 
diff --git a/src/trace_processor/event_tracker_unittest.cc b/src/trace_processor/event_tracker_unittest.cc
index f4e20cb..d8f41ed 100644
--- a/src/trace_processor/event_tracker_unittest.cc
+++ b/src/trace_processor/event_tracker_unittest.cc
@@ -114,7 +114,7 @@
 TEST_F(EventTrackerTest, CounterDuration) {
   uint32_t cpu = 3;
   int64_t timestamp = 100;
-  StringId name_id = 0;
+  StringId name_id = kNullStringId;
 
   TrackId track = context.track_tracker->InternCpuCounterTrack(name_id, cpu);
   context.event_tracker->PushCounter(timestamp, 1000, track);
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index c7cf7ab..b1f92f4 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -226,7 +226,7 @@
 TEST_F(ExportJsonTest, SystemEventsIgnored) {
   constexpr int64_t kCookie = 22;
   TrackId track = context_.track_tracker->InternAndroidAsyncTrack(
-      /*name=*/0, /*upid=*/0, kCookie);
+      /*name=*/kNullStringId, /*upid=*/0, kCookie);
   context_.args_tracker->Flush();  // Flush track args.
 
   // System events have no category.
@@ -794,7 +794,7 @@
   constexpr int64_t kSourceId = 235;
   TrackId track = context_.track_tracker->InternLegacyChromeAsyncTrack(
       name_id, upid, kSourceId, /*source_id_is_process_scoped=*/true,
-      /*source_scope=*/0);
+      /*source_scope=*/kNullStringId);
   context_.args_tracker->Flush();  // Flush track args.
 
   context_.storage->mutable_slice_table()->Insert(
@@ -885,7 +885,7 @@
   constexpr int64_t kSourceId = 235;
   TrackId track = context_.track_tracker->InternLegacyChromeAsyncTrack(
       name_id, upid, kSourceId, /*source_id_is_process_scoped=*/true,
-      /*source_scope=*/0);
+      /*source_scope=*/kNullStringId);
   context_.args_tracker->Flush();  // Flush track args.
 
   auto slice_id = context_.storage->mutable_slice_table()->Insert(
@@ -940,7 +940,7 @@
   constexpr int64_t kSourceId = 235;
   TrackId track = context_.track_tracker->InternLegacyChromeAsyncTrack(
       name_id, upid, kSourceId, /*source_id_is_process_scoped=*/true,
-      /*source_scope=*/0);
+      /*source_scope=*/kNullStringId);
   context_.args_tracker->Flush();  // Flush track args.
 
   auto slice_id = context_.storage->mutable_slice_table()->Insert(
@@ -983,7 +983,7 @@
   constexpr int64_t kSourceId = 235;
   TrackId track = context_.track_tracker->InternLegacyChromeAsyncTrack(
       name_id, upid, kSourceId, /*source_id_is_process_scoped=*/true,
-      /*source_scope=*/0);
+      /*source_scope=*/kNullStringId);
   context_.args_tracker->Flush();  // Flush track args.
 
   context_.storage->mutable_slice_table()->Insert(
@@ -1174,10 +1174,11 @@
 
   // TODO(140860736): Once we support null values for
   // stack_profile_frame.symbol_set_id remove this hack
-  storage->mutable_symbol_table()->Insert({0, 0, 0, 0});
+  storage->mutable_symbol_table()->Insert({0, kNullStringId, kNullStringId, 0});
 
   auto* frames = storage->mutable_stack_profile_frame_table();
-  auto frame_id_1 = frames->Insert({/*name_id=*/0, module_id_1.value, 0x42});
+  auto frame_id_1 =
+      frames->Insert({/*name_id=*/kNullStringId, module_id_1.value, 0x42});
   uint32_t frame_row_1 = *frames->id().IndexOf(frame_id_1);
 
   uint32_t symbol_set_id = storage->symbol_table().row_count();
@@ -1186,7 +1187,8 @@
        storage->InternString("foo_file"), 66});
   frames->mutable_symbol_set_id()->Set(frame_row_1, symbol_set_id);
 
-  auto frame_id_2 = frames->Insert({/*name_id=*/0, module_id_2.value, 0x4242});
+  auto frame_id_2 =
+      frames->Insert({/*name_id=*/kNullStringId, module_id_2.value, 0x4242});
   uint32_t frame_row_2 = *frames->id().IndexOf(frame_id_2);
 
   symbol_set_id = storage->symbol_table().row_count();
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
index ea63b8e..89798f2 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -39,6 +39,11 @@
 namespace trace_processor {
 namespace {
 
+#if !PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+const char kNoZlibErr[] =
+    "Cannot open compressed trace. zlib not enabled in the build config";
+#endif
+
 inline bool isspace(unsigned char c) {
   return ::isspace(c);
 }
@@ -119,12 +124,20 @@
         }
       case kGzipTraceType:
         PERFETTO_DLOG("gzip trace detected");
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
         reader_.reset(new GzipTraceParser(context_));
         break;
+#else
+        return util::ErrStatus(kNoZlibErr);
+#endif
       case kCtraceTraceType:
         PERFETTO_DLOG("ctrace trace detected");
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
         reader_.reset(new GzipTraceParser(context_));
         break;
+#else
+        return util::ErrStatus(kNoZlibErr);
+#endif
       case kUnknownTraceType:
         return util::ErrStatus("Unknown trace type provided");
     }
diff --git a/src/trace_processor/global_args_tracker.h b/src/trace_processor/global_args_tracker.h
index 09cf9af..74c5152 100644
--- a/src/trace_processor/global_args_tracker.h
+++ b/src/trace_processor/global_args_tracker.h
@@ -31,8 +31,8 @@
 class GlobalArgsTracker {
  public:
   struct Arg {
-    StringId flat_key = 0;
-    StringId key = 0;
+    StringId flat_key = kNullStringId;
+    StringId key = kNullStringId;
     Variadic value = Variadic::Integer(0);
 
     Column* column;
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index 3f5bec5..10eacfe 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -98,7 +98,7 @@
 
   struct FtraceMessageStrings {
     // The string id of name of the event field (e.g. sched_switch's id).
-    StringId message_name_id = 0;
+    StringId message_name_id = kNullStringId;
     std::array<StringId, kMaxFtraceEventFields> field_name_ids;
   };
   std::vector<FtraceMessageStrings> ftrace_message_strings_;
@@ -108,9 +108,9 @@
     MmEventCounterNames(StringId _count, StringId _max_lat, StringId _avg_lat)
         : count(_count), max_lat(_max_lat), avg_lat(_avg_lat) {}
 
-    StringId count = 0;
-    StringId max_lat = 0;
-    StringId avg_lat = 0;
+    StringId count = kNullStringId;
+    StringId max_lat = kNullStringId;
+    StringId avg_lat = kNullStringId;
   };
 
   // Keep kMmEventCounterSize equal to mm_event_type::MM_TYPE_NUM in the kernel.
diff --git a/src/trace_processor/importers/proto/graphics_event_parser.cc b/src/trace_processor/importers/proto/graphics_event_parser.cc
index 5d55216..eb58594 100644
--- a/src/trace_processor/importers/proto/graphics_event_parser.cc
+++ b/src/trace_processor/importers/proto/graphics_event_parser.cc
@@ -170,7 +170,7 @@
         gpu_counter_track_ids_.end()) {
       auto desc = spec.description();
 
-      StringId unit_id = 0;
+      StringId unit_id = kNullStringId;
       if (spec.has_numerator_units() || spec.has_denominator_units()) {
         char buffer[1024];
         base::StringWriter unit(buffer, sizeof(buffer));
@@ -277,7 +277,7 @@
   StringId track_name = context_->storage->InternString(hw_queue.name());
   if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size() ||
       !gpu_hw_queue_ids_[gpu_hw_queue_counter_].has_value()) {
-    tables::GpuTrackTable::Row track(track_name.id);
+    tables::GpuTrackTable::Row track(track_name);
     track.scope = gpu_render_stage_scope_id_;
     track.description = context_->storage->InternString(hw_queue.description());
     if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size()) {
@@ -304,7 +304,7 @@
       context_->storage->mutable_gpu_track_table()->mutable_description()->Set(
           row, context_->storage->InternString(hw_queue.description()));
     } else {
-      tables::GpuTrackTable::Row track(track_name.id);
+      tables::GpuTrackTable::Row track(track_name);
       track.scope = gpu_render_stage_scope_id_;
       track.description =
           context_->storage->InternString(hw_queue.description());
@@ -426,7 +426,7 @@
       }
       StringId track_name =
           context_->storage->InternString(writer.GetStringView());
-      tables::GpuTrackTable::Row track(track_name.id);
+      tables::GpuTrackTable::Row track(track_name);
       track.scope = gpu_render_stage_scope_id_;
       track_id = context_->track_tracker->InternGpuTrack(track);
       gpu_hw_queue_ids_.resize(hw_queue_id + 1);
@@ -508,7 +508,7 @@
   const uint32_t frame_number =
       event.has_frame_number() ? event.frame_number() : 0;
 
-  tables::GpuTrackTable::Row track(track_name_id.id);
+  tables::GpuTrackTable::Row track(track_name_id);
   track.scope = graphics_event_scope_id_;
   TrackId track_id = context_->track_tracker->InternGpuTrack(track);
 
@@ -532,7 +532,7 @@
     if (previous_timestamp_ == 0) {
       const StringId present_track_name_id =
           context_->storage->InternString("Displayed Frame");
-      tables::GpuTrackTable::Row present_track(present_track_name_id.id);
+      tables::GpuTrackTable::Row present_track(present_track_name_id);
       present_track.scope = graphics_event_scope_id_;
       present_track_id_ =
           context_->track_tracker->InternGpuTrack(present_track);
@@ -770,7 +770,7 @@
                     sequence_state,
                     static_cast<uint64_t>(annotation.string_iid()));
 
-        inserter.AddArg(key_id, Variadic::String(string_id.id));
+        inserter.AddArg(key_id, Variadic::String(string_id));
       }
     }
   }
@@ -779,7 +779,7 @@
 void GraphicsEventParser::ParseGpuLog(int64_t ts, ConstBytes blob) {
   protos::pbzero::GpuLog::Decoder event(blob.data, blob.size);
 
-  tables::GpuTrackTable::Row track(gpu_log_track_name_id_.id);
+  tables::GpuTrackTable::Row track(gpu_log_track_name_id_);
   track.scope = gpu_log_scope_id_;
   TrackId track_id = context_->track_tracker->InternGpuTrack(track);
 
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index 7942263..3c1001f 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -121,7 +121,7 @@
     sequence_state.object_id_to_row.emplace(obj.object_id, row);
     class_to_rows_[type_name].emplace_back(row);
     sequence_state.walker.AddNode(row, obj.self_size,
-                                  static_cast<int32_t>(type_name.id));
+                                  static_cast<int32_t>(type_name.raw_id()));
   }
 
   for (const SourceObject& obj : sequence_state.current_objects) {
@@ -230,7 +230,7 @@
 
     tables::StackProfileFrameTable::Row row{};
     PERFETTO_CHECK(node.class_name > 0);
-    row.name = StringId(static_cast<uint32_t>(node.class_name));
+    row.name = StringId::Raw(static_cast<uint32_t>(node.class_name));
     row.mapping = mapping_row;
 
     auto id =
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index ce48d17..b2b852f 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -174,7 +174,8 @@
           context->storage->InternString("chrome_event.legacy_user_trace")) {
   // TODO(140860736): Once we support null values for
   // stack_profile_frame.symbol_set_id remove this hack
-  context_->storage->mutable_symbol_table()->Insert({0, 0, 0, 0});
+  context_->storage->mutable_symbol_table()->Insert(
+      {0, kNullStringId, kNullStringId, 0});
 }
 
 ProtoTraceParser::~ProtoTraceParser() = default;
@@ -455,7 +456,8 @@
     int64_t callstack_id = *maybe_callstack_id;
 
     tables::CpuProfileStackSampleTable::Row sample_row{
-        sequence_state->state()->IncrementAndGetTrackEventTimeNs(*timestamp_it),
+        sequence_state->state()->IncrementAndGetTrackEventTimeNs(*timestamp_it *
+                                                                 1000),
         callstack_id, utid};
     storage->mutable_cpu_profile_stack_sample_table()->Insert(sample_row);
   }
@@ -575,7 +577,7 @@
   auto utid = context_->process_tracker->GetOrCreateThread(event.thread_id());
 
   StringId cat_id = metatrace_id_;
-  StringId name_id = 0;
+  StringId name_id = kNullStringId;
   char fallback[64];
 
   if (event.has_event_id()) {
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index c6b789d..adb1a2e 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -155,25 +155,6 @@
                void(UniquePid upid, StringId process_name_id));
 };
 
-// Mock trace storage that behaves like the real implementation, but allows for
-// the interactions with string interning/lookup to be overridden/inspected.
-class MockTraceStorage : public TraceStorage {
- public:
-  MockTraceStorage() : TraceStorage() {
-    ON_CALL(*this, InternString(_))
-        .WillByDefault(Invoke([this](base::StringView str) {
-          return TraceStorage::InternString(str);
-        }));
-
-    ON_CALL(*this, GetString(_)).WillByDefault(Invoke([this](StringId id) {
-      return TraceStorage::GetString(id);
-    }));
-  }
-
-  MOCK_METHOD1(InternString, StringId(base::StringView));
-  MOCK_CONST_METHOD1(GetString, NullTermStringView(StringId));
-};
-
 class MockBoundInserter : public ArgsTracker::BoundInserter {
  public:
   MockBoundInserter() : ArgsTracker::BoundInserter(nullptr, nullptr, 0u) {
@@ -214,7 +195,7 @@
 class ProtoTraceParserTest : public ::testing::Test {
  public:
   ProtoTraceParserTest() {
-    storage_ = new NiceMock<MockTraceStorage>();
+    storage_ = new TraceStorage();
     context_.storage.reset(storage_);
     context_.track_tracker.reset(new TrackTracker(&context_));
     context_.global_args_tracker.reset(new GlobalArgsTracker(&context_));
@@ -285,7 +266,7 @@
   MockProcessTracker* process_;
   MockSliceTracker* slice_;
   ClockTracker* clock_;
-  NiceMock<MockTraceStorage>* storage_;
+  TraceStorage* storage_;
 };
 
 // TODO(eseckler): Refactor these into a new file for ftrace tests.
@@ -388,12 +369,6 @@
   field->set_name("meta3");
   field->set_uint_value(3);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("Test")));
-  EXPECT_CALL(*storage_, InternString(base::StringView("meta1")));
-  EXPECT_CALL(*storage_, InternString(base::StringView("value1")));
-  EXPECT_CALL(*storage_, InternString(base::StringView("meta2")));
-  EXPECT_CALL(*storage_, InternString(base::StringView("meta3")));
-
   Tokenize();
 
   const auto& raw = storage_->raw_table();
@@ -402,18 +377,23 @@
   ASSERT_EQ(raw.ts()[raw.row_count() - 1], 100);
   ASSERT_EQ(storage_->thread_table().tid()[raw.utid()[raw.row_count() - 1]],
             10u);
+  ASSERT_EQ(raw.name().GetString(raw.row_count() - 1), "Test");
 
   auto set_id = raw.arg_set_id()[raw.row_count() - 1];
 
   const auto& args = storage_->arg_table();
   RowMap rm = args.FilterToRowMap({args.arg_set_id().eq(set_id)});
 
-  // Ignore string calls as they are handled by checking InternString calls
-  // above.
-
   auto row = rm.Get(0);
-  ASSERT_EQ(args.int_value()[++row], -2);
-  ASSERT_EQ(args.int_value()[++row], 3);
+
+  ASSERT_EQ(args.key().GetString(row), "meta1");
+  ASSERT_EQ(args.string_value().GetString(row++), "value1");
+
+  ASSERT_EQ(args.key().GetString(row), "meta2");
+  ASSERT_EQ(args.int_value()[row++], -2);
+
+  ASSERT_EQ(args.key().GetString(row), "meta3");
+  ASSERT_EQ(args.int_value()[row++], 3);
 }
 
 TEST_F(ProtoTraceParserTest, LoadMultipleEvents) {
@@ -667,16 +647,14 @@
       .WillRepeatedly(testing::Return(1u));
   EXPECT_CALL(*process_, GetOrCreateProcess(16)).WillOnce(testing::Return(2u));
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("OldProcessName")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*process_, SetProcessNameIfUnset(1u, StringId(1)));
+  EXPECT_CALL(*process_, SetProcessNameIfUnset(
+                             1u, storage_->InternString("OldProcessName")));
   // Packet with same thread, but different name should update the name.
-  EXPECT_CALL(*storage_, InternString(base::StringView("NewProcessName")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*process_, SetProcessNameIfUnset(1u, StringId(2)));
-  EXPECT_CALL(*storage_, InternString(base::StringView("DifferentProcessName")))
-      .WillOnce(Return(3));
-  EXPECT_CALL(*process_, SetProcessNameIfUnset(2u, StringId(3)));
+  EXPECT_CALL(*process_, SetProcessNameIfUnset(
+                             1u, storage_->InternString("NewProcessName")));
+  EXPECT_CALL(*process_,
+              SetProcessNameIfUnset(
+                  2u, storage_->InternString("DifferentProcessName")));
 
   Tokenize();
   context_.sorter->ExtractEventsForced();
@@ -723,16 +701,14 @@
       .WillRepeatedly(testing::Return(1u));
   EXPECT_CALL(*process_, UpdateThread(11, 15)).WillOnce(testing::Return(2u));
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("OldThreadName")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*process_, SetThreadNameIfUnset(1u, StringId(1)));
+  EXPECT_CALL(*process_, SetThreadNameIfUnset(
+                             1u, storage_->InternString("OldThreadName")));
   // Packet with same thread, but different name should update the name.
-  EXPECT_CALL(*storage_, InternString(base::StringView("NewThreadName")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*process_, SetThreadNameIfUnset(1u, StringId(2)));
-  EXPECT_CALL(*storage_, InternString(base::StringView("DifferentThreadName")))
-      .WillOnce(Return(3));
-  EXPECT_CALL(*process_, SetThreadNameIfUnset(2u, StringId(3)));
+  EXPECT_CALL(*process_, SetThreadNameIfUnset(
+                             1u, storage_->InternString("NewThreadName")));
+  EXPECT_CALL(
+      *process_,
+      SetThreadNameIfUnset(2u, storage_->InternString("DifferentThreadName")));
 
   Tokenize();
   context_.sorter->ExtractEventsForced();
@@ -1016,39 +992,30 @@
   constexpr TrackId thread_1_track{0u};
   constexpr TrackId process_2_track{1u};
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat2,cat3")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillRepeatedly(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillRepeatedly(Return(4));
+  StringId cat_2_3 = storage_->InternString("cat2,cat3");
+  StringId ev_2 = storage_->InternString("ev2");
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
 
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   MockBoundInserter inserter;
-  EXPECT_CALL(*slice_, Scoped(1005000, thread_1_track, StringId(1), StringId(2),
-                              23000, _))
+  EXPECT_CALL(*slice_, Scoped(1005000, thread_1_track, cat_2_3, ev_2, 23000, _))
       .WillOnce(DoAll(InvokeArgument<5>(&inserter), Return(0u)));
   EXPECT_CALL(inserter, AddArg(_, _, Variadic::UnsignedInteger(9999u)));
   EXPECT_CALL(inserter, AddArg(_, _, Variadic::Boolean(true)));
   EXPECT_CALL(inserter, AddArg(_, _, _));
 
-  EXPECT_CALL(*slice_,
-              Begin(1010000, thread_1_track, StringId(3), StringId(4), _))
+  EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, cat_1, ev_1, _))
       .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(1u)));
 
-  EXPECT_CALL(*slice_,
-              End(1020000, thread_1_track, StringId(3), StringId(4), _))
+  EXPECT_CALL(*slice_, End(1020000, thread_1_track, cat_1, ev_1, _))
       .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(1u)));
 
-  EXPECT_CALL(*slice_,
-              Scoped(1040000, thread_1_track, StringId(3), StringId(4), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1040000, thread_1_track, cat_1, ev_1, 0, _))
       .WillOnce(DoAll(InvokeArgument<5>(&inserter), Return(2u)));
 
-  EXPECT_CALL(*slice_,
-              Scoped(1050000, process_2_track, StringId(3), StringId(4), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1050000, process_2_track, cat_1, ev_1, 0, _))
       .WillOnce(DoAll(InvokeArgument<5>(&inserter), Return(3u)));
   // Second slice should have a legacy_event.original_tid arg.
   EXPECT_CALL(inserter, AddArg(_, _, Variadic::Integer(16)));
@@ -1178,39 +1145,28 @@
   row.upid = 1u;
   storage_->mutable_thread_table()->Insert(row);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillRepeatedly(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillRepeatedly(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
-      .WillRepeatedly(Return(4));
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat2")))
-      .WillRepeatedly(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat2:scope1")))
-      .WillOnce(Return(5));
-  EXPECT_CALL(*storage_, GetString(StringId(1))).WillRepeatedly(Return("cat1"));
-  EXPECT_CALL(*storage_, GetString(StringId(3))).WillRepeatedly(Return("cat2"));
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId cat_2 = storage_->InternString("cat2");
+  StringId ev_2 = storage_->InternString("ev2");
 
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
-  EXPECT_CALL(*slice_, Begin(1010000, TrackId{1}, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, Begin(1010000, TrackId{1}, cat_1, ev_1, _))
       .WillOnce(Return(0u));
-  EXPECT_CALL(*slice_,
-              Scoped(1015000, TrackId{1}, StringId(1), StringId(4), 0, _));
-  EXPECT_CALL(*slice_,
-              Scoped(1018000, TrackId{2}, StringId(3), StringId(4), 0, _));
-  EXPECT_CALL(*slice_, End(1020000, TrackId{1}, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, Scoped(1015000, TrackId{1}, cat_1, ev_2, 0, _));
+  EXPECT_CALL(*slice_, Scoped(1018000, TrackId{2}, cat_2, ev_2, 0, _));
+  EXPECT_CALL(*slice_, End(1020000, TrackId{1}, cat_1, ev_1, _))
       .WillOnce(Return(0u));
-  EXPECT_CALL(*slice_,
-              Scoped(1030000, TrackId{3}, StringId(3), StringId(4), 0, _));
+  EXPECT_CALL(*slice_, Scoped(1030000, TrackId{3}, cat_2, ev_2, 0, _));
 
   context_.sorter->ExtractEventsForced();
 
   // First track is for the thread; others are the async event tracks.
   EXPECT_EQ(storage_->track_table().row_count(), 4u);
-  EXPECT_EQ(storage_->track_table().name()[1], 2u);
-  EXPECT_EQ(storage_->track_table().name()[2], 4u);
-  EXPECT_EQ(storage_->track_table().name()[3], 4u);
+  EXPECT_EQ(storage_->track_table().name()[1], ev_1);
+  EXPECT_EQ(storage_->track_table().name()[2], ev_2);
+  EXPECT_EQ(storage_->track_table().name()[3], ev_2);
 
   EXPECT_EQ(storage_->process_track_table().row_count(), 3u);
   EXPECT_EQ(storage_->process_track_table().upid()[0], 1u);
@@ -1355,41 +1311,28 @@
   t2.upid = 2u;
   storage_->mutable_thread_table()->Insert(t2);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("Thread track 1")))
-      .WillOnce(Return(10));
-  EXPECT_CALL(*storage_, InternString(base::StringView("Async track 1")))
-      .WillOnce(Return(11));
-  EXPECT_CALL(*storage_, InternString(base::StringView("Thread track 2")))
-      .WillOnce(Return(12));
-
   Tokenize();
 
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId cat_2 = storage_->InternString("cat2");
+  StringId ev_2 = storage_->InternString("ev2");
+  StringId cat_3 = storage_->InternString("cat3");
+  StringId ev_3 = storage_->InternString("ev3");
+
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, TrackId{1}, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, Begin(1010000, TrackId{1}, cat_1, ev_1, _))
       .WillOnce(Return(0u));
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat2")))
-      .WillOnce(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
-      .WillOnce(Return(4));
-  EXPECT_CALL(*slice_,
-              Scoped(1015000, TrackId{0}, StringId(3), StringId(4), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1015000, TrackId{0}, cat_2, ev_2, 0, _))
       .WillOnce(Return(1u));
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat3")))
-      .WillOnce(Return(5));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev3")))
-      .WillOnce(Return(6));
-  EXPECT_CALL(*slice_,
-              Scoped(1016000, TrackId{2}, StringId(5), StringId(6), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1016000, TrackId{2}, cat_3, ev_3, 0, _))
       .WillOnce(Return(2u));
 
-  EXPECT_CALL(*slice_, End(1020000, TrackId{1}, StringId(0), StringId(0), _))
+  EXPECT_CALL(*slice_,
+              End(1020000, TrackId{1}, kNullStringId, kNullStringId, _))
       .WillOnce(Return(0u));
 
   context_.sorter->ExtractEventsForced();
@@ -1397,9 +1340,9 @@
   // First track is "Thread track 1"; second is "Async track 1", third is
   // "Thread track 2".
   EXPECT_EQ(storage_->track_table().row_count(), 3u);
-  EXPECT_EQ(storage_->track_table().name()[0], 10u);  // "Thread track 1"
-  EXPECT_EQ(storage_->track_table().name()[1], 11u);  // "Async track 1"
-  EXPECT_EQ(storage_->track_table().name()[2], 12u);  // "Thread track 2"
+  EXPECT_EQ(storage_->track_table().name().GetString(0), "Thread track 1");
+  EXPECT_EQ(storage_->track_table().name().GetString(1), "Async track 1");
+  EXPECT_EQ(storage_->track_table().name().GetString(2), "Thread track 2");
   EXPECT_EQ(storage_->thread_track_table().row_count(), 2u);
   EXPECT_EQ(storage_->thread_track_table().utid()[0], 1u);
   EXPECT_EQ(storage_->thread_track_table().utid()[1], 2u);
@@ -1683,25 +1626,18 @@
   t2.upid = 1u;
   storage_->mutable_thread_table()->Insert(t2);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillRepeatedly(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
-      .WillRepeatedly(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillRepeatedly(Return(3));
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_2 = storage_->InternString("ev2");
+  StringId ev_1 = storage_->InternString("ev1");
 
   constexpr TrackId thread_2_track{0u};
   constexpr TrackId thread_1_track{1u};
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
-  EXPECT_CALL(*slice_,
-              Begin(1005000, thread_2_track, StringId(1), StringId(2), _));
-  EXPECT_CALL(*slice_,
-              Begin(1010000, thread_1_track, StringId(1), StringId(3), _));
-  EXPECT_CALL(*slice_,
-              End(1015000, thread_2_track, StringId(1), StringId(2), _));
-  EXPECT_CALL(*slice_,
-              End(1020000, thread_1_track, StringId(1), StringId(3), _));
+  EXPECT_CALL(*slice_, Begin(1005000, thread_2_track, cat_1, ev_2, _));
+  EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, cat_1, ev_1, _));
+  EXPECT_CALL(*slice_, End(1015000, thread_2_track, cat_1, ev_2, _));
+  EXPECT_CALL(*slice_, End(1020000, thread_1_track, cat_1, ev_1, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -1839,82 +1775,58 @@
   row.upid = 1u;
   storage_->mutable_thread_table()->Insert(row);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillRepeatedly(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillRepeatedly(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an1")))
-      .WillOnce(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2")))
-      .WillOnce(Return(4));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2.child1")))
-      .WillRepeatedly(Return(5));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2.child2")))
-      .WillRepeatedly(Return(6));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2.child2[0]")))
-      .WillOnce(Return(7));
-  EXPECT_CALL(*storage_, InternString(base::StringView("child21")))
-      .WillOnce(Return(8));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2.child2[1]")))
-      .WillOnce(Return(9));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an2.child2[2]")))
-      .WillOnce(Return(10));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an3")))
-      .WillOnce(Return(11));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an4")))
-      .WillOnce(Return(12));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an5")))
-      .WillOnce(Return(13));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an6")))
-      .WillOnce(Return(14));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an7")))
-      .WillOnce(Return(15));
-  EXPECT_CALL(*storage_, InternString(base::StringView("val7")))
-      .WillOnce(Return(16));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an8")))
-      .WillOnce(Return(17));
-  EXPECT_CALL(*storage_, InternString(base::StringView("val8")))
-      .WillOnce(Return(18));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an8_foo")))
-      .WillOnce(Return(19));
-
-  EXPECT_CALL(*storage_, GetString(StringId(4))).WillOnce(Return("debug.an2"));
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId debug_an_1 = storage_->InternString("debug.an1");
+  StringId debug_an_2_child_1 = storage_->InternString("debug.an2.child1");
+  StringId debug_an_2_child_2 = storage_->InternString("debug.an2.child2");
+  StringId debug_an_2_child_2_0 = storage_->InternString("debug.an2.child2[0]");
+  StringId child21 = storage_->InternString("child21");
+  StringId debug_an_2_child_2_1 = storage_->InternString("debug.an2.child2[1]");
+  StringId debug_an_2_child_2_2 = storage_->InternString("debug.an2.child2[2]");
+  StringId debug_an_3 = storage_->InternString("debug.an3");
+  StringId debug_an_4 = storage_->InternString("debug.an4");
+  StringId debug_an_5 = storage_->InternString("debug.an5");
+  StringId debug_an_6 = storage_->InternString("debug.an6");
+  StringId debug_an_7 = storage_->InternString("debug.an7");
+  StringId val_7 = storage_->InternString("val7");
+  StringId debug_an_8 = storage_->InternString("debug.an8");
+  StringId val_8 = storage_->InternString("val8");
+  StringId debug_an_8_foo = storage_->InternString("debug.an8_foo");
 
   constexpr TrackId track{0u};
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
-  EXPECT_CALL(*slice_, Begin(1010000, track, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, Begin(1010000, track, cat_1, ev_1, _))
       .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(1u)));
   EXPECT_CALL(inserter,
-              AddArg(StringId(3), StringId(3), Variadic::UnsignedInteger(10u)));
+              AddArg(debug_an_1, debug_an_1, Variadic::UnsignedInteger(10u)));
 
-  EXPECT_CALL(inserter,
-              AddArg(StringId(5), StringId(5), Variadic::Boolean(true)));
+  EXPECT_CALL(inserter, AddArg(debug_an_2_child_1, debug_an_2_child_1,
+                               Variadic::Boolean(true)));
 
-  EXPECT_CALL(inserter,
-              AddArg(StringId(6), StringId(7), Variadic::String(StringId(8))));
+  EXPECT_CALL(inserter, AddArg(debug_an_2_child_2, debug_an_2_child_2_0,
+                               Variadic::String(child21)));
 
-  EXPECT_CALL(inserter, AddArg(StringId(6), StringId(9), Variadic::Real(2.2)));
+  EXPECT_CALL(inserter, AddArg(debug_an_2_child_2, debug_an_2_child_2_1,
+                               Variadic::Real(2.2)));
 
-  EXPECT_CALL(inserter,
-              AddArg(StringId(6), StringId(10), Variadic::Integer(23)));
+  EXPECT_CALL(inserter, AddArg(debug_an_2_child_2, debug_an_2_child_2_2,
+                               Variadic::Integer(23)));
 
-  EXPECT_CALL(*slice_, End(1020000, track, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, End(1020000, track, cat_1, ev_1, _))
       .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(1u)));
 
+  EXPECT_CALL(inserter, AddArg(debug_an_3, debug_an_3, Variadic::Integer(-3)));
   EXPECT_CALL(inserter,
-              AddArg(StringId(11), StringId(11), Variadic::Integer(-3)));
+              AddArg(debug_an_4, debug_an_4, Variadic::Boolean(true)));
+  EXPECT_CALL(inserter, AddArg(debug_an_5, debug_an_5, Variadic::Real(-5.5)));
+  EXPECT_CALL(inserter, AddArg(debug_an_6, debug_an_6, Variadic::Pointer(20u)));
   EXPECT_CALL(inserter,
-              AddArg(StringId(12), StringId(12), Variadic::Boolean(true)));
+              AddArg(debug_an_7, debug_an_7, Variadic::String(val_7)));
+  EXPECT_CALL(inserter, AddArg(debug_an_8, debug_an_8, Variadic::Json(val_8)));
   EXPECT_CALL(inserter,
-              AddArg(StringId(13), StringId(13), Variadic::Real(-5.5)));
-  EXPECT_CALL(inserter,
-              AddArg(StringId(14), StringId(14), Variadic::Pointer(20u)));
-  EXPECT_CALL(inserter,
-              AddArg(StringId(15), StringId(15), Variadic::String(16)));
-  EXPECT_CALL(inserter, AddArg(StringId(17), StringId(17), Variadic::Json(18)));
-  EXPECT_CALL(inserter,
-              AddArg(StringId(19), StringId(19), Variadic::Integer(15)));
+              AddArg(debug_an_8_foo, debug_an_8_foo, Variadic::Integer(15)));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -1969,21 +1881,19 @@
   storage_->mutable_thread_table()->Insert(row);
 
   constexpr TrackId track{0u};
+
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId file_1 = storage_->InternString("file1");
+  StringId func_1 = storage_->InternString("func1");
+
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   MockBoundInserter inserter;
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, track, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, Begin(1010000, track, cat_1, ev_1, _))
       .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(1u)));
-  EXPECT_CALL(*storage_, InternString(base::StringView("file1")))
-      .WillOnce(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("func1")))
-      .WillOnce(Return(4));
-  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(3)));
-  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(4)));
+  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(file_1)));
+  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(func_1)));
   EXPECT_CALL(inserter, AddArg(_, _, Variadic::UnsignedInteger(42)));
 
   context_.sorter->ExtractEventsForced();
@@ -2047,29 +1957,25 @@
   row.upid = 1u;
   storage_->mutable_thread_table()->Insert(row);
 
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId body_1 = storage_->InternString("body1");
+
   constexpr TrackId track{0};
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillOnce(Return(2));
-
   MockBoundInserter inserter;
-  EXPECT_CALL(*slice_, Scoped(1010000, track, StringId(1), StringId(2), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1010000, track, cat_1, ev_1, 0, _))
       .WillOnce(DoAll(InvokeArgument<5>(&inserter), Return(1u)));
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("body1")))
-      .WillOnce(Return(3));
-
   // Call with logMessageBody (body1 in this case).
-  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(StringId(3))));
+  EXPECT_CALL(inserter, AddArg(_, _, Variadic::String(body_1)));
 
   context_.sorter->ExtractEventsForced();
 
   EXPECT_GT(context_.storage->android_log_table().row_count(), 0u);
   EXPECT_EQ(context_.storage->android_log_table().ts()[0], 1010000);
-  EXPECT_EQ(context_.storage->android_log_table().msg()[0], 3u);
+  EXPECT_EQ(context_.storage->android_log_table().msg()[0], body_1);
 }
 
 TEST_F(ProtoTraceParserTest, TrackEventParseLegacyEventIntoRawTable) {
@@ -2132,17 +2038,11 @@
   row.upid = 1u;
   storage_->mutable_thread_table()->Insert(row);
 
-  EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView("scope1")))
-      .Times(1)
-      .WillRepeatedly(Return(3));
-  EXPECT_CALL(*storage_, InternString(base::StringView("?")))
-      .WillOnce(Return(4));
-  EXPECT_CALL(*storage_, InternString(base::StringView("debug.an1")))
-      .WillOnce(Return(5));
+  StringId cat_1 = storage_->InternString("cat1");
+  StringId ev_1 = storage_->InternString("ev1");
+  StringId scope_1 = storage_->InternString("scope1");
+  StringId question = storage_->InternString("?");
+  StringId debug_an_1 = storage_->InternString("debug.an1");
 
   context_.sorter->ExtractEventsForced();
 
@@ -2161,11 +2061,11 @@
   EXPECT_GE(storage_->arg_table().row_count(), 13u);
 
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.category"),
-                     Variadic::String(1u)));
+                     Variadic::String(cat_1)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.name"),
-                     Variadic::String(2u)));
+                     Variadic::String(ev_1)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.phase"),
-                     Variadic::String(4u)));
+                     Variadic::String(question)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.duration_ns"),
                      Variadic::Integer(23000)));
   EXPECT_TRUE(HasArg(1u,
@@ -2179,7 +2079,7 @@
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.global_id"),
                      Variadic::UnsignedInteger(99u)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.id_scope"),
-                     Variadic::String(3u)));
+                     Variadic::String(scope_1)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.bind_id"),
                      Variadic::UnsignedInteger(98u)));
   EXPECT_TRUE(HasArg(1u,
@@ -2187,7 +2087,7 @@
                      Variadic::Boolean(true)));
   EXPECT_TRUE(HasArg(1u, storage_->InternString("legacy_event.flow_direction"),
                      Variadic::String(storage_->InternString("inout"))));
-  EXPECT_TRUE(HasArg(1u, 5u, Variadic::UnsignedInteger(10u)));
+  EXPECT_TRUE(HasArg(1u, debug_an_1, Variadic::UnsignedInteger(10u)));
 }
 
 TEST_F(ProtoTraceParserTest, TrackEventLegacyTimestampsWithClockSnapshot) {
@@ -2378,12 +2278,9 @@
 
   Tokenize();
 
-  EXPECT_CALL(*storage_, InternString(base::StringView(kName)))
-      .WillOnce(Return(1));
-  EXPECT_CALL(*storage_, InternString(base::StringView(kTag1)))
-      .WillOnce(Return(2));
-  EXPECT_CALL(*storage_, InternString(base::StringView(kTag2)))
-      .WillOnce(Return(3));
+  StringId name_1 = storage_->InternString(kName);
+  StringId tag_1 = storage_->InternString(kTag1);
+  StringId tag_2 = storage_->InternString(kTag2);
 
   StringId benchmark_id = *storage_->string_pool().GetId(
       metadata::kNames[metadata::benchmark_name]);
@@ -2401,9 +2298,9 @@
     meta_entries.emplace_back(std::make_pair(meta_keys[i], meta_values[i]));
   }
   EXPECT_THAT(meta_entries,
-              UnorderedElementsAreArray({std::make_pair(benchmark_id, 1),
-                                         std::make_pair(tags_id, 2),
-                                         std::make_pair(tags_id, 3)}));
+              UnorderedElementsAreArray({std::make_pair(benchmark_id, name_1),
+                                         std::make_pair(tags_id, tag_1),
+                                         std::make_pair(tags_id, tag_2)}));
 }
 
 TEST_F(ProtoTraceParserTest, AndroidPackagesList) {
@@ -2543,15 +2440,15 @@
   const auto& samples = storage_->cpu_profile_stack_sample_table();
   EXPECT_EQ(samples.row_count(), 3u);
 
-  EXPECT_EQ(samples.ts()[0], 1010);
+  EXPECT_EQ(samples.ts()[0], 11000);
   EXPECT_EQ(samples.callsite_id()[0], 0);
   EXPECT_EQ(samples.utid()[0], 1u);
 
-  EXPECT_EQ(samples.ts()[1], 1025);
+  EXPECT_EQ(samples.ts()[1], 26000);
   EXPECT_EQ(samples.callsite_id()[1], 1);
   EXPECT_EQ(samples.utid()[1], 1u);
 
-  EXPECT_EQ(samples.ts()[2], 1067);
+  EXPECT_EQ(samples.ts()[2], 68000);
   EXPECT_EQ(samples.callsite_id()[2], 0);
   EXPECT_EQ(samples.utid()[2], 1u);
 }
diff --git a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
index b964a2c..ca746b7 100644
--- a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
+++ b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
@@ -18,8 +18,7 @@
 
 #include <string>
 
-#include <zlib.h>
-
+#include "perfetto/base/build_config.h"
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/string_view.h"
@@ -42,6 +41,10 @@
 #include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#endif
+
 namespace perfetto {
 namespace trace_processor {
 
@@ -53,6 +56,7 @@
 constexpr uint8_t kTracePacketTag =
     MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 TraceBlobView Decompress(TraceBlobView input) {
   uint8_t out[4096];
   std::string s;
@@ -81,6 +85,7 @@
   memcpy(output.get(), s.data(), s.size());
   return TraceBlobView(std::move(output), 0, s.size());
 }
+#endif  //  PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 
 }  // namespace
 
@@ -309,6 +314,7 @@
   }
 
   if (decoder.has_compressed_packets()) {
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
     protozero::ConstBytes field = decoder.compressed_packets();
     const size_t field_off = packet.offset_of(field.data);
     TraceBlobView compressed_packets = packet.slice(field_off, field.size);
@@ -334,6 +340,9 @@
     }
 
     return util::OkStatus();
+#else
+    return util::Status("Cannot decode compressed packets. Zlib not enabled");
+#endif
   }
 
   // If we're not forcing a full sort and this is a write_into_file trace, then
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 5355ad5..5ca7ca1 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -254,7 +254,7 @@
         continue;
       }
       bool is_counter_field = fld.id() < proc_stats_process_names_.size() &&
-                              proc_stats_process_names_[fld.id()] != 0;
+                              !proc_stats_process_names_[fld.id()].is_null();
       if (is_counter_field) {
         // Memory counters are in KB, keep values in bytes in the trace
         // processor.
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 650156f..60a3318 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -393,7 +393,7 @@
     category_strings.push_back(*it);
   }
 
-  StringId category_id = 0;
+  StringId category_id = kNullStringId;
 
   // If there's a single category, we can avoid building a concatenated
   // string.
@@ -430,7 +430,7 @@
       category_id = storage->InternString(base::StringView(categories));
   }
 
-  StringId name_id = 0;
+  StringId name_id = kNullStringId;
 
   uint64_t name_iid = event.name_iid();
   if (!name_iid)
@@ -978,7 +978,7 @@
   protos::pbzero::DebugAnnotation::Decoder annotation(debug_annotation.data,
                                                       debug_annotation.size);
 
-  StringId name_id = 0;
+  StringId name_id = kNullStringId;
 
   uint64_t name_iid = annotation.name_iid();
   if (PERFETTO_LIKELY(name_iid)) {
@@ -1095,8 +1095,8 @@
   if (!decoder)
     return;
 
-  StringId file_name_id = 0;
-  StringId function_name_id = 0;
+  StringId file_name_id = kNullStringId;
+  StringId function_name_id = kNullStringId;
   uint32_t line_number = 0;
 
   TraceStorage* storage = context_->storage.get();
@@ -1128,7 +1128,7 @@
 
   TraceStorage* storage = context_->storage.get();
 
-  StringId log_message_id = 0;
+  StringId log_message_id = kNullStringId;
 
   auto* decoder = sequence_state->LookupInternedMessage<
       protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
@@ -1143,8 +1143,8 @@
   context_->storage->mutable_android_log_table()->Insert(
       {ts, *utid,
        /*priority*/ 0,
-       /*tag_id*/ 0,  // TODO(nicomazz): Abuse tag_id to display
-                      // "file_name:line_number".
+       /*tag_id*/ kNullStringId,  // TODO(nicomazz): Abuse tag_id to display
+                                  // "file_name:line_number".
        log_message_id});
 
   inserter->AddArg(log_message_body_key_id_, Variadic::String(log_message_id));
diff --git a/src/trace_processor/importers/systrace/systrace_parser.cc b/src/trace_processor/importers/systrace/systrace_parser.cc
index b6642a2..745a447 100644
--- a/src/trace_processor/importers/systrace/systrace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_parser.cc
@@ -109,7 +109,8 @@
       StringId name_id = context_->storage->InternString(point.name);
       UniqueTid utid = context_->process_tracker->UpdateThread(pid, point.tgid);
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      context_->slice_tracker->Begin(ts, track_id, 0 /* cat */, name_id);
+      context_->slice_tracker->Begin(ts, track_id, kNullStringId /* cat */,
+                                     name_id);
       break;
     }
 
@@ -142,7 +143,7 @@
       TrackId track_id = context_->track_tracker->InternAndroidAsyncTrack(
           name_id, upid, cookie);
       if (point.phase == 'S') {
-        context_->slice_tracker->Begin(ts, track_id, 0, name_id);
+        context_->slice_tracker->Begin(ts, track_id, kNullStringId, name_id);
       } else {
         context_->slice_tracker->End(ts, track_id);
       }
diff --git a/src/trace_processor/importers/systrace/systrace_trace_parser.h b/src/trace_processor/importers/systrace/systrace_trace_parser.h
index 1b5926b..26553e9 100644
--- a/src/trace_processor/importers/systrace/systrace_trace_parser.h
+++ b/src/trace_processor/importers/systrace/systrace_trace_parser.h
@@ -47,8 +47,8 @@
   util::Status ParseSingleSystraceEvent(const std::string& buffer);
 
   TraceProcessorContext* const context_;
-  const StringId sched_wakeup_name_id_ = 0;
-  const StringId cpu_idle_name_id_ = 0;
+  const StringId sched_wakeup_name_id_ = kNullStringId;
+  const StringId cpu_idle_name_id_ = kNullStringId;
   const std::regex line_matcher_;
 
   ParseState state_ = ParseState::kBeforeParse;
diff --git a/src/trace_processor/metadata.h b/src/trace_processor/metadata.h
index eb55e15..2546cec 100644
--- a/src/trace_processor/metadata.h
+++ b/src/trace_processor/metadata.h
@@ -56,6 +56,9 @@
   F(kMulti,  "multi")
 // clang-format
 
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
 #define PERFETTO_TP_META_TYPE_ENUM(varname, ...) varname
 enum class KeyType : size_t {
   PERFETTO_TP_METADATA_KEY_TYPES(PERFETTO_TP_META_TYPE_ENUM),
diff --git a/src/trace_processor/process_tracker.cc b/src/trace_processor/process_tracker.cc
index fe80471..82aa32d 100644
--- a/src/trace_processor/process_tracker.cc
+++ b/src/trace_processor/process_tracker.cc
@@ -178,7 +178,7 @@
 
   // Create a new UTID for the main thread, so we don't end up reusing an old
   // entry in case of TID recycling.
-  StartNewThread(timestamp, /*tid=*/pid, 0);
+  StartNewThread(timestamp, /*tid=*/pid, kNullStringId);
 
   // Note that we erased the pid above so this should always return a new
   // process.
@@ -187,7 +187,7 @@
   auto* process_table = context_->storage->mutable_process_table();
   auto* thread_table = context_->storage->mutable_thread_table();
 
-  PERFETTO_DCHECK(process_table->name()[upid] == 0);
+  PERFETTO_DCHECK(process_table->name()[upid].is_null());
   PERFETTO_DCHECK(!process_table->start_ts()[upid].has_value());
 
   if (timestamp) {
diff --git a/src/trace_processor/process_tracker_unittest.cc b/src/trace_processor/process_tracker_unittest.cc
index bd6d2b7..e626681 100644
--- a/src/trace_processor/process_tracker_unittest.cc
+++ b/src/trace_processor/process_tracker_unittest.cc
@@ -59,7 +59,8 @@
 
 TEST_F(ProcessTrackerTest, StartNewProcess) {
   TraceStorage storage;
-  auto upid = context.process_tracker->StartNewProcess(1000, 0u, 123, 0);
+  auto upid =
+      context.process_tracker->StartNewProcess(1000, 0u, 123, kNullStringId);
   ASSERT_EQ(context.process_tracker->GetOrCreateProcess(123), upid);
   ASSERT_EQ(context.storage->process_table().start_ts()[upid], 1000);
 }
diff --git a/src/trace_processor/slice_tracker_unittest.cc b/src/trace_processor/slice_tracker_unittest.cc
index f6debfa..6b27258 100644
--- a/src/trace_processor/slice_tracker_unittest.cc
+++ b/src/trace_processor/slice_tracker_unittest.cc
@@ -56,16 +56,18 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Begin(2 /*ts*/, track, 0 /*cat*/, 1 /*name*/);
-  tracker.End(10 /*ts*/, track, 0 /*cat*/, 1 /*name*/);
+  tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
+                StringId::Raw(1) /*name*/);
+  tracker.End(10 /*ts*/, track, kNullStringId /*cat*/,
+              StringId::Raw(1) /*name*/);
 
   const auto& slices = context.storage->slice_table();
   EXPECT_EQ(slices.row_count(), 1u);
   EXPECT_EQ(slices.ts()[0], 2);
   EXPECT_EQ(slices.dur()[0], 8);
   EXPECT_EQ(slices.track_id()[0], track.value);
-  EXPECT_EQ(slices.category()[0], 0u);
-  EXPECT_EQ(slices.name()[0], 1u);
+  EXPECT_EQ(slices.category()[0].raw_id(), 0u);
+  EXPECT_EQ(slices.name()[0].raw_id(), 1u);
   EXPECT_EQ(slices.depth()[0], 0u);
   EXPECT_EQ(slices.arg_set_id()[0], kInvalidArgSetId);
 }
@@ -77,14 +79,18 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Begin(2 /*ts*/, track, 0 /*cat*/, 1 /*name*/,
+  tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
+                StringId::Raw(1) /*name*/,
                 [](ArgsTracker::BoundInserter* inserter) {
-                  inserter->AddArg(/*flat_key=*/1, /*key=*/2,
+                  inserter->AddArg(/*flat_key=*/StringId::Raw(1),
+                                   /*key=*/StringId::Raw(2),
                                    /*value=*/Variadic::Integer(10));
                 });
-  tracker.End(10 /*ts*/, track, 0 /*cat*/, 1 /*name*/,
+  tracker.End(10 /*ts*/, track, kNullStringId /*cat*/,
+              StringId::Raw(1) /*name*/,
               [](ArgsTracker::BoundInserter* inserter) {
-                inserter->AddArg(/*flat_key=*/3, /*key=*/4,
+                inserter->AddArg(/*flat_key=*/StringId::Raw(3),
+                                 /*key=*/StringId::Raw(4),
                                  /*value=*/Variadic::Integer(20));
               });
 
@@ -93,19 +99,19 @@
   EXPECT_EQ(slices.ts()[0], 2);
   EXPECT_EQ(slices.dur()[0], 8);
   EXPECT_EQ(slices.track_id()[0], track.value);
-  EXPECT_EQ(slices.category()[0], 0u);
-  EXPECT_EQ(slices.name()[0], 1u);
+  EXPECT_EQ(slices.category()[0].raw_id(), 0u);
+  EXPECT_EQ(slices.name()[0].raw_id(), 1u);
   EXPECT_EQ(slices.depth()[0], 0u);
   auto set_id = slices.arg_set_id()[0];
 
   const auto& args = context.storage->arg_table();
   EXPECT_EQ(args.arg_set_id()[0], set_id);
-  EXPECT_EQ(args.flat_key()[0], 1u);
-  EXPECT_EQ(args.key()[0], 2u);
+  EXPECT_EQ(args.flat_key()[0].raw_id(), 1u);
+  EXPECT_EQ(args.key()[0].raw_id(), 2u);
   EXPECT_EQ(args.int_value()[0], 10);
   EXPECT_EQ(args.arg_set_id()[1], set_id);
-  EXPECT_EQ(args.flat_key()[1], 3u);
-  EXPECT_EQ(args.key()[1], 4u);
+  EXPECT_EQ(args.flat_key()[1].raw_id(), 3u);
+  EXPECT_EQ(args.key()[1].raw_id(), 4u);
   EXPECT_EQ(args.int_value()[1], 20);
 }
 
@@ -115,8 +121,10 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Begin(2 /*ts*/, track, 0 /*cat*/, 1 /*name*/);
-  tracker.Begin(3 /*ts*/, track, 0 /*cat*/, 2 /*name*/);
+  tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
+                StringId::Raw(1) /*name*/);
+  tracker.Begin(3 /*ts*/, track, kNullStringId /*cat*/,
+                StringId::Raw(2) /*name*/);
   tracker.End(5 /*ts*/, track);
   tracker.End(10 /*ts*/, track);
 
@@ -128,15 +136,15 @@
   EXPECT_EQ(slices.ts()[idx], 2);
   EXPECT_EQ(slices.dur()[idx], 8);
   EXPECT_EQ(slices.track_id()[idx], track.value);
-  EXPECT_EQ(slices.category()[idx], 0u);
-  EXPECT_EQ(slices.name()[idx], 1u);
+  EXPECT_EQ(slices.category()[idx].raw_id(), 0u);
+  EXPECT_EQ(slices.name()[idx].raw_id(), 1u);
   EXPECT_EQ(slices.depth()[idx++], 0u);
 
   EXPECT_EQ(slices.ts()[idx], 3);
   EXPECT_EQ(slices.dur()[idx], 2);
   EXPECT_EQ(slices.track_id()[idx], track.value);
-  EXPECT_EQ(slices.category()[idx], 0u);
-  EXPECT_EQ(slices.name()[idx], 2u);
+  EXPECT_EQ(slices.category()[idx].raw_id(), 0u);
+  EXPECT_EQ(slices.name()[idx].raw_id(), 2u);
   EXPECT_EQ(slices.depth()[idx], 1u);
 
   EXPECT_EQ(slices.parent_stack_id()[0], 0);
@@ -150,9 +158,9 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Begin(0 /*ts*/, track, 0, 0);
-  tracker.Begin(1 /*ts*/, track, 0, 0);
-  tracker.Scoped(2 /*ts*/, track, 0, 0, 6);
+  tracker.Begin(0 /*ts*/, track, kNullStringId, kNullStringId);
+  tracker.Begin(1 /*ts*/, track, kNullStringId, kNullStringId);
+  tracker.Scoped(2 /*ts*/, track, kNullStringId, kNullStringId, 6);
   tracker.End(9 /*ts*/, track);
   tracker.End(10 /*ts*/, track);
 
@@ -167,10 +175,14 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Begin(2 /*ts*/, track, 5 /*cat*/, 1 /*name*/);
-  tracker.End(3 /*ts*/, track, 1 /*cat*/, 1 /*name*/);
-  tracker.End(4 /*ts*/, track, 0 /*cat*/, 2 /*name*/);
-  tracker.End(5 /*ts*/, track, 5 /*cat*/, 1 /*name*/);
+  tracker.Begin(2 /*ts*/, track, StringId::Raw(5) /*cat*/,
+                StringId::Raw(1) /*name*/);
+  tracker.End(3 /*ts*/, track, StringId::Raw(1) /*cat*/,
+              StringId::Raw(1) /*name*/);
+  tracker.End(4 /*ts*/, track, kNullStringId /*cat*/,
+              StringId::Raw(2) /*name*/);
+  tracker.End(5 /*ts*/, track, StringId::Raw(5) /*cat*/,
+              StringId::Raw(1) /*name*/);
 
   auto slices = ToSliceInfo(context.storage->slice_table());
   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 3}));
@@ -185,10 +197,14 @@
   // from being closed, leading to an inconsistency when we try to insert the
   // final slice and it doesn't intersect with the still pending first slice.
   constexpr TrackId track{22u};
-  tracker.Scoped(2 /*ts*/, track, 0 /*cat*/, 1 /*name*/, 10 /* dur */);
-  tracker.Scoped(2 /*ts*/, track, 0 /*cat*/, 1 /*name*/, 0 /* dur */);
-  tracker.Scoped(12 /*ts*/, track, 0 /*cat*/, 1 /*name*/, 1 /* dur */);
-  tracker.Scoped(13 /*ts*/, track, 0 /*cat*/, 1 /*name*/, 1 /* dur */);
+  tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
+                 StringId::Raw(1) /*name*/, 10 /* dur */);
+  tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
+                 StringId::Raw(1) /*name*/, 0 /* dur */);
+  tracker.Scoped(12 /*ts*/, track, kNullStringId /*cat*/,
+                 StringId::Raw(1) /*name*/, 1 /* dur */);
+  tracker.Scoped(13 /*ts*/, track, kNullStringId /*cat*/,
+                 StringId::Raw(1) /*name*/, 1 /* dur */);
 
   auto slices = ToSliceInfo(context.storage->slice_table());
   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 10}, SliceInfo{2, 0},
@@ -202,9 +218,9 @@
 
   constexpr TrackId track_a{22u};
   constexpr TrackId track_b{23u};
-  tracker.Begin(0 /*ts*/, track_a, 0, 0);
-  tracker.Scoped(2 /*ts*/, track_b, 0, 0, 6);
-  tracker.Scoped(3 /*ts*/, track_b, 0, 0, 4);
+  tracker.Begin(0 /*ts*/, track_a, kNullStringId, kNullStringId);
+  tracker.Scoped(2 /*ts*/, track_b, kNullStringId, kNullStringId, 6);
+  tracker.Scoped(3 /*ts*/, track_b, kNullStringId, kNullStringId, 4);
   tracker.End(10 /*ts*/, track_a);
   tracker.FlushPendingSlices();
 
@@ -226,26 +242,36 @@
   SliceTracker tracker(&context);
 
   constexpr TrackId track{22u};
-  tracker.Scoped(50 /*ts*/, track, 11 /*cat*/, 21 /*name*/, 100 /*dur*/);
-  tracker.Begin(100 /*ts*/, track, 12 /*cat*/, 22 /*name*/);
+  tracker.Scoped(50 /*ts*/, track, StringId::Raw(11) /*cat*/,
+                 StringId::Raw(21) /*name*/, 100 /*dur*/);
+  tracker.Begin(100 /*ts*/, track, StringId::Raw(12) /*cat*/,
+                StringId::Raw(22) /*name*/);
 
   // This slice should now have depth 0.
-  tracker.Scoped(450 /*ts*/, track, 12 /*cat*/, 22 /*name*/, 100 /*dur*/);
+  tracker.Scoped(450 /*ts*/, track, StringId::Raw(12) /*cat*/,
+                 StringId::Raw(22) /*name*/, 100 /*dur*/);
 
   // This slice should be ignored.
-  tracker.End(500 /*ts*/, track, 12 /*cat*/, 22 /*name*/);
+  tracker.End(500 /*ts*/, track, StringId::Raw(12) /*cat*/,
+              StringId::Raw(22) /*name*/);
 
-  tracker.Begin(800 /*ts*/, track, 13 /*cat*/, 23 /*name*/);
+  tracker.Begin(800 /*ts*/, track, StringId::Raw(13) /*cat*/,
+                StringId::Raw(23) /*name*/);
   // Null cat and name matches everything.
-  tracker.End(1000 /*ts*/, track, 0 /*cat*/, 0 /*name*/);
+  tracker.End(1000 /*ts*/, track, kNullStringId /*cat*/,
+              kNullStringId /*name*/);
 
   // Slice will not close if category is different.
-  tracker.Begin(1100 /*ts*/, track, 11 /*cat*/, 21 /*name*/);
-  tracker.End(1200 /*ts*/, track, 12 /*cat*/, 21 /*name*/);
+  tracker.Begin(1100 /*ts*/, track, StringId::Raw(11) /*cat*/,
+                StringId::Raw(21) /*name*/);
+  tracker.End(1200 /*ts*/, track, StringId::Raw(12) /*cat*/,
+              StringId::Raw(21) /*name*/);
 
   // Slice will not close if name is different.
-  tracker.Begin(1300 /*ts*/, track, 11 /*cat*/, 21 /*name*/);
-  tracker.End(1400 /*ts*/, track, 11 /*cat*/, 22 /*name*/);
+  tracker.Begin(1300 /*ts*/, track, StringId::Raw(11) /*cat*/,
+                StringId::Raw(21) /*name*/);
+  tracker.End(1400 /*ts*/, track, StringId::Raw(11) /*cat*/,
+              StringId::Raw(22) /*name*/);
 
   tracker.FlushPendingSlices();
 
diff --git a/src/trace_processor/stats.h b/src/trace_processor/stats.h
index 19b35b3..8d52968 100644
--- a/src/trace_processor/stats.h
+++ b/src/trace_processor/stats.h
@@ -150,6 +150,9 @@
   kAnalysis
 };
 
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
 // Declares an enum of literals (one for each stat). The enum values of each
 // literal corresponds to the string index in the arrays below.
 #define PERFETTO_TP_STATS_ENUM(name, ...) name
diff --git a/src/trace_processor/syscall_tracker.cc b/src/trace_processor/syscall_tracker.cc
index 609284d..5991497 100644
--- a/src/trace_processor/syscall_tracker.cc
+++ b/src/trace_processor/syscall_tracker.cc
@@ -83,7 +83,7 @@
   }
 
   for (size_t i = 0; i < kMaxSyscalls; i++) {
-    StringId id = 0;
+    StringId id = kNullStringId;
     if (i < num_syscalls && syscall_table[i] && *syscall_table[i]) {
       const char* name = syscall_table[i];
       id = context_->storage->InternString(name);
diff --git a/src/trace_processor/syscall_tracker.h b/src/trace_processor/syscall_tracker.h
index 1dba57d..88d67b4 100644
--- a/src/trace_processor/syscall_tracker.h
+++ b/src/trace_processor/syscall_tracker.h
@@ -58,7 +58,8 @@
     StringId name = SyscallNumberToStringId(syscall_num);
     if (!name.is_null()) {
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      context_->slice_tracker->Begin(ts, track_id, 0 /* cat */, name);
+      context_->slice_tracker->Begin(ts, track_id, kNullStringId /* cat */,
+                                     name);
     }
   }
 
@@ -66,7 +67,7 @@
     StringId name = SyscallNumberToStringId(syscall_num);
     if (!name.is_null()) {
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      context_->slice_tracker->End(ts, track_id, 0 /* cat */, name);
+      context_->slice_tracker->End(ts, track_id, kNullStringId /* cat */, name);
     }
   }
 
@@ -77,14 +78,14 @@
 
   inline StringId SyscallNumberToStringId(uint32_t syscall_num) {
     if (syscall_num > kMaxSyscalls)
-      return 0;
+      return kNullStringId;
     // We see two write sys calls around each userspace slice that is going via
     // trace_marker, this violates the assumption that userspace slices are
     // perfectly nested. For the moment ignore all write sys calls.
     // TODO(hjd): Remove this limitation.
     StringId id = arch_syscall_to_string_id_[syscall_num];
     if (id == sys_write_string_id_)
-      return 0;
+      return kNullStringId;
     return id;
   }
 
diff --git a/src/trace_processor/syscall_tracker_unittest.cc b/src/trace_processor/syscall_tracker_unittest.cc
index f7a2eef..61124d1 100644
--- a/src/trace_processor/syscall_tracker_unittest.cc
+++ b/src/trace_processor/syscall_tracker_unittest.cc
@@ -64,8 +64,8 @@
 
 TEST_F(SyscallTrackerTest, ReportUnknownSyscalls) {
   constexpr TrackId track{0u};
-  StringId begin_name = 0;
-  StringId end_name = 0;
+  StringId begin_name = kNullStringId;
+  StringId end_name = kNullStringId;
   EXPECT_CALL(*slice_tracker, Begin(100, track, kNullStringId, _, _))
       .WillOnce(DoAll(SaveArg<3>(&begin_name), Return(base::nullopt)));
   EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
@@ -90,8 +90,8 @@
 
 TEST_F(SyscallTrackerTest, Aarch64) {
   constexpr TrackId track{0u};
-  StringId begin_name = 0;
-  StringId end_name = 0;
+  StringId begin_name = kNullStringId;
+  StringId end_name = kNullStringId;
   EXPECT_CALL(*slice_tracker, Begin(100, track, kNullStringId, _, _))
       .WillOnce(DoAll(SaveArg<3>(&begin_name), Return(base::nullopt)));
   EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
@@ -107,8 +107,8 @@
 
 TEST_F(SyscallTrackerTest, x8664) {
   constexpr TrackId track{0u};
-  StringId begin_name = 0;
-  StringId end_name = 0;
+  StringId begin_name = kNullStringId;
+  StringId end_name = kNullStringId;
   EXPECT_CALL(*slice_tracker, Begin(100, track, kNullStringId, _, _))
       .WillOnce(DoAll(SaveArg<3>(&begin_name), Return(base::nullopt)));
   EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
diff --git a/src/trace_processor/tables/macros_internal.h b/src/trace_processor/tables/macros_internal.h
index ada4b8c..71895b2 100644
--- a/src/trace_processor/tables/macros_internal.h
+++ b/src/trace_processor/tables/macros_internal.h
@@ -122,6 +122,9 @@
 
 }  // namespace macros_internal
 
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
 // Basic helper macros.
 #define PERFETTO_TP_NOOP(...)
 
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index d06580d..9b44058 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -539,7 +539,12 @@
     auto it = ExecuteQuery(query);
     while (it.Next()) {
     }
-    PERFETTO_CHECK(it.Status().ok());
+    // Index deletion can legitimately fail. If one creates an index "i" on a
+    // table "t" but issues the deletion in the order (t, i), the DROP index i
+    // will fail with "no such index" because deleting the table "t"
+    // automatically deletes all associated indexes.
+    if (!it.Status().ok() && tn.first != "index")
+      PERFETTO_FATAL("%s -> %s", query.c_str(), it.Status().c_message());
   }
   return deletion_list.size();
 }
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index da7d12a..8b0634b 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -58,7 +58,7 @@
 
 // StringId is an offset into |string_pool_|.
 using StringId = StringPool::Id;
-static const StringId kNullStringId = StringId(0);
+static const StringId kNullStringId = StringId::Null();
 
 using ArgSetId = uint32_t;
 static const ArgSetId kInvalidArgSetId = 0;
@@ -710,7 +710,7 @@
 
   // TODO(lalitm): remove this when we find a better home for this.
   using FrameKey = std::pair<size_t /* mapping row */, uint64_t /* rel_pc */>;
-  std::map<MappingKey, std::vector<int64_t>> stack_profile_frame_index_;
+  std::map<FrameKey, std::vector<int64_t>> stack_profile_frame_index_;
 
   // One entry for each unique string in the trace.
   StringPool string_pool_;
diff --git a/src/trace_processor/track_tracker.cc b/src/trace_processor/track_tracker.cc
index 4ac6f5b..94661b8 100644
--- a/src/trace_processor/track_tracker.cc
+++ b/src/trace_processor/track_tracker.cc
@@ -81,7 +81,7 @@
 }
 
 TrackId TrackTracker::InternGpuTrack(const tables::GpuTrackTable::Row& row) {
-  GpuTrackTuple tuple{row.name.id, row.scope, row.context_id.value_or(0)};
+  GpuTrackTuple tuple{row.name, row.scope, row.context_id.value_or(0)};
 
   auto it = gpu_tracks_.find(tuple);
   if (it != gpu_tracks_.end())
diff --git a/src/trace_processor/track_tracker.h b/src/trace_processor/track_tracker.h
index 803b908..de6233a 100644
--- a/src/trace_processor/track_tracker.h
+++ b/src/trace_processor/track_tracker.h
@@ -131,8 +131,8 @@
   // Creates a counter track associated with a GPU into the storage.
   TrackId CreateGpuCounterTrack(StringId name,
                                 uint32_t gpu_id,
-                                StringId description = 0,
-                                StringId unit = 0);
+                                StringId description = StringId::Null(),
+                                StringId unit = StringId::Null());
 
  private:
   struct GpuTrackTuple {
@@ -148,7 +148,7 @@
   struct ChromeTrackTuple {
     base::Optional<int64_t> upid;
     int64_t source_id = 0;
-    StringId source_scope = 0;
+    StringId source_scope = StringId::Null();
 
     friend bool operator<(const ChromeTrackTuple& l,
                           const ChromeTrackTuple& r) {
@@ -212,17 +212,17 @@
   std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_;
   std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_;
 
-  const StringId source_key_ = 0;
-  const StringId source_id_key_ = 0;
-  const StringId source_id_is_process_scoped_key_ = 0;
-  const StringId source_scope_key_ = 0;
+  const StringId source_key_ = kNullStringId;
+  const StringId source_id_key_ = kNullStringId;
+  const StringId source_id_is_process_scoped_key_ = kNullStringId;
+  const StringId source_scope_key_ = kNullStringId;
 
-  const StringId fuchsia_source_ = 0;
-  const StringId chrome_source_ = 0;
-  const StringId android_source_ = 0;
-  const StringId descriptor_source_ = 0;
+  const StringId fuchsia_source_ = kNullStringId;
+  const StringId chrome_source_ = kNullStringId;
+  const StringId android_source_ = kNullStringId;
+  const StringId descriptor_source_ = kNullStringId;
 
-  const StringId default_descriptor_track_name_ = 0;
+  const StringId default_descriptor_track_name_ = kNullStringId;
 
   TraceProcessorContext* const context_;
 };
diff --git a/src/traced/probes/ftrace/format_parser.cc b/src/traced/probes/ftrace/format_parser.cc
index c5ce2c1..d4e119f 100644
--- a/src/traced/probes/ftrace/format_parser.cc
+++ b/src/traced/probes/ftrace/format_parser.cc
@@ -141,7 +141,7 @@
 
   for (base::StringSplitter ss(std::move(input), '\n'); ss.Next();) {
     const char* line = ss.cur_token();
-    if (!has_id && sscanf(line, "ID: %d", &id) == 1) {
+    if (!has_id && sscanf(line, "ID: %u", &id) == 1) {
       has_id = true;
       continue;
     }
diff --git a/src/traced/probes/ftrace/ftrace_data_source.cc b/src/traced/probes/ftrace/ftrace_data_source.cc
index f576f16..f28a491 100644
--- a/src/traced/probes/ftrace/ftrace_data_source.cc
+++ b/src/traced/probes/ftrace/ftrace_data_source.cc
@@ -36,12 +36,12 @@
     : ProbesDataSource(session_id, kTypeId),
       config_(config),
       writer_(std::move(writer)),
-      controller_weak_(std::move(controller_weak)){};
+      controller_weak_(std::move(controller_weak)) {}
 
 FtraceDataSource::~FtraceDataSource() {
   if (controller_weak_)
     controller_weak_->RemoveDataSource(this);
-};
+}
 
 void FtraceDataSource::Initialize(
     FtraceConfigId config_id,
diff --git a/src/traced/probes/ftrace/proto_translation_table.cc b/src/traced/probes/ftrace/proto_translation_table.cc
index 86c61f0..ceb0973 100644
--- a/src/traced/probes/ftrace/proto_translation_table.cc
+++ b/src/traced/probes/ftrace/proto_translation_table.cc
@@ -521,12 +521,12 @@
   group_to_events_[e->group].push_back(&events_.at(e->ftrace_event_id));
 
   return e;
-};
+}
 
 const char* ProtoTranslationTable::InternString(const std::string& str) {
   auto it_and_inserted = interned_strings_.insert(str);
   return it_and_inserted.first->c_str();
-};
+}
 
 uint16_t ProtoTranslationTable::CreateGenericEventField(
     const FtraceEvent::Field& ftrace_field,
diff --git a/test/benchmark_main.cc b/test/benchmark_main.cc
index e410e52..3a3feaa 100644
--- a/test/benchmark_main.cc
+++ b/test/benchmark_main.cc
@@ -14,4 +14,4 @@
 
 #include <benchmark/benchmark.h>
 
-BENCHMARK_MAIN();
+BENCHMARK_MAIN()
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 41c844d..6892d1a 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -50,10 +50,12 @@
     "../../src/profiling/symbolizer:symbolize_database",
   ]
   public_deps = [
-    "../../gn:zlib",
     "../../include/perfetto/ext/base",
     "../../include/perfetto/profiling:deobfuscator",
   ]
+  if (enable_perfetto_zlib) {
+    public_deps += [ "../../gn:zlib" ]
+  }
   sources = [
     "utils.cc",
     "utils.h",
@@ -144,9 +146,11 @@
     ":utils",
     "../../gn:default_deps",
     "../../gn:protobuf_full",
-    "../../gn:zlib",
     "../../protos/perfetto/trace:zero",
   ]
+  if (enable_perfetto_zlib) {
+    deps += [ "../../gn:zlib" ]
+  }
   sources = [
     "proto_full_utils.cc",
     "proto_full_utils.h",
diff --git a/tools/trace_to_text/trace_to_text.cc b/tools/trace_to_text/trace_to_text.cc
index 3fb86d8..1616a2d 100644
--- a/tools/trace_to_text/trace_to_text.cc
+++ b/tools/trace_to_text/trace_to_text.cc
@@ -16,8 +16,6 @@
 
 #include "tools/trace_to_text/trace_to_text.h"
 
-#include <zlib.h>
-
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -31,6 +29,10 @@
 #include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#endif
+
 namespace perfetto {
 namespace trace_to_text {
 
@@ -78,6 +80,7 @@
 void PrintCompressedPackets(const std::string& packets,
                             Message* compressed_msg_scratch,
                             ZeroCopyOutputStream* output) {
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
   uint8_t out[4096];
   std::vector<uint8_t> data;
 
@@ -120,6 +123,24 @@
   }
   WriteToZeroCopyOutput(output, kCompressedPacketsSuffix,
                         sizeof(kCompressedPacketsSuffix) - 1);
+#else
+  base::ignore_result(packets);
+  base::ignore_result(compressed_msg_scratch);
+  base::ignore_result(kIndentedPacketPrefix);
+  base::ignore_result(kIndentedPacketSuffix);
+  WriteToZeroCopyOutput(output, kCompressedPacketsPrefix,
+                        sizeof(kCompressedPacketsPrefix) - 1);
+  static const char kErrMsg[] =
+      "Cannot decode compressed packets. zlib not enabled in the build config";
+  WriteToZeroCopyOutput(output, kErrMsg, sizeof(kErrMsg) - 1);
+  WriteToZeroCopyOutput(output, kCompressedPacketsSuffix,
+                        sizeof(kCompressedPacketsSuffix) - 1);
+  static bool log_once = [] {
+    PERFETTO_ELOG("%s", kErrMsg);
+    return true;
+  }();
+  base::ignore_result(log_once);
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 }
 
 }  // namespace
diff --git a/tools/trace_to_text/utils.cc b/tools/trace_to_text/utils.cc
index 73645f6..e655b38 100644
--- a/tools/trace_to_text/utils.cc
+++ b/tools/trace_to_text/utils.cc
@@ -39,8 +39,9 @@
 
 using Iterator = trace_processor::TraceProcessor::Iterator;
 
-
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 constexpr size_t kCompressionBufferSize = 500 * 1024;
+#endif
 
 std::map<std::string, std::set<std::string>> GetHeapGraphClasses(
     trace_processor::TraceProcessor* tp) {
@@ -179,7 +180,6 @@
   return true;
 }
 
-
 void DeobfuscateDatabase(
     trace_processor::TraceProcessor* tp,
     const std::map<std::string, profiling::ObfuscatedClass>& mapping,
@@ -229,6 +229,8 @@
   output_->write(data, static_cast<std::streamsize>(sz));
 }
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 DeflateTraceWriter::DeflateTraceWriter(std::ostream* output)
     : TraceWriter(output),
       buf_(base::PagedMemory::Allocate(kCompressionBufferSize)),
@@ -270,6 +272,15 @@
   PERFETTO_FATAL("Expected %d got %d: %s", actual_code, expected_code,
                  stream_.msg);
 }
+#else
+
+DeflateTraceWriter::DeflateTraceWriter(std::ostream* output)
+    : TraceWriter(output) {
+  PERFETTO_ELOG("Cannot compress. Zlib is not enabled in the build config");
+}
+DeflateTraceWriter::~DeflateTraceWriter() = default;
+
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 
 }  // namespace trace_to_text
 }  // namespace perfetto
diff --git a/tools/trace_to_text/utils.h b/tools/trace_to_text/utils.h
index 19bd3ca..d708e04 100644
--- a/tools/trace_to_text/utils.h
+++ b/tools/trace_to_text/utils.h
@@ -26,13 +26,15 @@
 #include <memory>
 #include <vector>
 
-#include <zlib.h>
-
 #include "perfetto/base/build_config.h"
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/paged_memory.h"
 #include "perfetto/profiling/deobfuscator.h"
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#endif
+
 namespace perfetto {
 
 namespace trace_processor {
@@ -83,6 +85,7 @@
   std::ostream* output_;
 };
 
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
 class DeflateTraceWriter : public TraceWriter {
  public:
   DeflateTraceWriter(std::ostream* output);
@@ -100,6 +103,17 @@
   uint8_t* const end_;
 };
 
+#else
+
+// Fallback implementation. Will print an error and write uncompressed.
+class DeflateTraceWriter : public TraceWriter {
+ public:
+  DeflateTraceWriter(std::ostream* output);
+  ~DeflateTraceWriter() override;
+};
+
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
 }  // namespace trace_to_text
 }  // namespace perfetto