Merge "trace_processor: Bounds checks for reading Fuchsia record data"
diff --git a/Android.bp b/Android.bp
index c65df9d..679b438 100644
--- a/Android.bp
+++ b/Android.bp
@@ -63,23 +63,33 @@
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -126,23 +136,33 @@
     "heapprofd.rc",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -252,23 +272,33 @@
     ":perfetto_include_perfetto_public_public",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -324,23 +354,33 @@
     "include/perfetto/base/build_configs/android_tree",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -420,23 +460,33 @@
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -476,23 +526,33 @@
     "include/perfetto/base/build_configs/android_tree",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -516,23 +576,33 @@
     "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   export_generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -577,23 +647,33 @@
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -635,23 +715,33 @@
     "libz",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -800,23 +890,33 @@
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -902,23 +1002,33 @@
     "libperfetto_client_experimental",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -963,6 +1073,78 @@
   ],
 }
 
+// GN: //protos/perfetto/common:cpp
+genrule {
+  name: "perfetto_protos_perfetto_common_cpp_gen",
+  srcs: [
+    "protos/perfetto/common/android_log_constants.proto",
+    "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
+    "protos/perfetto/common/descriptor.proto",
+    "protos/perfetto/common/gpu_counter_descriptor.proto",
+    "protos/perfetto/common/observable_events.proto",
+    "protos/perfetto/common/sys_stats_counters.proto",
+    "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
+    "protos/perfetto/common/track_event_descriptor.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/common/android_log_constants.gen.cc",
+    "external/perfetto/protos/perfetto/common/commit_data_request.gen.cc",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.gen.cc",
+    "external/perfetto/protos/perfetto/common/descriptor.gen.cc",
+    "external/perfetto/protos/perfetto/common/gpu_counter_descriptor.gen.cc",
+    "external/perfetto/protos/perfetto/common/observable_events.gen.cc",
+    "external/perfetto/protos/perfetto/common/sys_stats_counters.gen.cc",
+    "external/perfetto/protos/perfetto/common/trace_stats.gen.cc",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.gen.cc",
+    "external/perfetto/protos/perfetto/common/track_event_descriptor.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/common:cpp
+genrule {
+  name: "perfetto_protos_perfetto_common_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/common/android_log_constants.proto",
+    "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
+    "protos/perfetto/common/descriptor.proto",
+    "protos/perfetto/common/gpu_counter_descriptor.proto",
+    "protos/perfetto/common/observable_events.proto",
+    "protos/perfetto/common/sys_stats_counters.proto",
+    "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
+    "protos/perfetto/common/track_event_descriptor.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/common/android_log_constants.gen.h",
+    "external/perfetto/protos/perfetto/common/commit_data_request.gen.h",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.gen.h",
+    "external/perfetto/protos/perfetto/common/descriptor.gen.h",
+    "external/perfetto/protos/perfetto/common/gpu_counter_descriptor.gen.h",
+    "external/perfetto/protos/perfetto/common/observable_events.gen.h",
+    "external/perfetto/protos/perfetto/common/sys_stats_counters.gen.h",
+    "external/perfetto/protos/perfetto/common/trace_stats.gen.h",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.gen.h",
+    "external/perfetto/protos/perfetto/common/track_event_descriptor.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/common:lite
 genrule {
   name: "perfetto_protos_perfetto_common_lite_gen",
@@ -1105,6 +1287,46 @@
   ],
 }
 
+// GN: //protos/perfetto/config/android:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_android_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/android/android_log_config.proto",
+    "protos/perfetto/config/android/packages_list_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/android/android_log_config.gen.cc",
+    "external/perfetto/protos/perfetto/config/android/packages_list_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/android:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_android_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/android/android_log_config.proto",
+    "protos/perfetto/config/android/packages_list_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/android/android_log_config.gen.h",
+    "external/perfetto/protos/perfetto/config/android/packages_list_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/android:lite
 genrule {
   name: "perfetto_protos_perfetto_config_android_lite_gen",
@@ -1183,6 +1405,90 @@
   ],
 }
 
+// GN: //protos/perfetto/config:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/chrome/chrome_config.proto",
+    "protos/perfetto/config/data_source_config.proto",
+    "protos/perfetto/config/test_config.proto",
+    "protos/perfetto/config/trace_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/chrome/chrome_config.gen.cc",
+    "external/perfetto/protos/perfetto/config/data_source_config.gen.cc",
+    "external/perfetto/protos/perfetto/config/test_config.gen.cc",
+    "external/perfetto/protos/perfetto/config/trace_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/chrome/chrome_config.proto",
+    "protos/perfetto/config/data_source_config.proto",
+    "protos/perfetto/config/test_config.proto",
+    "protos/perfetto/config/trace_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/chrome/chrome_config.gen.h",
+    "external/perfetto/protos/perfetto/config/data_source_config.gen.h",
+    "external/perfetto/protos/perfetto/config/test_config.gen.h",
+    "external/perfetto/protos/perfetto/config/trace_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
+// GN: //protos/perfetto/config/ftrace:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_ftrace_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/ftrace/ftrace_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/ftrace:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/ftrace/ftrace_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/ftrace:lite
 genrule {
   name: "perfetto_protos_perfetto_config_ftrace_lite_gen",
@@ -1253,6 +1559,42 @@
   ],
 }
 
+// GN: //protos/perfetto/config/gpu:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_gpu_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/gpu/gpu_counter_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/gpu/gpu_counter_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/gpu:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/gpu/gpu_counter_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/gpu/gpu_counter_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/gpu:lite
 genrule {
   name: "perfetto_protos_perfetto_config_gpu_lite_gen",
@@ -1323,6 +1665,42 @@
   ],
 }
 
+// GN: //protos/perfetto/config/inode_file:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_inode_file_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/inode_file/inode_file_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/inode_file:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/inode_file/inode_file_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/inode_file:lite
 genrule {
   name: "perfetto_protos_perfetto_config_inode_file_lite_gen",
@@ -1439,6 +1817,42 @@
   ],
 }
 
+// GN: //protos/perfetto/config/power:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_power_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/power/android_power_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/power/android_power_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/power:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_power_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/power/android_power_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/power/android_power_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/power:lite
 genrule {
   name: "perfetto_protos_perfetto_config_power_lite_gen",
@@ -1509,6 +1923,42 @@
   ],
 }
 
+// GN: //protos/perfetto/config/process_stats:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_process_stats_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/process_stats/process_stats_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/process_stats:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/process_stats/process_stats_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/process_stats:lite
 genrule {
   name: "perfetto_protos_perfetto_config_process_stats_lite_gen",
@@ -1579,6 +2029,46 @@
   ],
 }
 
+// GN: //protos/perfetto/config/profiling:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_profiling_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/profiling/heapprofd_config.proto",
+    "protos/perfetto/config/profiling/java_hprof_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/profiling/heapprofd_config.gen.cc",
+    "external/perfetto/protos/perfetto/config/profiling/java_hprof_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/profiling:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/profiling/heapprofd_config.proto",
+    "protos/perfetto/config/profiling/java_hprof_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/profiling/heapprofd_config.gen.h",
+    "external/perfetto/protos/perfetto/config/profiling/java_hprof_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/profiling:lite
 genrule {
   name: "perfetto_protos_perfetto_config_profiling_lite_gen",
@@ -1657,6 +2147,42 @@
   ],
 }
 
+// GN: //protos/perfetto/config/sys_stats:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_sys_stats_cpp_gen",
+  srcs: [
+    "protos/perfetto/config/sys_stats/sys_stats_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/sys_stats/sys_stats_config.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/config/sys_stats:cpp
+genrule {
+  name: "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/config/sys_stats/sys_stats_config.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/config/sys_stats/sys_stats_config.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/config/sys_stats:lite
 genrule {
   name: "perfetto_protos_perfetto_config_sys_stats_lite_gen",
@@ -3751,9 +4277,7 @@
   srcs: [
     "src/profiling/memory/bookkeeping.cc",
     "src/profiling/memory/bookkeeping_dump.cc",
-    "src/profiling/memory/heapprofd_config.cc",
     "src/profiling/memory/heapprofd_producer.cc",
-    "src/profiling/memory/java_hprof_config.cc",
     "src/profiling/memory/java_hprof_producer.cc",
     "src/profiling/memory/page_idle_checker.cc",
     "src/profiling/memory/system_property.cc",
@@ -3835,6 +4359,27 @@
   ],
 }
 
+// GN: //src/protozero/protoc_plugin:cppgen_plugin
+cc_binary_host {
+  name: "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  srcs: [
+    ":perfetto_include_perfetto_base_base",
+    ":perfetto_include_perfetto_ext_base_base",
+    ":perfetto_src_base_base",
+    "src/protozero/protoc_plugin/cppgen_plugin.cc",
+  ],
+  shared_libs: [
+    "libprotoc",
+  ],
+  defaults: [
+    "perfetto_defaults",
+  ],
+  cflags: [
+    "-DGOOGLE_PROTOBUF_NO_RTTI",
+    "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+  ],
+}
+
 // GN: //src/protozero:protozero
 filegroup {
   name: "perfetto_src_protozero_protozero",
@@ -4195,7 +4740,6 @@
     "src/traced/probes/ftrace/cpu_stats_parser.cc",
     "src/traced/probes/ftrace/event_info.cc",
     "src/traced/probes/ftrace/event_info_constants.cc",
-    "src/traced/probes/ftrace/ftrace_config.cc",
     "src/traced/probes/ftrace/ftrace_config_muxer.cc",
     "src/traced/probes/ftrace/ftrace_config_utils.cc",
     "src/traced/probes/ftrace/ftrace_controller.cc",
@@ -4492,28 +5036,19 @@
 filegroup {
   name: "perfetto_src_tracing_tracing",
   srcs: [
-    "src/tracing/core/chrome_config.cc",
-    "src/tracing/core/commit_data_request.cc",
-    "src/tracing/core/data_source_config.cc",
-    "src/tracing/core/data_source_descriptor.cc",
     "src/tracing/core/id_allocator.cc",
     "src/tracing/core/metatrace_writer.cc",
     "src/tracing/core/null_trace_writer.cc",
-    "src/tracing/core/observable_events.cc",
     "src/tracing/core/packet_stream_validator.cc",
     "src/tracing/core/shared_memory_abi.cc",
     "src/tracing/core/shared_memory_arbiter_impl.cc",
     "src/tracing/core/sliced_protobuf_input_stream.cc",
     "src/tracing/core/startup_trace_writer.cc",
     "src/tracing/core/startup_trace_writer_registry.cc",
-    "src/tracing/core/test_config.cc",
     "src/tracing/core/trace_buffer.cc",
-    "src/tracing/core/trace_config.cc",
     "src/tracing/core/trace_packet.cc",
-    "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
-    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
   ],
 }
@@ -4752,23 +5287,33 @@
     ":perfetto_include_perfetto_trace_processor_trace_processor",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -4885,23 +5430,33 @@
   ],
   generated_headers: [
     "gen_merged_sql_metrics",
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -5292,23 +5847,33 @@
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_tracing_core_core",
     ":perfetto_include_perfetto_tracing_tracing",
+    ":perfetto_protos_perfetto_common_cpp_gen",
     ":perfetto_protos_perfetto_common_lite_gen",
     ":perfetto_protos_perfetto_common_zero_gen",
+    ":perfetto_protos_perfetto_config_android_cpp_gen",
     ":perfetto_protos_perfetto_config_android_lite_gen",
     ":perfetto_protos_perfetto_config_android_zero_gen",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+    ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
     ":perfetto_protos_perfetto_config_ftrace_lite_gen",
     ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+    ":perfetto_protos_perfetto_config_gpu_cpp_gen",
     ":perfetto_protos_perfetto_config_gpu_lite_gen",
     ":perfetto_protos_perfetto_config_gpu_zero_gen",
+    ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
     ":perfetto_protos_perfetto_config_inode_file_lite_gen",
     ":perfetto_protos_perfetto_config_inode_file_zero_gen",
     ":perfetto_protos_perfetto_config_lite_gen",
+    ":perfetto_protos_perfetto_config_power_cpp_gen",
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_power_zero_gen",
+    ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+    ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
+    ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -5347,23 +5912,33 @@
     "libprotobuf-cpp-lite",
   ],
   generated_headers: [
+    "perfetto_protos_perfetto_common_cpp_gen_headers",
     "perfetto_protos_perfetto_common_lite_gen_headers",
     "perfetto_protos_perfetto_common_zero_gen_headers",
+    "perfetto_protos_perfetto_config_android_cpp_gen_headers",
     "perfetto_protos_perfetto_config_android_lite_gen_headers",
     "perfetto_protos_perfetto_config_android_zero_gen_headers",
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
+    "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_lite_gen_headers",
     "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+    "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
     "perfetto_protos_perfetto_config_gpu_lite_gen_headers",
     "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+    "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_lite_gen_headers",
     "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
     "perfetto_protos_perfetto_config_lite_gen_headers",
+    "perfetto_protos_perfetto_config_power_cpp_gen_headers",
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
+    "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+    "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
diff --git a/BUILD b/BUILD
index 1170b2c..4063dd8 100644
--- a/BUILD
+++ b/BUILD
@@ -21,6 +21,7 @@
     "perfetto_cc_ipc_library",
     "perfetto_cc_library",
     "perfetto_cc_proto_library",
+    "perfetto_cc_protocpp_library",
     "perfetto_cc_protozero_library",
     "perfetto_java_proto_library",
     "perfetto_proto_library",
@@ -69,6 +70,19 @@
     ] + PERFETTO_CONFIG.deps.protobuf_lite,
 )
 
+# GN target: //src/protozero/protoc_plugin:cppgen_plugin
+perfetto_cc_binary(
+    name = "cppgen_plugin",
+    srcs = [
+        "src/protozero/protoc_plugin/cppgen_plugin.cc",
+        ":include_perfetto_base_base",
+        ":include_perfetto_ext_base_base",
+        ":src_base_base",
+    ],
+    deps = [
+    ] + PERFETTO_CONFIG.deps.protoc_lib,
+)
+
 # GN target: //src/protozero/protoc_plugin:protozero_plugin
 perfetto_cc_binary(
     name = "protozero_plugin",
@@ -137,23 +151,33 @@
         ":include_perfetto_tracing_tracing",
     ],
     deps = [
+        ":protos_perfetto_common_cpp",
         ":protos_perfetto_common_lite",
         ":protos_perfetto_common_zero",
+        ":protos_perfetto_config_android_cpp",
         ":protos_perfetto_config_android_lite",
         ":protos_perfetto_config_android_zero",
+        ":protos_perfetto_config_cpp",
+        ":protos_perfetto_config_ftrace_cpp",
         ":protos_perfetto_config_ftrace_lite",
         ":protos_perfetto_config_ftrace_zero",
+        ":protos_perfetto_config_gpu_cpp",
         ":protos_perfetto_config_gpu_lite",
         ":protos_perfetto_config_gpu_zero",
+        ":protos_perfetto_config_inode_file_cpp",
         ":protos_perfetto_config_inode_file_lite",
         ":protos_perfetto_config_inode_file_zero",
         ":protos_perfetto_config_lite",
+        ":protos_perfetto_config_power_cpp",
         ":protos_perfetto_config_power_lite",
         ":protos_perfetto_config_power_zero",
+        ":protos_perfetto_config_process_stats_cpp",
         ":protos_perfetto_config_process_stats_lite",
         ":protos_perfetto_config_process_stats_zero",
+        ":protos_perfetto_config_profiling_cpp",
         ":protos_perfetto_config_profiling_lite",
         ":protos_perfetto_config_profiling_zero",
+        ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_sys_stats_lite",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_zero",
@@ -352,7 +376,6 @@
         "include/perfetto/tracing/core/chrome_config.h",
         "include/perfetto/tracing/core/data_source_config.h",
         "include/perfetto/tracing/core/data_source_descriptor.h",
-        "include/perfetto/tracing/core/test_config.h",
         "include/perfetto/tracing/core/trace_config.h",
         "include/perfetto/tracing/core/tracing_service_state.h",
     ],
@@ -703,6 +726,7 @@
         "src/trace_processor/systrace_trace_parser.h",
         "src/trace_processor/thread_table.cc",
         "src/trace_processor/thread_table.h",
+        "src/trace_processor/timestamped_trace_piece.h",
         "src/trace_processor/trace_blob_view.h",
         "src/trace_processor/trace_parser.h",
         "src/trace_processor/trace_processor.cc",
@@ -780,8 +804,6 @@
         "src/traced/probes/ftrace/event_info.h",
         "src/traced/probes/ftrace/event_info_constants.cc",
         "src/traced/probes/ftrace/event_info_constants.h",
-        "src/traced/probes/ftrace/ftrace_config.cc",
-        "src/traced/probes/ftrace/ftrace_config.h",
         "src/traced/probes/ftrace/ftrace_config_muxer.cc",
         "src/traced/probes/ftrace/ftrace_config_muxer.h",
         "src/traced/probes/ftrace/ftrace_config_utils.cc",
@@ -948,17 +970,12 @@
 filegroup(
     name = "src_tracing_tracing",
     srcs = [
-        "src/tracing/core/chrome_config.cc",
-        "src/tracing/core/commit_data_request.cc",
-        "src/tracing/core/data_source_config.cc",
-        "src/tracing/core/data_source_descriptor.cc",
         "src/tracing/core/id_allocator.cc",
         "src/tracing/core/id_allocator.h",
         "src/tracing/core/metatrace_writer.cc",
         "src/tracing/core/metatrace_writer.h",
         "src/tracing/core/null_trace_writer.cc",
         "src/tracing/core/null_trace_writer.h",
-        "src/tracing/core/observable_events.cc",
         "src/tracing/core/packet_stream_validator.cc",
         "src/tracing/core/packet_stream_validator.h",
         "src/tracing/core/patch_list.h",
@@ -968,17 +985,13 @@
         "src/tracing/core/sliced_protobuf_input_stream.cc",
         "src/tracing/core/startup_trace_writer.cc",
         "src/tracing/core/startup_trace_writer_registry.cc",
-        "src/tracing/core/test_config.cc",
         "src/tracing/core/trace_buffer.cc",
         "src/tracing/core/trace_buffer.h",
-        "src/tracing/core/trace_config.cc",
         "src/tracing/core/trace_packet.cc",
-        "src/tracing/core/trace_stats.cc",
         "src/tracing/core/trace_writer_impl.cc",
         "src/tracing/core/trace_writer_impl.h",
         "src/tracing/core/tracing_service_impl.cc",
         "src/tracing/core/tracing_service_impl.h",
-        "src/tracing/core/tracing_service_state.cc",
         "src/tracing/core/virtual_destructors.cc",
     ],
 )
@@ -1048,6 +1061,35 @@
 # Proto libraries
 # ##############################################################################
 
+# GN target: //protos/perfetto/common:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_common_cpp",
+    deps = [
+        ":protos_perfetto_common_cpp_protos",
+        ":protos_perfetto_common_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/common:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_common_cpp_protos",
+    srcs = [
+        "protos/perfetto/common/android_log_constants.proto",
+        "protos/perfetto/common/commit_data_request.proto",
+        "protos/perfetto/common/data_source_descriptor.proto",
+        "protos/perfetto/common/descriptor.proto",
+        "protos/perfetto/common/gpu_counter_descriptor.proto",
+        "protos/perfetto/common/observable_events.proto",
+        "protos/perfetto/common/sys_stats_counters.proto",
+        "protos/perfetto/common/trace_stats.proto",
+        "protos/perfetto/common/tracing_service_state.proto",
+        "protos/perfetto/common/track_event_descriptor.proto",
+    ],
+    deps = [
+        ":protos_perfetto_common_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/common:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_common_lite",
@@ -1081,6 +1123,31 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/android:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_android_cpp",
+    deps = [
+        ":protos_perfetto_config_android_cpp_protos",
+        ":protos_perfetto_common_lite",
+        ":protos_perfetto_config_android_lite",
+        ":protos_perfetto_common_cpp",
+    ],
+)
+
+# GN target: //protos/perfetto/config/android:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_android_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/android/android_log_config.proto",
+        "protos/perfetto/config/android/packages_list_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_common_cpp_protos",
+        ":protos_perfetto_common_protos",
+        ":protos_perfetto_config_android_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/android:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_android_lite",
@@ -1109,6 +1176,85 @@
     ],
 )
 
+# GN target: //protos/perfetto/config:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_cpp",
+    deps = [
+        ":protos_perfetto_config_cpp_protos",
+        ":protos_perfetto_config_inode_file_cpp",
+        ":protos_perfetto_config_android_cpp",
+        ":protos_perfetto_config_lite",
+        ":protos_perfetto_config_android_lite",
+        ":protos_perfetto_common_cpp",
+        ":protos_perfetto_config_gpu_lite",
+        ":protos_perfetto_common_lite",
+        ":protos_perfetto_config_profiling_lite",
+        ":protos_perfetto_config_process_stats_cpp",
+        ":protos_perfetto_config_power_cpp",
+        ":protos_perfetto_config_process_stats_lite",
+        ":protos_perfetto_config_power_lite",
+        ":protos_perfetto_config_profiling_cpp",
+        ":protos_perfetto_config_inode_file_lite",
+        ":protos_perfetto_config_gpu_cpp",
+        ":protos_perfetto_config_ftrace_lite",
+        ":protos_perfetto_config_sys_stats_lite",
+        ":protos_perfetto_config_ftrace_cpp",
+        ":protos_perfetto_config_sys_stats_cpp",
+    ],
+)
+
+# GN target: //protos/perfetto/config:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/chrome/chrome_config.proto",
+        "protos/perfetto/config/data_source_config.proto",
+        "protos/perfetto/config/test_config.proto",
+        "protos/perfetto/config/trace_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_common_cpp_protos",
+        ":protos_perfetto_common_protos",
+        ":protos_perfetto_config_android_cpp_protos",
+        ":protos_perfetto_config_android_protos",
+        ":protos_perfetto_config_ftrace_cpp_protos",
+        ":protos_perfetto_config_ftrace_protos",
+        ":protos_perfetto_config_gpu_cpp_protos",
+        ":protos_perfetto_config_gpu_protos",
+        ":protos_perfetto_config_inode_file_cpp_protos",
+        ":protos_perfetto_config_inode_file_protos",
+        ":protos_perfetto_config_power_cpp_protos",
+        ":protos_perfetto_config_power_protos",
+        ":protos_perfetto_config_process_stats_cpp_protos",
+        ":protos_perfetto_config_process_stats_protos",
+        ":protos_perfetto_config_profiling_cpp_protos",
+        ":protos_perfetto_config_profiling_protos",
+        ":protos_perfetto_config_protos",
+        ":protos_perfetto_config_sys_stats_cpp_protos",
+        ":protos_perfetto_config_sys_stats_protos",
+    ],
+)
+
+# GN target: //protos/perfetto/config/ftrace:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_ftrace_cpp",
+    deps = [
+        ":protos_perfetto_config_ftrace_cpp_protos",
+        ":protos_perfetto_config_ftrace_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/ftrace:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_ftrace_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/ftrace/ftrace_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_ftrace_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/ftrace:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_ftrace_lite",
@@ -1133,6 +1279,26 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/gpu:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_gpu_cpp",
+    deps = [
+        ":protos_perfetto_config_gpu_cpp_protos",
+        ":protos_perfetto_config_gpu_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/gpu:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_gpu_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/gpu/gpu_counter_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_gpu_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/gpu:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_gpu_lite",
@@ -1157,6 +1323,26 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/inode_file:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_inode_file_cpp",
+    deps = [
+        ":protos_perfetto_config_inode_file_cpp_protos",
+        ":protos_perfetto_config_inode_file_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/inode_file:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_inode_file_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/inode_file/inode_file_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_inode_file_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/inode_file:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_inode_file_lite",
@@ -1208,6 +1394,26 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/power:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_power_cpp",
+    deps = [
+        ":protos_perfetto_config_power_cpp_protos",
+        ":protos_perfetto_config_power_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/power:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_power_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/power/android_power_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_power_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/power:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_power_lite",
@@ -1232,6 +1438,26 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/process_stats:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_process_stats_cpp",
+    deps = [
+        ":protos_perfetto_config_process_stats_cpp_protos",
+        ":protos_perfetto_config_process_stats_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/process_stats:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_process_stats_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/process_stats/process_stats_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_process_stats_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/process_stats:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_process_stats_lite",
@@ -1256,6 +1482,27 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/profiling:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_profiling_cpp",
+    deps = [
+        ":protos_perfetto_config_profiling_cpp_protos",
+        ":protos_perfetto_config_profiling_lite",
+    ],
+)
+
+# GN target: //protos/perfetto/config/profiling:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_profiling_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/profiling/heapprofd_config.proto",
+        "protos/perfetto/config/profiling/java_hprof_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_config_profiling_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/profiling:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_profiling_lite",
@@ -1303,6 +1550,30 @@
     ],
 )
 
+# GN target: //protos/perfetto/config/sys_stats:cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_config_sys_stats_cpp",
+    deps = [
+        ":protos_perfetto_config_sys_stats_cpp_protos",
+        ":protos_perfetto_common_lite",
+        ":protos_perfetto_config_sys_stats_lite",
+        ":protos_perfetto_common_cpp",
+    ],
+)
+
+# GN target: //protos/perfetto/config/sys_stats:cpp
+perfetto_proto_library(
+    name = "protos_perfetto_config_sys_stats_cpp_protos",
+    srcs = [
+        "protos/perfetto/config/sys_stats/sys_stats_config.proto",
+    ],
+    deps = [
+        ":protos_perfetto_common_cpp_protos",
+        ":protos_perfetto_common_protos",
+        ":protos_perfetto_config_sys_stats_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/config/sys_stats:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_config_sys_stats_lite",
@@ -2016,23 +2287,33 @@
         "//visibility:public",
     ],
     deps = [
+        ":protos_perfetto_common_cpp",
         ":protos_perfetto_common_lite",
         ":protos_perfetto_common_zero",
+        ":protos_perfetto_config_android_cpp",
         ":protos_perfetto_config_android_lite",
         ":protos_perfetto_config_android_zero",
+        ":protos_perfetto_config_cpp",
+        ":protos_perfetto_config_ftrace_cpp",
         ":protos_perfetto_config_ftrace_lite",
         ":protos_perfetto_config_ftrace_zero",
+        ":protos_perfetto_config_gpu_cpp",
         ":protos_perfetto_config_gpu_lite",
         ":protos_perfetto_config_gpu_zero",
+        ":protos_perfetto_config_inode_file_cpp",
         ":protos_perfetto_config_inode_file_lite",
         ":protos_perfetto_config_inode_file_zero",
         ":protos_perfetto_config_lite",
+        ":protos_perfetto_config_power_cpp",
         ":protos_perfetto_config_power_lite",
         ":protos_perfetto_config_power_zero",
+        ":protos_perfetto_config_process_stats_cpp",
         ":protos_perfetto_config_process_stats_lite",
         ":protos_perfetto_config_process_stats_zero",
+        ":protos_perfetto_config_profiling_cpp",
         ":protos_perfetto_config_profiling_lite",
         ":protos_perfetto_config_profiling_zero",
+        ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_sys_stats_lite",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_zero",
@@ -2087,23 +2368,33 @@
         "//visibility:public",
     ],
     deps = [
+               ":protos_perfetto_common_cpp",
                ":protos_perfetto_common_lite",
                ":protos_perfetto_common_zero",
+               ":protos_perfetto_config_android_cpp",
                ":protos_perfetto_config_android_lite",
                ":protos_perfetto_config_android_zero",
+               ":protos_perfetto_config_cpp",
+               ":protos_perfetto_config_ftrace_cpp",
                ":protos_perfetto_config_ftrace_lite",
                ":protos_perfetto_config_ftrace_zero",
+               ":protos_perfetto_config_gpu_cpp",
                ":protos_perfetto_config_gpu_lite",
                ":protos_perfetto_config_gpu_zero",
+               ":protos_perfetto_config_inode_file_cpp",
                ":protos_perfetto_config_inode_file_lite",
                ":protos_perfetto_config_inode_file_zero",
                ":protos_perfetto_config_lite",
+               ":protos_perfetto_config_power_cpp",
                ":protos_perfetto_config_power_lite",
                ":protos_perfetto_config_power_zero",
+               ":protos_perfetto_config_process_stats_cpp",
                ":protos_perfetto_config_process_stats_lite",
                ":protos_perfetto_config_process_stats_zero",
+               ":protos_perfetto_config_profiling_cpp",
                ":protos_perfetto_config_profiling_lite",
                ":protos_perfetto_config_profiling_zero",
+               ":protos_perfetto_config_sys_stats_cpp",
                ":protos_perfetto_config_sys_stats_lite",
                ":protos_perfetto_config_sys_stats_zero",
                ":protos_perfetto_config_zero",
diff --git a/BUILD.gn b/BUILD.gn
index 831a546..f73a5e9 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -106,6 +106,12 @@
     "protos/perfetto/config:merged_config",
     "protos/perfetto/trace:merged_trace",  # For syntax-checking the proto.
 
+    # For checking all generated xxx.gen.{cc,h} files without waiting for
+    # embedders to try to use them and fail.
+    "protos/perfetto/trace:cpp",
+    "protos/perfetto/config:cpp",
+    "protos/perfetto/common:cpp",
+
     # The diff testing framework depends on these descriptors.
     "protos/perfetto/metrics:descriptor($host_toolchain)",
     "protos/perfetto/trace:descriptor($host_toolchain)",
diff --git a/bazel/rules.bzl b/bazel/rules.bzl
index 8713984..61941ad 100644
--- a/bazel/rules.bzl
+++ b/bazel/rules.bzl
@@ -146,6 +146,51 @@
         **kwargs
     )
 
+
+# Generates .gen.{cc,h} from .proto(s).
+def perfetto_cc_protocpp_library(name, deps, **kwargs):
+    if _rule_override(
+        "cc_protocpp_library",
+        name = name,
+        deps = deps,
+        **kwargs
+    ):
+        return
+
+    # A perfetto_cc_protocpp_library has two types of dependencies:
+    # 1. Exactly one dependency on a proto_library target. This defines the
+    #    .proto sources for the target
+    # 2. Zero or more deps on other perfetto_cc_protocpp_library targets. This
+    #    to deal with the case of foo.proto including common.proto from another
+    #    target.
+    _proto_deps = [d for d in deps if d.endswith("_protos")]
+    _cc_deps = [d for d in deps if d not in _proto_deps]
+
+    proto_gen(
+        name = name + "_gen",
+        deps = _proto_deps,
+        suffix = "gen",
+        plugin = PERFETTO_CONFIG.root + ":cppgen_plugin",
+        protoc = PERFETTO_CONFIG.deps.protoc[0],
+        root = PERFETTO_CONFIG.root,
+    )
+
+    native.filegroup(
+        name = name + "_gen_h",
+        srcs = [":" + name + "_gen"],
+        output_group = "h",
+    )
+
+    perfetto_cc_library(
+        name = name,
+        srcs = [":" + name + "_gen"],
+        hdrs = [":" + name + "_gen_h"],
+        deps = [
+            PERFETTO_CONFIG.root + ":libprotozero"
+        ] + _cc_deps,
+        **kwargs
+    )
+
 # +----------------------------------------------------------------------------+
 # | Misc utility functions                                                     |
 # +----------------------------------------------------------------------------+
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index b4c1ab0..c7af114 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -94,6 +94,48 @@
   }
 }
 
+# This template generates .gen.cc/h files from .proto files. The generated
+# sources are actual C++ classes that can be moved and copied around, very
+# similar to the libprotobuf generated ones API-wise, but use protozero under
+# the hoods, without any zero-copy benefit though.
+# They are mainly used for the perfetto IPC layer and tests.
+template("protozero_cpp_library") {
+  proto_library(target_name) {
+    perfetto_root_path = invoker.perfetto_root_path
+
+    generate_cc = false
+    generate_python = false
+    generator_plugin_label =
+        perfetto_root_path + "src/protozero/protoc_plugin:cppgen_plugin"
+    generator_plugin_suffix = ".gen"
+    if (build_with_chromium) {
+      component_build_force_source_set = true
+    }
+
+    deps = [
+      "$perfetto_root_path/gn:default_deps",
+      "$perfetto_root_path/include/perfetto/base",
+    ]
+
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
+    forward_variables_from(invoker,
+                           [
+                             "defines",
+                             "generator_plugin_options",
+                             "include_dirs",
+                             "proto_in_dir",
+                             "proto_out_dir",
+                             "sources",
+                             "testonly",
+                             "visibility",
+                             "generate_descriptor",
+                           ])
+  }
+}
+
 # The template used everywhere in the codebase.
 template("perfetto_proto_library") {
   if (defined(invoker.proto_generators)) {
@@ -102,6 +144,7 @@
     proto_generators = [
       "zero",
       "lite",
+      "cpp",
     ]
   }
 
@@ -117,16 +160,16 @@
     "visibility",
     "testonly",
   ]
-  type_expansion_token = "@TYPE@"
+  expansion_token = "@TYPE@"
 
   foreach(gen_type, proto_generators) {
-    target_name_ = string_replace(target_name, type_expansion_token, gen_type)
+    target_name_ = string_replace(target_name, expansion_token, gen_type)
 
     # Translate deps from xxx:@TYPE@ to xxx:lite/zero.
     deps_ = []
     if (defined(invoker.deps)) {
       foreach(dep, invoker.deps) {
-        deps_ += [ string_replace(dep, type_expansion_token, gen_type) ]
+        deps_ += [ string_replace(dep, expansion_token, gen_type) ]
       }
     }
 
@@ -138,6 +181,14 @@
         deps = deps_
         forward_variables_from(invoker, vars_to_forward)
       }
+    } else if (gen_type == "cpp") {
+      lite_target_name_ = string_replace(target_name, expansion_token, "lite")
+      protozero_cpp_library(target_name_) {
+        proto_in_dir = proto_path
+        proto_out_dir = proto_path
+        deps = deps_ + [ ":$lite_target_name_" ]
+        forward_variables_from(invoker, vars_to_forward)
+      }
     } else if (gen_type == "lite") {
       proto_library(target_name_) {
         proto_in_dir = proto_path
diff --git a/include/perfetto/ext/tracing/core/BUILD.gn b/include/perfetto/ext/tracing/core/BUILD.gn
index 1df092a..e88fd768 100644
--- a/include/perfetto/ext/tracing/core/BUILD.gn
+++ b/include/perfetto/ext/tracing/core/BUILD.gn
@@ -14,6 +14,7 @@
 
 source_set("core") {
   public_deps = [
+    "../../../../../protos/perfetto/common:cpp",
     "../../../tracing/core",
     "../../base",
   ]
diff --git a/include/perfetto/ext/tracing/core/commit_data_request.h b/include/perfetto/ext/tracing/core/commit_data_request.h
index 4cf6282..baff757 100644
--- a/include/perfetto/ext/tracing/core/commit_data_request.h
+++ b/include/perfetto/ext/tracing/core/commit_data_request.h
@@ -14,230 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/commit_data_request.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_COMMIT_DATA_REQUEST_H_
 #define INCLUDE_PERFETTO_EXT_TRACING_CORE_COMMIT_DATA_REQUEST_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class CommitDataRequest;
-class CommitDataRequest_ChunksToMove;
-class CommitDataRequest_ChunkToPatch;
-class CommitDataRequest_ChunkToPatch_Patch;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class CommitDataRequest;
-
-class PERFETTO_EXPORT CommitDataRequest {
- public:
-  class PERFETTO_EXPORT ChunksToMove {
-   public:
-    ChunksToMove();
-    ~ChunksToMove();
-    ChunksToMove(ChunksToMove&&) noexcept;
-    ChunksToMove& operator=(ChunksToMove&&);
-    ChunksToMove(const ChunksToMove&);
-    ChunksToMove& operator=(const ChunksToMove&);
-    bool operator==(const ChunksToMove&) const;
-    bool operator!=(const ChunksToMove& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::CommitDataRequest_ChunksToMove&);
-    void ToProto(perfetto::protos::CommitDataRequest_ChunksToMove*) const;
-
-    uint32_t page() const { return page_; }
-    void set_page(uint32_t value) { page_ = value; }
-
-    uint32_t chunk() const { return chunk_; }
-    void set_chunk(uint32_t value) { chunk_ = value; }
-
-    uint32_t target_buffer() const { return target_buffer_; }
-    void set_target_buffer(uint32_t value) { target_buffer_ = value; }
-
-   private:
-    uint32_t page_{};
-    uint32_t chunk_{};
-    uint32_t target_buffer_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT ChunkToPatch {
-   public:
-    class PERFETTO_EXPORT Patch {
-     public:
-      Patch();
-      ~Patch();
-      Patch(Patch&&) noexcept;
-      Patch& operator=(Patch&&);
-      Patch(const Patch&);
-      Patch& operator=(const Patch&);
-      bool operator==(const Patch&) const;
-      bool operator!=(const Patch& other) const { return !(*this == other); }
-
-      // Raw proto decoding.
-      void ParseRawProto(const std::string&);
-      // Conversion methods from/to the corresponding protobuf types.
-      void FromProto(
-          const perfetto::protos::CommitDataRequest_ChunkToPatch_Patch&);
-      void ToProto(
-          perfetto::protos::CommitDataRequest_ChunkToPatch_Patch*) const;
-
-      uint32_t offset() const { return offset_; }
-      void set_offset(uint32_t value) { offset_ = value; }
-
-      const std::string& data() const { return data_; }
-      void set_data(const std::string& value) { data_ = value; }
-      void set_data(const void* p, size_t s) {
-        data_.assign(reinterpret_cast<const char*>(p), s);
-      }
-
-     private:
-      uint32_t offset_{};
-      std::string data_{};
-
-      // Allows to preserve unknown protobuf fields for compatibility
-      // with future versions of .proto files.
-      std::string unknown_fields_;
-    };
-
-    ChunkToPatch();
-    ~ChunkToPatch();
-    ChunkToPatch(ChunkToPatch&&) noexcept;
-    ChunkToPatch& operator=(ChunkToPatch&&);
-    ChunkToPatch(const ChunkToPatch&);
-    ChunkToPatch& operator=(const ChunkToPatch&);
-    bool operator==(const ChunkToPatch&) const;
-    bool operator!=(const ChunkToPatch& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::CommitDataRequest_ChunkToPatch&);
-    void ToProto(perfetto::protos::CommitDataRequest_ChunkToPatch*) const;
-
-    uint32_t target_buffer() const { return target_buffer_; }
-    void set_target_buffer(uint32_t value) { target_buffer_ = value; }
-
-    uint32_t writer_id() const { return writer_id_; }
-    void set_writer_id(uint32_t value) { writer_id_ = value; }
-
-    uint32_t chunk_id() const { return chunk_id_; }
-    void set_chunk_id(uint32_t value) { chunk_id_ = value; }
-
-    int patches_size() const { return static_cast<int>(patches_.size()); }
-    const std::vector<Patch>& patches() const { return patches_; }
-    std::vector<Patch>* mutable_patches() { return &patches_; }
-    void clear_patches() { patches_.clear(); }
-    Patch* add_patches() {
-      patches_.emplace_back();
-      return &patches_.back();
-    }
-
-    bool has_more_patches() const { return has_more_patches_; }
-    void set_has_more_patches(bool value) { has_more_patches_ = value; }
-
-   private:
-    uint32_t target_buffer_{};
-    uint32_t writer_id_{};
-    uint32_t chunk_id_{};
-    std::vector<Patch> patches_;
-    bool has_more_patches_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  CommitDataRequest();
-  ~CommitDataRequest();
-  CommitDataRequest(CommitDataRequest&&) noexcept;
-  CommitDataRequest& operator=(CommitDataRequest&&);
-  CommitDataRequest(const CommitDataRequest&);
-  CommitDataRequest& operator=(const CommitDataRequest&);
-  bool operator==(const CommitDataRequest&) const;
-  bool operator!=(const CommitDataRequest& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::CommitDataRequest&);
-  void ToProto(perfetto::protos::CommitDataRequest*) const;
-
-  int chunks_to_move_size() const {
-    return static_cast<int>(chunks_to_move_.size());
-  }
-  const std::vector<ChunksToMove>& chunks_to_move() const {
-    return chunks_to_move_;
-  }
-  std::vector<ChunksToMove>* mutable_chunks_to_move() {
-    return &chunks_to_move_;
-  }
-  void clear_chunks_to_move() { chunks_to_move_.clear(); }
-  ChunksToMove* add_chunks_to_move() {
-    chunks_to_move_.emplace_back();
-    return &chunks_to_move_.back();
-  }
-
-  int chunks_to_patch_size() const {
-    return static_cast<int>(chunks_to_patch_.size());
-  }
-  const std::vector<ChunkToPatch>& chunks_to_patch() const {
-    return chunks_to_patch_;
-  }
-  std::vector<ChunkToPatch>* mutable_chunks_to_patch() {
-    return &chunks_to_patch_;
-  }
-  void clear_chunks_to_patch() { chunks_to_patch_.clear(); }
-  ChunkToPatch* add_chunks_to_patch() {
-    chunks_to_patch_.emplace_back();
-    return &chunks_to_patch_.back();
-  }
-
-  uint64_t flush_request_id() const { return flush_request_id_; }
-  void set_flush_request_id(uint64_t value) { flush_request_id_ = value; }
-
- private:
-  std::vector<ChunksToMove> chunks_to_move_;
-  std::vector<ChunkToPatch> chunks_to_patch_;
-  uint64_t flush_request_id_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/common/commit_data_request.gen.h"
 
 #endif  // INCLUDE_PERFETTO_EXT_TRACING_CORE_COMMIT_DATA_REQUEST_H_
diff --git a/include/perfetto/ext/tracing/core/observable_events.h b/include/perfetto/ext/tracing/core/observable_events.h
index ff1b73b..abf408d 100644
--- a/include/perfetto/ext/tracing/core/observable_events.h
+++ b/include/perfetto/ext/tracing/core/observable_events.h
@@ -14,130 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/observable_events.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_OBSERVABLE_EVENTS_H_
 #define INCLUDE_PERFETTO_EXT_TRACING_CORE_OBSERVABLE_EVENTS_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class ObservableEvents;
-class ObservableEvents_DataSourceInstanceStateChange;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class ObservableEvents;
-
-class PERFETTO_EXPORT ObservableEvents {
- public:
-  class PERFETTO_EXPORT DataSourceInstanceStateChange {
-   public:
-    enum DataSourceInstanceState {
-      DATA_SOURCE_INSTANCE_STATE_STOPPED = 1,
-      DATA_SOURCE_INSTANCE_STATE_STARTED = 2,
-    };
-    DataSourceInstanceStateChange();
-    ~DataSourceInstanceStateChange();
-    DataSourceInstanceStateChange(DataSourceInstanceStateChange&&) noexcept;
-    DataSourceInstanceStateChange& operator=(DataSourceInstanceStateChange&&);
-    DataSourceInstanceStateChange(const DataSourceInstanceStateChange&);
-    DataSourceInstanceStateChange& operator=(
-        const DataSourceInstanceStateChange&);
-    bool operator==(const DataSourceInstanceStateChange&) const;
-    bool operator!=(const DataSourceInstanceStateChange& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::
-                       ObservableEvents_DataSourceInstanceStateChange&);
-    void ToProto(
-        perfetto::protos::ObservableEvents_DataSourceInstanceStateChange*)
-        const;
-
-    const std::string& producer_name() const { return producer_name_; }
-    void set_producer_name(const std::string& value) { producer_name_ = value; }
-
-    const std::string& data_source_name() const { return data_source_name_; }
-    void set_data_source_name(const std::string& value) {
-      data_source_name_ = value;
-    }
-
-    DataSourceInstanceState state() const { return state_; }
-    void set_state(DataSourceInstanceState value) { state_ = value; }
-
-   private:
-    std::string producer_name_{};
-    std::string data_source_name_{};
-    DataSourceInstanceState state_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  ObservableEvents();
-  ~ObservableEvents();
-  ObservableEvents(ObservableEvents&&) noexcept;
-  ObservableEvents& operator=(ObservableEvents&&);
-  ObservableEvents(const ObservableEvents&);
-  ObservableEvents& operator=(const ObservableEvents&);
-  bool operator==(const ObservableEvents&) const;
-  bool operator!=(const ObservableEvents& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::ObservableEvents&);
-  void ToProto(perfetto::protos::ObservableEvents*) const;
-
-  int instance_state_changes_size() const {
-    return static_cast<int>(instance_state_changes_.size());
-  }
-  const std::vector<DataSourceInstanceStateChange>& instance_state_changes()
-      const {
-    return instance_state_changes_;
-  }
-  std::vector<DataSourceInstanceStateChange>* mutable_instance_state_changes() {
-    return &instance_state_changes_;
-  }
-  void clear_instance_state_changes() { instance_state_changes_.clear(); }
-  DataSourceInstanceStateChange* add_instance_state_changes() {
-    instance_state_changes_.emplace_back();
-    return &instance_state_changes_.back();
-  }
-
- private:
-  std::vector<DataSourceInstanceStateChange> instance_state_changes_;
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/common/observable_events.gen.h"
 
 #endif  // INCLUDE_PERFETTO_EXT_TRACING_CORE_OBSERVABLE_EVENTS_H_
diff --git a/include/perfetto/ext/tracing/core/trace_stats.h b/include/perfetto/ext/tracing/core/trace_stats.h
index b29a913..c4f9930 100644
--- a/include/perfetto/ext/tracing/core/trace_stats.h
+++ b/include/perfetto/ext/tracing/core/trace_stats.h
@@ -14,229 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/trace_stats.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
 #define INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class TraceStats;
-class TraceStats_BufferStats;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class TraceStats;
-
-class PERFETTO_EXPORT TraceStats {
- public:
-  class PERFETTO_EXPORT BufferStats {
-   public:
-    BufferStats();
-    ~BufferStats();
-    BufferStats(BufferStats&&) noexcept;
-    BufferStats& operator=(BufferStats&&);
-    BufferStats(const BufferStats&);
-    BufferStats& operator=(const BufferStats&);
-    bool operator==(const BufferStats&) const;
-    bool operator!=(const BufferStats& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceStats_BufferStats&);
-    void ToProto(perfetto::protos::TraceStats_BufferStats*) const;
-
-    uint64_t buffer_size() const { return buffer_size_; }
-    void set_buffer_size(uint64_t value) { buffer_size_ = value; }
-
-    uint64_t bytes_written() const { return bytes_written_; }
-    void set_bytes_written(uint64_t value) { bytes_written_ = value; }
-
-    uint64_t bytes_overwritten() const { return bytes_overwritten_; }
-    void set_bytes_overwritten(uint64_t value) { bytes_overwritten_ = value; }
-
-    uint64_t bytes_read() const { return bytes_read_; }
-    void set_bytes_read(uint64_t value) { bytes_read_ = value; }
-
-    uint64_t padding_bytes_written() const { return padding_bytes_written_; }
-    void set_padding_bytes_written(uint64_t value) {
-      padding_bytes_written_ = value;
-    }
-
-    uint64_t padding_bytes_cleared() const { return padding_bytes_cleared_; }
-    void set_padding_bytes_cleared(uint64_t value) {
-      padding_bytes_cleared_ = value;
-    }
-
-    uint64_t chunks_written() const { return chunks_written_; }
-    void set_chunks_written(uint64_t value) { chunks_written_ = value; }
-
-    uint64_t chunks_rewritten() const { return chunks_rewritten_; }
-    void set_chunks_rewritten(uint64_t value) { chunks_rewritten_ = value; }
-
-    uint64_t chunks_overwritten() const { return chunks_overwritten_; }
-    void set_chunks_overwritten(uint64_t value) { chunks_overwritten_ = value; }
-
-    uint64_t chunks_discarded() const { return chunks_discarded_; }
-    void set_chunks_discarded(uint64_t value) { chunks_discarded_ = value; }
-
-    uint64_t chunks_read() const { return chunks_read_; }
-    void set_chunks_read(uint64_t value) { chunks_read_ = value; }
-
-    uint64_t chunks_committed_out_of_order() const {
-      return chunks_committed_out_of_order_;
-    }
-    void set_chunks_committed_out_of_order(uint64_t value) {
-      chunks_committed_out_of_order_ = value;
-    }
-
-    uint64_t write_wrap_count() const { return write_wrap_count_; }
-    void set_write_wrap_count(uint64_t value) { write_wrap_count_ = value; }
-
-    uint64_t patches_succeeded() const { return patches_succeeded_; }
-    void set_patches_succeeded(uint64_t value) { patches_succeeded_ = value; }
-
-    uint64_t patches_failed() const { return patches_failed_; }
-    void set_patches_failed(uint64_t value) { patches_failed_ = value; }
-
-    uint64_t readaheads_succeeded() const { return readaheads_succeeded_; }
-    void set_readaheads_succeeded(uint64_t value) {
-      readaheads_succeeded_ = value;
-    }
-
-    uint64_t readaheads_failed() const { return readaheads_failed_; }
-    void set_readaheads_failed(uint64_t value) { readaheads_failed_ = value; }
-
-    uint64_t abi_violations() const { return abi_violations_; }
-    void set_abi_violations(uint64_t value) { abi_violations_ = value; }
-
-    uint64_t trace_writer_packet_loss() const {
-      return trace_writer_packet_loss_;
-    }
-    void set_trace_writer_packet_loss(uint64_t value) {
-      trace_writer_packet_loss_ = value;
-    }
-
-   private:
-    uint64_t buffer_size_{};
-    uint64_t bytes_written_{};
-    uint64_t bytes_overwritten_{};
-    uint64_t bytes_read_{};
-    uint64_t padding_bytes_written_{};
-    uint64_t padding_bytes_cleared_{};
-    uint64_t chunks_written_{};
-    uint64_t chunks_rewritten_{};
-    uint64_t chunks_overwritten_{};
-    uint64_t chunks_discarded_{};
-    uint64_t chunks_read_{};
-    uint64_t chunks_committed_out_of_order_{};
-    uint64_t write_wrap_count_{};
-    uint64_t patches_succeeded_{};
-    uint64_t patches_failed_{};
-    uint64_t readaheads_succeeded_{};
-    uint64_t readaheads_failed_{};
-    uint64_t abi_violations_{};
-    uint64_t trace_writer_packet_loss_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  TraceStats();
-  ~TraceStats();
-  TraceStats(TraceStats&&) noexcept;
-  TraceStats& operator=(TraceStats&&);
-  TraceStats(const TraceStats&);
-  TraceStats& operator=(const TraceStats&);
-  bool operator==(const TraceStats&) const;
-  bool operator!=(const TraceStats& other) const { return !(*this == other); }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::TraceStats&);
-  void ToProto(perfetto::protos::TraceStats*) const;
-
-  int buffer_stats_size() const {
-    return static_cast<int>(buffer_stats_.size());
-  }
-  const std::vector<BufferStats>& buffer_stats() const { return buffer_stats_; }
-  std::vector<BufferStats>* mutable_buffer_stats() { return &buffer_stats_; }
-  void clear_buffer_stats() { buffer_stats_.clear(); }
-  BufferStats* add_buffer_stats() {
-    buffer_stats_.emplace_back();
-    return &buffer_stats_.back();
-  }
-
-  uint32_t producers_connected() const { return producers_connected_; }
-  void set_producers_connected(uint32_t value) { producers_connected_ = value; }
-
-  uint64_t producers_seen() const { return producers_seen_; }
-  void set_producers_seen(uint64_t value) { producers_seen_ = value; }
-
-  uint32_t data_sources_registered() const { return data_sources_registered_; }
-  void set_data_sources_registered(uint32_t value) {
-    data_sources_registered_ = value;
-  }
-
-  uint64_t data_sources_seen() const { return data_sources_seen_; }
-  void set_data_sources_seen(uint64_t value) { data_sources_seen_ = value; }
-
-  uint32_t tracing_sessions() const { return tracing_sessions_; }
-  void set_tracing_sessions(uint32_t value) { tracing_sessions_ = value; }
-
-  uint32_t total_buffers() const { return total_buffers_; }
-  void set_total_buffers(uint32_t value) { total_buffers_ = value; }
-
-  uint64_t chunks_discarded() const { return chunks_discarded_; }
-  void set_chunks_discarded(uint64_t value) { chunks_discarded_ = value; }
-
-  uint64_t patches_discarded() const { return patches_discarded_; }
-  void set_patches_discarded(uint64_t value) { patches_discarded_ = value; }
-
-  uint64_t invalid_packets() const { return invalid_packets_; }
-  void set_invalid_packets(uint64_t value) { invalid_packets_ = value; }
-
- private:
-  std::vector<BufferStats> buffer_stats_;
-  uint32_t producers_connected_{};
-  uint64_t producers_seen_{};
-  uint32_t data_sources_registered_{};
-  uint64_t data_sources_seen_{};
-  uint32_t tracing_sessions_{};
-  uint32_t total_buffers_{};
-  uint64_t chunks_discarded_{};
-  uint64_t patches_discarded_{};
-  uint64_t invalid_packets_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/common/trace_stats.gen.h"
 
 #endif  // INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
diff --git a/include/perfetto/tracing/core/BUILD.gn b/include/perfetto/tracing/core/BUILD.gn
index b53e8f0..8cc4829 100644
--- a/include/perfetto/tracing/core/BUILD.gn
+++ b/include/perfetto/tracing/core/BUILD.gn
@@ -13,11 +13,14 @@
 # limitations under the License.
 
 source_set("core") {
+  public_deps = [
+    "../../../../protos/perfetto/common:cpp",
+    "../../../../protos/perfetto/config:cpp",
+  ]
   sources = [
     "chrome_config.h",
     "data_source_config.h",
     "data_source_descriptor.h",
-    "test_config.h",
     "trace_config.h",
     "tracing_service_state.h",
   ]
diff --git a/include/perfetto/tracing/core/chrome_config.h b/include/perfetto/tracing/core/chrome_config.h
index f25bd6a..dff4d87 100644
--- a/include/perfetto/tracing/core/chrome_config.h
+++ b/include/perfetto/tracing/core/chrome_config.h
@@ -14,72 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/chrome/chrome_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_TRACING_CORE_CHROME_CONFIG_H_
 #define INCLUDE_PERFETTO_TRACING_CORE_CHROME_CONFIG_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class ChromeConfig;
-}
-}  // namespace perfetto
-
-namespace perfetto {
-class ChromeConfig;
-
-class PERFETTO_EXPORT ChromeConfig {
- public:
-  ChromeConfig();
-  ~ChromeConfig();
-  ChromeConfig(ChromeConfig&&) noexcept;
-  ChromeConfig& operator=(ChromeConfig&&);
-  ChromeConfig(const ChromeConfig&);
-  ChromeConfig& operator=(const ChromeConfig&);
-  bool operator==(const ChromeConfig&) const;
-  bool operator!=(const ChromeConfig& other) const { return !(*this == other); }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::ChromeConfig&);
-  void ToProto(perfetto::protos::ChromeConfig*) const;
-
-  const std::string& trace_config() const { return trace_config_; }
-  void set_trace_config(const std::string& value) { trace_config_ = value; }
-
-  bool privacy_filtering_enabled() const { return privacy_filtering_enabled_; }
-  void set_privacy_filtering_enabled(bool value) {
-    privacy_filtering_enabled_ = value;
-  }
-
- private:
-  std::string trace_config_{};
-  bool privacy_filtering_enabled_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/config/chrome/chrome_config.gen.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_CORE_CHROME_CONFIG_H_
diff --git a/include/perfetto/tracing/core/data_source_config.h b/include/perfetto/tracing/core/data_source_config.h
index 446ce58..9b7966c 100644
--- a/include/perfetto/tracing/core/data_source_config.h
+++ b/include/perfetto/tracing/core/data_source_config.h
@@ -14,179 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/data_source_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_CONFIG_H_
 #define INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_CONFIG_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class DataSourceConfig;
-class ChromeConfig;
-class TestConfig;
-class TestConfig_DummyFields;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class DataSourceConfig;
-class ChromeConfig;
-class TestConfig;
-
-class PERFETTO_EXPORT DataSourceConfig {
- public:
-  DataSourceConfig();
-  ~DataSourceConfig();
-  DataSourceConfig(DataSourceConfig&&) noexcept;
-  DataSourceConfig& operator=(DataSourceConfig&&);
-  DataSourceConfig(const DataSourceConfig&);
-  DataSourceConfig& operator=(const DataSourceConfig&);
-  bool operator==(const DataSourceConfig&) const;
-  bool operator!=(const DataSourceConfig& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::DataSourceConfig&);
-  void ToProto(perfetto::protos::DataSourceConfig*) const;
-
-  const std::string& name() const { return name_; }
-  void set_name(const std::string& value) { name_ = value; }
-
-  uint32_t target_buffer() const { return target_buffer_; }
-  void set_target_buffer(uint32_t value) { target_buffer_ = value; }
-
-  uint32_t trace_duration_ms() const { return trace_duration_ms_; }
-  void set_trace_duration_ms(uint32_t value) { trace_duration_ms_ = value; }
-
-  uint32_t stop_timeout_ms() const { return stop_timeout_ms_; }
-  void set_stop_timeout_ms(uint32_t value) { stop_timeout_ms_ = value; }
-
-  bool enable_extra_guardrails() const { return enable_extra_guardrails_; }
-  void set_enable_extra_guardrails(bool value) {
-    enable_extra_guardrails_ = value;
-  }
-
-  uint64_t tracing_session_id() const { return tracing_session_id_; }
-  void set_tracing_session_id(uint64_t value) { tracing_session_id_ = value; }
-
-  const std::string& ftrace_config_raw() const { return ftrace_config_; }
-  void set_ftrace_config_raw(const std::string& raw) { ftrace_config_ = raw; }
-
-  const std::string& inode_file_config_raw() const {
-    return inode_file_config_;
-  }
-  void set_inode_file_config_raw(const std::string& raw) {
-    inode_file_config_ = raw;
-  }
-
-  const std::string& process_stats_config_raw() const {
-    return process_stats_config_;
-  }
-  void set_process_stats_config_raw(const std::string& raw) {
-    process_stats_config_ = raw;
-  }
-
-  const std::string& sys_stats_config_raw() const { return sys_stats_config_; }
-  void set_sys_stats_config_raw(const std::string& raw) {
-    sys_stats_config_ = raw;
-  }
-
-  const std::string& heapprofd_config_raw() const { return heapprofd_config_; }
-  void set_heapprofd_config_raw(const std::string& raw) {
-    heapprofd_config_ = raw;
-  }
-
-  const std::string& java_hprof_config_raw() const {
-    return java_hprof_config_;
-  }
-  void set_java_hprof_config_raw(const std::string& raw) {
-    java_hprof_config_ = raw;
-  }
-
-  const std::string& android_power_config_raw() const {
-    return android_power_config_;
-  }
-  void set_android_power_config_raw(const std::string& raw) {
-    android_power_config_ = raw;
-  }
-
-  const std::string& android_log_config_raw() const {
-    return android_log_config_;
-  }
-  void set_android_log_config_raw(const std::string& raw) {
-    android_log_config_ = raw;
-  }
-
-  const std::string& gpu_counter_config_raw() const {
-    return gpu_counter_config_;
-  }
-  void set_gpu_counter_config_raw(const std::string& raw) {
-    gpu_counter_config_ = raw;
-  }
-
-  const std::string& packages_list_config_raw() const {
-    return packages_list_config_;
-  }
-  void set_packages_list_config_raw(const std::string& raw) {
-    packages_list_config_ = raw;
-  }
-
-  const ChromeConfig& chrome_config() const { return *chrome_config_; }
-  ChromeConfig* mutable_chrome_config() { return chrome_config_.get(); }
-
-  const std::string& legacy_config() const { return legacy_config_; }
-  void set_legacy_config(const std::string& value) { legacy_config_ = value; }
-
-  const TestConfig& for_testing() const { return *for_testing_; }
-  TestConfig* mutable_for_testing() { return for_testing_.get(); }
-
- private:
-  std::string name_{};
-  uint32_t target_buffer_{};
-  uint32_t trace_duration_ms_{};
-  uint32_t stop_timeout_ms_{};
-  bool enable_extra_guardrails_{};
-  uint64_t tracing_session_id_{};
-  std::string ftrace_config_;         // [lazy=true]
-  std::string inode_file_config_;     // [lazy=true]
-  std::string process_stats_config_;  // [lazy=true]
-  std::string sys_stats_config_;      // [lazy=true]
-  std::string heapprofd_config_;      // [lazy=true]
-  std::string java_hprof_config_;     // [lazy=true]
-  std::string android_power_config_;  // [lazy=true]
-  std::string android_log_config_;    // [lazy=true]
-  std::string gpu_counter_config_;    // [lazy=true]
-  std::string packages_list_config_;  // [lazy=true]
-  ::perfetto::base::CopyablePtr<ChromeConfig> chrome_config_;
-  std::string legacy_config_{};
-  ::perfetto::base::CopyablePtr<TestConfig> for_testing_;
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/config/data_source_config.gen.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_CONFIG_H_
diff --git a/include/perfetto/tracing/core/data_source_descriptor.h b/include/perfetto/tracing/core/data_source_descriptor.h
index d55b878..75818bf 100644
--- a/include/perfetto/tracing/core/data_source_descriptor.h
+++ b/include/perfetto/tracing/core/data_source_descriptor.h
@@ -14,100 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/data_source_descriptor.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_DESCRIPTOR_H_
 #define INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_DESCRIPTOR_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class DataSourceDescriptor;
-}
-}  // namespace perfetto
-
-namespace perfetto {
-class DataSourceDescriptor;
-
-class PERFETTO_EXPORT DataSourceDescriptor {
- public:
-  DataSourceDescriptor();
-  ~DataSourceDescriptor();
-  DataSourceDescriptor(DataSourceDescriptor&&) noexcept;
-  DataSourceDescriptor& operator=(DataSourceDescriptor&&);
-  DataSourceDescriptor(const DataSourceDescriptor&);
-  DataSourceDescriptor& operator=(const DataSourceDescriptor&);
-  bool operator==(const DataSourceDescriptor&) const;
-  bool operator!=(const DataSourceDescriptor& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::DataSourceDescriptor&);
-  void ToProto(perfetto::protos::DataSourceDescriptor*) const;
-
-  const std::string& name() const { return name_; }
-  void set_name(const std::string& value) { name_ = value; }
-
-  bool will_notify_on_stop() const { return will_notify_on_stop_; }
-  void set_will_notify_on_stop(bool value) { will_notify_on_stop_ = value; }
-
-  bool will_notify_on_start() const { return will_notify_on_start_; }
-  void set_will_notify_on_start(bool value) { will_notify_on_start_ = value; }
-
-  bool handles_incremental_state_clear() const {
-    return handles_incremental_state_clear_;
-  }
-  void set_handles_incremental_state_clear(bool value) {
-    handles_incremental_state_clear_ = value;
-  }
-
-  const std::string& gpu_counter_descriptor_raw() const {
-    return gpu_counter_descriptor_;
-  }
-  void set_gpu_counter_descriptor_raw(const std::string& raw) {
-    gpu_counter_descriptor_ = raw;
-  }
-
-  const std::string& track_event_descriptor_raw() const {
-    return track_event_descriptor_;
-  }
-  void set_track_event_descriptor_raw(const std::string& raw) {
-    track_event_descriptor_ = raw;
-  }
-
- private:
-  std::string name_{};
-  bool will_notify_on_stop_{};
-  bool will_notify_on_start_{};
-  bool handles_incremental_state_clear_{};
-  std::string gpu_counter_descriptor_;  // [lazy=true]
-  std::string track_event_descriptor_;  // [lazy=true]
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/common/data_source_descriptor.gen.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_CORE_DATA_SOURCE_DESCRIPTOR_H_
diff --git a/include/perfetto/tracing/core/test_config.h b/include/perfetto/tracing/core/test_config.h
deleted file mode 100644
index 699b119..0000000
--- a/include/perfetto/tracing/core/test_config.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/test_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#ifndef INCLUDE_PERFETTO_TRACING_CORE_TEST_CONFIG_H_
-#define INCLUDE_PERFETTO_TRACING_CORE_TEST_CONFIG_H_
-
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class TestConfig;
-class TestConfig_DummyFields;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class TestConfig;
-
-class PERFETTO_EXPORT TestConfig {
- public:
-  class PERFETTO_EXPORT DummyFields {
-   public:
-    DummyFields();
-    ~DummyFields();
-    DummyFields(DummyFields&&) noexcept;
-    DummyFields& operator=(DummyFields&&);
-    DummyFields(const DummyFields&);
-    DummyFields& operator=(const DummyFields&);
-    bool operator==(const DummyFields&) const;
-    bool operator!=(const DummyFields& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TestConfig_DummyFields&);
-    void ToProto(perfetto::protos::TestConfig_DummyFields*) const;
-
-    uint32_t field_uint32() const { return field_uint32_; }
-    void set_field_uint32(uint32_t value) { field_uint32_ = value; }
-
-    int32_t field_int32() const { return field_int32_; }
-    void set_field_int32(int32_t value) { field_int32_ = value; }
-
-    uint64_t field_uint64() const { return field_uint64_; }
-    void set_field_uint64(uint64_t value) { field_uint64_ = value; }
-
-    int64_t field_int64() const { return field_int64_; }
-    void set_field_int64(int64_t value) { field_int64_ = value; }
-
-    uint64_t field_fixed64() const { return field_fixed64_; }
-    void set_field_fixed64(uint64_t value) { field_fixed64_ = value; }
-
-    int64_t field_sfixed64() const { return field_sfixed64_; }
-    void set_field_sfixed64(int64_t value) { field_sfixed64_ = value; }
-
-    uint32_t field_fixed32() const { return field_fixed32_; }
-    void set_field_fixed32(uint32_t value) { field_fixed32_ = value; }
-
-    int32_t field_sfixed32() const { return field_sfixed32_; }
-    void set_field_sfixed32(int32_t value) { field_sfixed32_ = value; }
-
-    double field_double() const { return field_double_; }
-    void set_field_double(double value) { field_double_ = value; }
-
-    float field_float() const { return field_float_; }
-    void set_field_float(float value) { field_float_ = value; }
-
-    int64_t field_sint64() const { return field_sint64_; }
-    void set_field_sint64(int64_t value) { field_sint64_ = value; }
-
-    int32_t field_sint32() const { return field_sint32_; }
-    void set_field_sint32(int32_t value) { field_sint32_ = value; }
-
-    const std::string& field_string() const { return field_string_; }
-    void set_field_string(const std::string& value) { field_string_ = value; }
-
-    const std::string& field_bytes() const { return field_bytes_; }
-    void set_field_bytes(const std::string& value) { field_bytes_ = value; }
-    void set_field_bytes(const void* p, size_t s) {
-      field_bytes_.assign(reinterpret_cast<const char*>(p), s);
-    }
-
-   private:
-    uint32_t field_uint32_{};
-    int32_t field_int32_{};
-    uint64_t field_uint64_{};
-    int64_t field_int64_{};
-    uint64_t field_fixed64_{};
-    int64_t field_sfixed64_{};
-    uint32_t field_fixed32_{};
-    int32_t field_sfixed32_{};
-    double field_double_{};
-    float field_float_{};
-    int64_t field_sint64_{};
-    int32_t field_sint32_{};
-    std::string field_string_{};
-    std::string field_bytes_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  TestConfig();
-  ~TestConfig();
-  TestConfig(TestConfig&&) noexcept;
-  TestConfig& operator=(TestConfig&&);
-  TestConfig(const TestConfig&);
-  TestConfig& operator=(const TestConfig&);
-  bool operator==(const TestConfig&) const;
-  bool operator!=(const TestConfig& other) const { return !(*this == other); }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::TestConfig&);
-  void ToProto(perfetto::protos::TestConfig*) const;
-
-  uint32_t message_count() const { return message_count_; }
-  void set_message_count(uint32_t value) { message_count_ = value; }
-
-  uint32_t max_messages_per_second() const { return max_messages_per_second_; }
-  void set_max_messages_per_second(uint32_t value) {
-    max_messages_per_second_ = value;
-  }
-
-  uint32_t seed() const { return seed_; }
-  void set_seed(uint32_t value) { seed_ = value; }
-
-  uint32_t message_size() const { return message_size_; }
-  void set_message_size(uint32_t value) { message_size_ = value; }
-
-  bool send_batch_on_register() const { return send_batch_on_register_; }
-  void set_send_batch_on_register(bool value) {
-    send_batch_on_register_ = value;
-  }
-
-  const DummyFields& dummy_fields() const { return *dummy_fields_; }
-  DummyFields* mutable_dummy_fields() { return dummy_fields_.get(); }
-
- private:
-  uint32_t message_count_{};
-  uint32_t max_messages_per_second_{};
-  uint32_t seed_{};
-  uint32_t message_size_{};
-  bool send_batch_on_register_{};
-  ::perfetto::base::CopyablePtr<DummyFields> dummy_fields_;
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
-
-#endif  // INCLUDE_PERFETTO_TRACING_CORE_TEST_CONFIG_H_
diff --git a/include/perfetto/tracing/core/trace_config.h b/include/perfetto/tracing/core/trace_config.h
index e89f105..d2ec6e1 100644
--- a/include/perfetto/tracing/core/trace_config.h
+++ b/include/perfetto/tracing/core/trace_config.h
@@ -14,678 +14,14 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/trace_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
 #ifndef INCLUDE_PERFETTO_TRACING_CORE_TRACE_CONFIG_H_
 #define INCLUDE_PERFETTO_TRACING_CORE_TRACE_CONFIG_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class TraceConfig;
-class TraceConfig_BufferConfig;
-class TraceConfig_DataSource;
-class DataSourceConfig;
-class ChromeConfig;
-class TestConfig;
-class TestConfig_DummyFields;
-class TraceConfig_BuiltinDataSource;
-class TraceConfig_ProducerConfig;
-class TraceConfig_StatsdMetadata;
-class TraceConfig_GuardrailOverrides;
-class TraceConfig_TriggerConfig;
-class TraceConfig_TriggerConfig_Trigger;
-class TraceConfig_IncrementalStateConfig;
-class TraceConfig_IncidentReportConfig;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class TraceConfig;
-class DataSourceConfig;
-class ChromeConfig;
-class TestConfig;
-
-class PERFETTO_EXPORT TraceConfig {
- public:
-  class PERFETTO_EXPORT BufferConfig {
-   public:
-    enum FillPolicy {
-      UNSPECIFIED = 0,
-      RING_BUFFER = 1,
-      DISCARD = 2,
-    };
-    BufferConfig();
-    ~BufferConfig();
-    BufferConfig(BufferConfig&&) noexcept;
-    BufferConfig& operator=(BufferConfig&&);
-    BufferConfig(const BufferConfig&);
-    BufferConfig& operator=(const BufferConfig&);
-    bool operator==(const BufferConfig&) const;
-    bool operator!=(const BufferConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_BufferConfig&);
-    void ToProto(perfetto::protos::TraceConfig_BufferConfig*) const;
-
-    uint32_t size_kb() const { return size_kb_; }
-    void set_size_kb(uint32_t value) { size_kb_ = value; }
-
-    FillPolicy fill_policy() const { return fill_policy_; }
-    void set_fill_policy(FillPolicy value) { fill_policy_ = value; }
-
-   private:
-    uint32_t size_kb_{};
-    FillPolicy fill_policy_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT DataSource {
-   public:
-    DataSource();
-    ~DataSource();
-    DataSource(DataSource&&) noexcept;
-    DataSource& operator=(DataSource&&);
-    DataSource(const DataSource&);
-    DataSource& operator=(const DataSource&);
-    bool operator==(const DataSource&) const;
-    bool operator!=(const DataSource& other) const { return !(*this == other); }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_DataSource&);
-    void ToProto(perfetto::protos::TraceConfig_DataSource*) const;
-
-    const DataSourceConfig& config() const { return *config_; }
-    DataSourceConfig* mutable_config() { return config_.get(); }
-
-    int producer_name_filter_size() const {
-      return static_cast<int>(producer_name_filter_.size());
-    }
-    const std::vector<std::string>& producer_name_filter() const {
-      return producer_name_filter_;
-    }
-    std::vector<std::string>* mutable_producer_name_filter() {
-      return &producer_name_filter_;
-    }
-    void clear_producer_name_filter() { producer_name_filter_.clear(); }
-    std::string* add_producer_name_filter() {
-      producer_name_filter_.emplace_back();
-      return &producer_name_filter_.back();
-    }
-
-   private:
-    ::perfetto::base::CopyablePtr<DataSourceConfig> config_;
-    std::vector<std::string> producer_name_filter_;
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT BuiltinDataSource {
-   public:
-    BuiltinDataSource();
-    ~BuiltinDataSource();
-    BuiltinDataSource(BuiltinDataSource&&) noexcept;
-    BuiltinDataSource& operator=(BuiltinDataSource&&);
-    BuiltinDataSource(const BuiltinDataSource&);
-    BuiltinDataSource& operator=(const BuiltinDataSource&);
-    bool operator==(const BuiltinDataSource&) const;
-    bool operator!=(const BuiltinDataSource& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_BuiltinDataSource&);
-    void ToProto(perfetto::protos::TraceConfig_BuiltinDataSource*) const;
-
-    bool disable_clock_snapshotting() const {
-      return disable_clock_snapshotting_;
-    }
-    void set_disable_clock_snapshotting(bool value) {
-      disable_clock_snapshotting_ = value;
-    }
-
-    bool disable_trace_config() const { return disable_trace_config_; }
-    void set_disable_trace_config(bool value) { disable_trace_config_ = value; }
-
-    bool disable_system_info() const { return disable_system_info_; }
-    void set_disable_system_info(bool value) { disable_system_info_ = value; }
-
-   private:
-    bool disable_clock_snapshotting_{};
-    bool disable_trace_config_{};
-    bool disable_system_info_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  enum LockdownModeOperation {
-    LOCKDOWN_UNCHANGED = 0,
-    LOCKDOWN_CLEAR = 1,
-    LOCKDOWN_SET = 2,
-  };
-
-  class PERFETTO_EXPORT ProducerConfig {
-   public:
-    ProducerConfig();
-    ~ProducerConfig();
-    ProducerConfig(ProducerConfig&&) noexcept;
-    ProducerConfig& operator=(ProducerConfig&&);
-    ProducerConfig(const ProducerConfig&);
-    ProducerConfig& operator=(const ProducerConfig&);
-    bool operator==(const ProducerConfig&) const;
-    bool operator!=(const ProducerConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_ProducerConfig&);
-    void ToProto(perfetto::protos::TraceConfig_ProducerConfig*) const;
-
-    const std::string& producer_name() const { return producer_name_; }
-    void set_producer_name(const std::string& value) { producer_name_ = value; }
-
-    uint32_t shm_size_kb() const { return shm_size_kb_; }
-    void set_shm_size_kb(uint32_t value) { shm_size_kb_ = value; }
-
-    uint32_t page_size_kb() const { return page_size_kb_; }
-    void set_page_size_kb(uint32_t value) { page_size_kb_ = value; }
-
-   private:
-    std::string producer_name_{};
-    uint32_t shm_size_kb_{};
-    uint32_t page_size_kb_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT StatsdMetadata {
-   public:
-    StatsdMetadata();
-    ~StatsdMetadata();
-    StatsdMetadata(StatsdMetadata&&) noexcept;
-    StatsdMetadata& operator=(StatsdMetadata&&);
-    StatsdMetadata(const StatsdMetadata&);
-    StatsdMetadata& operator=(const StatsdMetadata&);
-    bool operator==(const StatsdMetadata&) const;
-    bool operator!=(const StatsdMetadata& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_StatsdMetadata&);
-    void ToProto(perfetto::protos::TraceConfig_StatsdMetadata*) const;
-
-    int64_t triggering_alert_id() const { return triggering_alert_id_; }
-    void set_triggering_alert_id(int64_t value) {
-      triggering_alert_id_ = value;
-    }
-
-    int32_t triggering_config_uid() const { return triggering_config_uid_; }
-    void set_triggering_config_uid(int32_t value) {
-      triggering_config_uid_ = value;
-    }
-
-    int64_t triggering_config_id() const { return triggering_config_id_; }
-    void set_triggering_config_id(int64_t value) {
-      triggering_config_id_ = value;
-    }
-
-    int64_t triggering_subscription_id() const {
-      return triggering_subscription_id_;
-    }
-    void set_triggering_subscription_id(int64_t value) {
-      triggering_subscription_id_ = value;
-    }
-
-   private:
-    int64_t triggering_alert_id_{};
-    int32_t triggering_config_uid_{};
-    int64_t triggering_config_id_{};
-    int64_t triggering_subscription_id_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT GuardrailOverrides {
-   public:
-    GuardrailOverrides();
-    ~GuardrailOverrides();
-    GuardrailOverrides(GuardrailOverrides&&) noexcept;
-    GuardrailOverrides& operator=(GuardrailOverrides&&);
-    GuardrailOverrides(const GuardrailOverrides&);
-    GuardrailOverrides& operator=(const GuardrailOverrides&);
-    bool operator==(const GuardrailOverrides&) const;
-    bool operator!=(const GuardrailOverrides& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_GuardrailOverrides&);
-    void ToProto(perfetto::protos::TraceConfig_GuardrailOverrides*) const;
-
-    uint64_t max_upload_per_day_bytes() const {
-      return max_upload_per_day_bytes_;
-    }
-    void set_max_upload_per_day_bytes(uint64_t value) {
-      max_upload_per_day_bytes_ = value;
-    }
-
-   private:
-    uint64_t max_upload_per_day_bytes_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT TriggerConfig {
-   public:
-    enum TriggerMode {
-      UNSPECIFIED = 0,
-      START_TRACING = 1,
-      STOP_TRACING = 2,
-    };
-
-    class PERFETTO_EXPORT Trigger {
-     public:
-      Trigger();
-      ~Trigger();
-      Trigger(Trigger&&) noexcept;
-      Trigger& operator=(Trigger&&);
-      Trigger(const Trigger&);
-      Trigger& operator=(const Trigger&);
-      bool operator==(const Trigger&) const;
-      bool operator!=(const Trigger& other) const { return !(*this == other); }
-
-      // Raw proto decoding.
-      void ParseRawProto(const std::string&);
-      // Conversion methods from/to the corresponding protobuf types.
-      void FromProto(
-          const perfetto::protos::TraceConfig_TriggerConfig_Trigger&);
-      void ToProto(perfetto::protos::TraceConfig_TriggerConfig_Trigger*) const;
-
-      const std::string& name() const { return name_; }
-      void set_name(const std::string& value) { name_ = value; }
-
-      const std::string& producer_name_regex() const {
-        return producer_name_regex_;
-      }
-      void set_producer_name_regex(const std::string& value) {
-        producer_name_regex_ = value;
-      }
-
-      uint32_t stop_delay_ms() const { return stop_delay_ms_; }
-      void set_stop_delay_ms(uint32_t value) { stop_delay_ms_ = value; }
-
-     private:
-      std::string name_{};
-      std::string producer_name_regex_{};
-      uint32_t stop_delay_ms_{};
-
-      // Allows to preserve unknown protobuf fields for compatibility
-      // with future versions of .proto files.
-      std::string unknown_fields_;
-    };
-
-    TriggerConfig();
-    ~TriggerConfig();
-    TriggerConfig(TriggerConfig&&) noexcept;
-    TriggerConfig& operator=(TriggerConfig&&);
-    TriggerConfig(const TriggerConfig&);
-    TriggerConfig& operator=(const TriggerConfig&);
-    bool operator==(const TriggerConfig&) const;
-    bool operator!=(const TriggerConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_TriggerConfig&);
-    void ToProto(perfetto::protos::TraceConfig_TriggerConfig*) const;
-
-    TriggerMode trigger_mode() const { return trigger_mode_; }
-    void set_trigger_mode(TriggerMode value) { trigger_mode_ = value; }
-
-    int triggers_size() const { return static_cast<int>(triggers_.size()); }
-    const std::vector<Trigger>& triggers() const { return triggers_; }
-    std::vector<Trigger>* mutable_triggers() { return &triggers_; }
-    void clear_triggers() { triggers_.clear(); }
-    Trigger* add_triggers() {
-      triggers_.emplace_back();
-      return &triggers_.back();
-    }
-
-    uint32_t trigger_timeout_ms() const { return trigger_timeout_ms_; }
-    void set_trigger_timeout_ms(uint32_t value) { trigger_timeout_ms_ = value; }
-
-   private:
-    TriggerMode trigger_mode_{};
-    std::vector<Trigger> triggers_;
-    uint32_t trigger_timeout_ms_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT IncrementalStateConfig {
-   public:
-    IncrementalStateConfig();
-    ~IncrementalStateConfig();
-    IncrementalStateConfig(IncrementalStateConfig&&) noexcept;
-    IncrementalStateConfig& operator=(IncrementalStateConfig&&);
-    IncrementalStateConfig(const IncrementalStateConfig&);
-    IncrementalStateConfig& operator=(const IncrementalStateConfig&);
-    bool operator==(const IncrementalStateConfig&) const;
-    bool operator!=(const IncrementalStateConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_IncrementalStateConfig&);
-    void ToProto(perfetto::protos::TraceConfig_IncrementalStateConfig*) const;
-
-    uint32_t clear_period_ms() const { return clear_period_ms_; }
-    void set_clear_period_ms(uint32_t value) { clear_period_ms_ = value; }
-
-   private:
-    uint32_t clear_period_ms_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  enum CompressionType {
-    COMPRESSION_TYPE_UNSPECIFIED = 0,
-    COMPRESSION_TYPE_DEFLATE = 1,
-  };
-
-  class PERFETTO_EXPORT IncidentReportConfig {
-   public:
-    IncidentReportConfig();
-    ~IncidentReportConfig();
-    IncidentReportConfig(IncidentReportConfig&&) noexcept;
-    IncidentReportConfig& operator=(IncidentReportConfig&&);
-    IncidentReportConfig(const IncidentReportConfig&);
-    IncidentReportConfig& operator=(const IncidentReportConfig&);
-    bool operator==(const IncidentReportConfig&) const;
-    bool operator!=(const IncidentReportConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TraceConfig_IncidentReportConfig&);
-    void ToProto(perfetto::protos::TraceConfig_IncidentReportConfig*) const;
-
-    const std::string& destination_package() const {
-      return destination_package_;
-    }
-    void set_destination_package(const std::string& value) {
-      destination_package_ = value;
-    }
-
-    const std::string& destination_class() const { return destination_class_; }
-    void set_destination_class(const std::string& value) {
-      destination_class_ = value;
-    }
-
-    int32_t privacy_level() const { return privacy_level_; }
-    void set_privacy_level(int32_t value) { privacy_level_ = value; }
-
-    bool skip_dropbox() const { return skip_dropbox_; }
-    void set_skip_dropbox(bool value) { skip_dropbox_ = value; }
-
-   private:
-    std::string destination_package_{};
-    std::string destination_class_{};
-    int32_t privacy_level_{};
-    bool skip_dropbox_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  TraceConfig();
-  ~TraceConfig();
-  TraceConfig(TraceConfig&&) noexcept;
-  TraceConfig& operator=(TraceConfig&&);
-  TraceConfig(const TraceConfig&);
-  TraceConfig& operator=(const TraceConfig&);
-  bool operator==(const TraceConfig&) const;
-  bool operator!=(const TraceConfig& other) const { return !(*this == other); }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::TraceConfig&);
-  void ToProto(perfetto::protos::TraceConfig*) const;
-
-  int buffers_size() const { return static_cast<int>(buffers_.size()); }
-  const std::vector<BufferConfig>& buffers() const { return buffers_; }
-  std::vector<BufferConfig>* mutable_buffers() { return &buffers_; }
-  void clear_buffers() { buffers_.clear(); }
-  BufferConfig* add_buffers() {
-    buffers_.emplace_back();
-    return &buffers_.back();
-  }
-
-  int data_sources_size() const {
-    return static_cast<int>(data_sources_.size());
-  }
-  const std::vector<DataSource>& data_sources() const { return data_sources_; }
-  std::vector<DataSource>* mutable_data_sources() { return &data_sources_; }
-  void clear_data_sources() { data_sources_.clear(); }
-  DataSource* add_data_sources() {
-    data_sources_.emplace_back();
-    return &data_sources_.back();
-  }
-
-  const BuiltinDataSource& builtin_data_sources() const {
-    return *builtin_data_sources_;
-  }
-  BuiltinDataSource* mutable_builtin_data_sources() {
-    return builtin_data_sources_.get();
-  }
-
-  uint32_t duration_ms() const { return duration_ms_; }
-  void set_duration_ms(uint32_t value) { duration_ms_ = value; }
-
-  bool enable_extra_guardrails() const { return enable_extra_guardrails_; }
-  void set_enable_extra_guardrails(bool value) {
-    enable_extra_guardrails_ = value;
-  }
-
-  LockdownModeOperation lockdown_mode() const { return lockdown_mode_; }
-  void set_lockdown_mode(LockdownModeOperation value) {
-    lockdown_mode_ = value;
-  }
-
-  int producers_size() const { return static_cast<int>(producers_.size()); }
-  const std::vector<ProducerConfig>& producers() const { return producers_; }
-  std::vector<ProducerConfig>* mutable_producers() { return &producers_; }
-  void clear_producers() { producers_.clear(); }
-  ProducerConfig* add_producers() {
-    producers_.emplace_back();
-    return &producers_.back();
-  }
-
-  const StatsdMetadata& statsd_metadata() const { return *statsd_metadata_; }
-  StatsdMetadata* mutable_statsd_metadata() { return statsd_metadata_.get(); }
-
-  bool write_into_file() const { return write_into_file_; }
-  void set_write_into_file(bool value) { write_into_file_ = value; }
-
-  uint32_t file_write_period_ms() const { return file_write_period_ms_; }
-  void set_file_write_period_ms(uint32_t value) {
-    file_write_period_ms_ = value;
-  }
-
-  uint64_t max_file_size_bytes() const { return max_file_size_bytes_; }
-  void set_max_file_size_bytes(uint64_t value) { max_file_size_bytes_ = value; }
-
-  const GuardrailOverrides& guardrail_overrides() const {
-    return *guardrail_overrides_;
-  }
-  GuardrailOverrides* mutable_guardrail_overrides() {
-    return guardrail_overrides_.get();
-  }
-
-  bool deferred_start() const { return deferred_start_; }
-  void set_deferred_start(bool value) { deferred_start_ = value; }
-
-  uint32_t flush_period_ms() const { return flush_period_ms_; }
-  void set_flush_period_ms(uint32_t value) { flush_period_ms_ = value; }
-
-  uint32_t flush_timeout_ms() const { return flush_timeout_ms_; }
-  void set_flush_timeout_ms(uint32_t value) { flush_timeout_ms_ = value; }
-
-  uint32_t data_source_stop_timeout_ms() const {
-    return data_source_stop_timeout_ms_;
-  }
-  void set_data_source_stop_timeout_ms(uint32_t value) {
-    data_source_stop_timeout_ms_ = value;
-  }
-
-  bool notify_traceur() const { return notify_traceur_; }
-  void set_notify_traceur(bool value) { notify_traceur_ = value; }
-
-  const TriggerConfig& trigger_config() const { return *trigger_config_; }
-  TriggerConfig* mutable_trigger_config() { return trigger_config_.get(); }
-
-  int activate_triggers_size() const {
-    return static_cast<int>(activate_triggers_.size());
-  }
-  const std::vector<std::string>& activate_triggers() const {
-    return activate_triggers_;
-  }
-  std::vector<std::string>* mutable_activate_triggers() {
-    return &activate_triggers_;
-  }
-  void clear_activate_triggers() { activate_triggers_.clear(); }
-  std::string* add_activate_triggers() {
-    activate_triggers_.emplace_back();
-    return &activate_triggers_.back();
-  }
-
-  const IncrementalStateConfig& incremental_state_config() const {
-    return *incremental_state_config_;
-  }
-  IncrementalStateConfig* mutable_incremental_state_config() {
-    return incremental_state_config_.get();
-  }
-
-  bool allow_user_build_tracing() const { return allow_user_build_tracing_; }
-  void set_allow_user_build_tracing(bool value) {
-    allow_user_build_tracing_ = value;
-  }
-
-  const std::string& unique_session_name() const {
-    return unique_session_name_;
-  }
-  void set_unique_session_name(const std::string& value) {
-    unique_session_name_ = value;
-  }
-
-  CompressionType compression_type() const { return compression_type_; }
-  void set_compression_type(CompressionType value) {
-    compression_type_ = value;
-  }
-
-  const IncidentReportConfig& incident_report_config() const {
-    return *incident_report_config_;
-  }
-  IncidentReportConfig* mutable_incident_report_config() {
-    return incident_report_config_.get();
-  }
-
-  const std::string& trace_uuid() const { return trace_uuid_; }
-  void set_trace_uuid(const std::string& value) { trace_uuid_ = value; }
-  void set_trace_uuid(const void* p, size_t s) {
-    trace_uuid_.assign(reinterpret_cast<const char*>(p), s);
-  }
-
- private:
-  std::vector<BufferConfig> buffers_;
-  std::vector<DataSource> data_sources_;
-  ::perfetto::base::CopyablePtr<BuiltinDataSource> builtin_data_sources_;
-  uint32_t duration_ms_{};
-  bool enable_extra_guardrails_{};
-  LockdownModeOperation lockdown_mode_{};
-  std::vector<ProducerConfig> producers_;
-  ::perfetto::base::CopyablePtr<StatsdMetadata> statsd_metadata_;
-  bool write_into_file_{};
-  uint32_t file_write_period_ms_{};
-  uint64_t max_file_size_bytes_{};
-  ::perfetto::base::CopyablePtr<GuardrailOverrides> guardrail_overrides_;
-  bool deferred_start_{};
-  uint32_t flush_period_ms_{};
-  uint32_t flush_timeout_ms_{};
-  uint32_t data_source_stop_timeout_ms_{};
-  bool notify_traceur_{};
-  ::perfetto::base::CopyablePtr<TriggerConfig> trigger_config_;
-  std::vector<std::string> activate_triggers_;
-  ::perfetto::base::CopyablePtr<IncrementalStateConfig>
-      incremental_state_config_;
-  bool allow_user_build_tracing_{};
-  std::string unique_session_name_{};
-  CompressionType compression_type_{};
-  ::perfetto::base::CopyablePtr<IncidentReportConfig> incident_report_config_;
-  std::string trace_uuid_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/config/trace_config.gen.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_CORE_TRACE_CONFIG_H_
diff --git a/include/perfetto/tracing/core/tracing_service_state.h b/include/perfetto/tracing/core/tracing_service_state.h
index ab9d178..c9d74cd 100644
--- a/include/perfetto/tracing/core/tracing_service_state.h
+++ b/include/perfetto/tracing/core/tracing_service_state.h
@@ -14,172 +14,15 @@
  * limitations under the License.
  */
 
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/tracing_service_state.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
 
 #ifndef INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
 #define INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
 
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class TracingServiceState;
-class TracingServiceState_Producer;
-class TracingServiceState_DataSource;
-class DataSourceDescriptor;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class TracingServiceState;
-class DataSourceDescriptor;
-
-class PERFETTO_EXPORT TracingServiceState {
- public:
-  class PERFETTO_EXPORT Producer {
-   public:
-    Producer();
-    ~Producer();
-    Producer(Producer&&) noexcept;
-    Producer& operator=(Producer&&);
-    Producer(const Producer&);
-    Producer& operator=(const Producer&);
-    bool operator==(const Producer&) const;
-    bool operator!=(const Producer& other) const { return !(*this == other); }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TracingServiceState_Producer&);
-    void ToProto(perfetto::protos::TracingServiceState_Producer*) const;
-
-    int32_t id() const { return id_; }
-    void set_id(int32_t value) { id_ = value; }
-
-    const std::string& name() const { return name_; }
-    void set_name(const std::string& value) { name_ = value; }
-
-    int32_t uid() const { return uid_; }
-    void set_uid(int32_t value) { uid_ = value; }
-
-   private:
-    int32_t id_{};
-    std::string name_{};
-    int32_t uid_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  class PERFETTO_EXPORT DataSource {
-   public:
-    DataSource();
-    ~DataSource();
-    DataSource(DataSource&&) noexcept;
-    DataSource& operator=(DataSource&&);
-    DataSource(const DataSource&);
-    DataSource& operator=(const DataSource&);
-    bool operator==(const DataSource&) const;
-    bool operator!=(const DataSource& other) const { return !(*this == other); }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::TracingServiceState_DataSource&);
-    void ToProto(perfetto::protos::TracingServiceState_DataSource*) const;
-
-    const DataSourceDescriptor& ds_descriptor() const {
-      return *ds_descriptor_;
-    }
-    DataSourceDescriptor* mutable_ds_descriptor() {
-      return ds_descriptor_.get();
-    }
-
-    int32_t producer_id() const { return producer_id_; }
-    void set_producer_id(int32_t value) { producer_id_ = value; }
-
-   private:
-    ::perfetto::base::CopyablePtr<DataSourceDescriptor> ds_descriptor_;
-    int32_t producer_id_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  TracingServiceState();
-  ~TracingServiceState();
-  TracingServiceState(TracingServiceState&&) noexcept;
-  TracingServiceState& operator=(TracingServiceState&&);
-  TracingServiceState(const TracingServiceState&);
-  TracingServiceState& operator=(const TracingServiceState&);
-  bool operator==(const TracingServiceState&) const;
-  bool operator!=(const TracingServiceState& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::TracingServiceState&);
-  void ToProto(perfetto::protos::TracingServiceState*) const;
-
-  int producers_size() const { return static_cast<int>(producers_.size()); }
-  const std::vector<Producer>& producers() const { return producers_; }
-  std::vector<Producer>* mutable_producers() { return &producers_; }
-  void clear_producers() { producers_.clear(); }
-  Producer* add_producers() {
-    producers_.emplace_back();
-    return &producers_.back();
-  }
-
-  int data_sources_size() const {
-    return static_cast<int>(data_sources_.size());
-  }
-  const std::vector<DataSource>& data_sources() const { return data_sources_; }
-  std::vector<DataSource>* mutable_data_sources() { return &data_sources_; }
-  void clear_data_sources() { data_sources_.clear(); }
-  DataSource* add_data_sources() {
-    data_sources_.emplace_back();
-    return &data_sources_.back();
-  }
-
-  int32_t num_sessions() const { return num_sessions_; }
-  void set_num_sessions(int32_t value) { num_sessions_ = value; }
-
-  int32_t num_sessions_started() const { return num_sessions_started_; }
-  void set_num_sessions_started(int32_t value) {
-    num_sessions_started_ = value;
-  }
-
- private:
-  std::vector<Producer> producers_;
-  std::vector<DataSource> data_sources_;
-  int32_t num_sessions_{};
-  int32_t num_sessions_started_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
+// This header exists only for legacy code that used to refer to the
+// checked-in auto-generated code, before it was moved to be a build-time gen
+// rule. DO NOT add any new includes to this header, instead directly include
+// the one below.
+// TODO(primiano): cleanup call-sites and remove this header.
+#include "protos/perfetto/common/tracing_service_state.gen.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
diff --git a/protos/perfetto/common/data_source_descriptor.proto b/protos/perfetto/common/data_source_descriptor.proto
index a2d3c07..63a5114 100644
--- a/protos/perfetto/common/data_source_descriptor.proto
+++ b/protos/perfetto/common/data_source_descriptor.proto
@@ -22,9 +22,6 @@
 import "protos/perfetto/common/gpu_counter_descriptor.proto";
 import "protos/perfetto/common/track_event_descriptor.proto";
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // This message is sent from Producer(s) to the tracing Service when registering
 // to advertise their capabilities. It describes the structure of tracing
 // protos that will be produced by the data source and the supported filters.
diff --git a/protos/perfetto/common/tracing_service_state.proto b/protos/perfetto/common/tracing_service_state.proto
index 7f187ac..86723b3 100644
--- a/protos/perfetto/common/tracing_service_state.proto
+++ b/protos/perfetto/common/tracing_service_state.proto
@@ -21,9 +21,6 @@
 
 import "protos/perfetto/common/data_source_descriptor.proto";
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // Reports the state of the tracing service. Used to gather details about the
 // data sources connected.
 // See ConsumerPort::QueryServiceState().
diff --git a/protos/perfetto/config/chrome/chrome_config.proto b/protos/perfetto/config/chrome/chrome_config.proto
index e5c92d6..3906f03 100644
--- a/protos/perfetto/config/chrome/chrome_config.proto
+++ b/protos/perfetto/config/chrome/chrome_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ChromeConfig {
   optional string trace_config = 1;
 
diff --git a/protos/perfetto/config/data_source_config.proto b/protos/perfetto/config/data_source_config.proto
index c207723..3a63cbf 100644
--- a/protos/perfetto/config/data_source_config.proto
+++ b/protos/perfetto/config/data_source_config.proto
@@ -32,9 +32,6 @@
 import "protos/perfetto/config/sys_stats/sys_stats_config.proto";
 import "protos/perfetto/config/test_config.proto";
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration that is passed to each data source when starting tracing.
 message DataSourceConfig {
   // Data source unique name, e.g., "linux.ftrace". This must match
diff --git a/protos/perfetto/config/ftrace/ftrace_config.proto b/protos/perfetto/config/ftrace/ftrace_config.proto
index 24e5bce..56dc0d0 100644
--- a/protos/perfetto/config/ftrace/ftrace_config.proto
+++ b/protos/perfetto/config/ftrace/ftrace_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message FtraceConfig {
   repeated string ftrace_events = 1;
   repeated string atrace_categories = 2;
diff --git a/protos/perfetto/config/gpu/gpu_counter_config.proto b/protos/perfetto/config/gpu/gpu_counter_config.proto
index 6e448af..017195b 100644
--- a/protos/perfetto/config/gpu/gpu_counter_config.proto
+++ b/protos/perfetto/config/gpu/gpu_counter_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message GpuCounterConfig {
   // Desired sampling interval for counters.
   optional uint64 counter_period_ns = 1;
diff --git a/protos/perfetto/config/inode_file/inode_file_config.proto b/protos/perfetto/config/inode_file/inode_file_config.proto
index 47669bf..d291cd1 100644
--- a/protos/perfetto/config/inode_file/inode_file_config.proto
+++ b/protos/perfetto/config/inode_file/inode_file_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message InodeFileConfig {
   message MountPointMappingEntry {
     optional string mountpoint = 1;
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 0a6e824..2d38de4 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -40,9 +40,6 @@
 
 // Begin of protos/perfetto/common/data_source_descriptor.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // This message is sent from Producer(s) to the tracing Service when registering
 // to advertise their capabilities. It describes the structure of tracing
 // protos that will be produced by the data source and the supported filters.
@@ -467,9 +464,6 @@
 
 // Begin of protos/perfetto/common/tracing_service_state.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // Reports the state of the tracing service. Used to gather details about the
 // data sources connected.
 // See ConsumerPort::QueryServiceState().
@@ -533,9 +527,6 @@
 
 // Begin of protos/perfetto/config/chrome/chrome_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ChromeConfig {
   optional string trace_config = 1;
 
@@ -548,9 +539,6 @@
 
 // Begin of protos/perfetto/config/data_source_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration that is passed to each data source when starting tracing.
 message DataSourceConfig {
   // Data source unique name, e.g., "linux.ftrace". This must match
@@ -630,9 +618,6 @@
 
 // Begin of protos/perfetto/config/ftrace/ftrace_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message FtraceConfig {
   repeated string ftrace_events = 1;
   repeated string atrace_categories = 2;
@@ -660,9 +645,6 @@
 
 // Begin of protos/perfetto/config/inode_file/inode_file_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message InodeFileConfig {
   message MountPointMappingEntry {
     optional string mountpoint = 1;
@@ -713,9 +695,6 @@
 
 // Begin of protos/perfetto/config/process_stats/process_stats_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ProcessStatsConfig {
   enum Quirks {
     QUIRKS_UNSPECIFIED = 0;
@@ -760,9 +739,6 @@
 
 // Begin of protos/perfetto/config/sys_stats/sys_stats_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // This file defines the configuration for the Linux /proc poller data source,
 // which injects counters in the trace.
 // Counters that are needed in the trace must be explicitly listed in the
@@ -806,9 +782,6 @@
 
 // Begin of protos/perfetto/config/test_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration for a fake producer used in tests.
 message TestConfig {
   message DummyFields {
@@ -857,9 +830,6 @@
 
 // Begin of protos/perfetto/config/trace_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // The overall config that is used when starting a new tracing session through
 // ProducerPort::StartTracing().
 // It contains the general config for the logging buffer(s) and the configs for
@@ -1275,9 +1245,6 @@
 
 // Begin of protos/perfetto/config/gpu/gpu_counter_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message GpuCounterConfig {
   // Desired sampling interval for counters.
   optional uint64 counter_period_ns = 1;
diff --git a/protos/perfetto/config/process_stats/process_stats_config.proto b/protos/perfetto/config/process_stats/process_stats_config.proto
index 14b964d..14cb4e9 100644
--- a/protos/perfetto/config/process_stats/process_stats_config.proto
+++ b/protos/perfetto/config/process_stats/process_stats_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ProcessStatsConfig {
   enum Quirks {
     QUIRKS_UNSPECIFIED = 0;
diff --git a/protos/perfetto/config/sys_stats/sys_stats_config.proto b/protos/perfetto/config/sys_stats/sys_stats_config.proto
index cb6d557..7eafa3e 100644
--- a/protos/perfetto/config/sys_stats/sys_stats_config.proto
+++ b/protos/perfetto/config/sys_stats/sys_stats_config.proto
@@ -21,9 +21,6 @@
 
 import "protos/perfetto/common/sys_stats_counters.proto";
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // This file defines the configuration for the Linux /proc poller data source,
 // which injects counters in the trace.
 // Counters that are needed in the trace must be explicitly listed in the
diff --git a/protos/perfetto/config/test_config.proto b/protos/perfetto/config/test_config.proto
index b50012e..c22a7e9 100644
--- a/protos/perfetto/config/test_config.proto
+++ b/protos/perfetto/config/test_config.proto
@@ -19,9 +19,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration for a fake producer used in tests.
 message TestConfig {
   message DummyFields {
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index 032bc6e..9a44990 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -21,9 +21,6 @@
 
 package perfetto.protos;
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // The overall config that is used when starting a new tracing session through
 // ProducerPort::StartTracing().
 // It contains the general config for the logging buffer(s) and the configs for
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index eab011a..ebd8b98 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -175,8 +175,7 @@
 
 // Arguments for rpc CommitData().
 // See commit_data_request.proto for CommitDataRequest. That has its own file
-// because it is used also as input to generate the C++ classes in tracing/core
-// via tools/gen_tracing_cpp_headers_from_protos.py.
+// because it is used also as input to generate C++ classes (xxx.gen.h).
 
 message CommitDataResponse {}
 
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index 9f0e1c3..ca76396 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -61,11 +61,14 @@
   ]
 }
 
-perfetto_proto_library("non_minimal_@TYPE@") {
-  visibility = [
-    ":lite",
-    ":zero",
+group("cpp") {
+  public_deps = [
+    ":minimal_cpp",
+    ":non_minimal_cpp",
   ]
+}
+
+perfetto_proto_library("non_minimal_@TYPE@") {
   deps = [
     ":minimal_@TYPE@",
     "../config:@TYPE@",
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 7070df9..9302662 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -40,9 +40,6 @@
 
 // Begin of protos/perfetto/common/data_source_descriptor.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // This message is sent from Producer(s) to the tracing Service when registering
 // to advertise their capabilities. It describes the structure of tracing
 // protos that will be produced by the data source and the supported filters.
@@ -467,9 +464,6 @@
 
 // Begin of protos/perfetto/common/tracing_service_state.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // Reports the state of the tracing service. Used to gather details about the
 // data sources connected.
 // See ConsumerPort::QueryServiceState().
@@ -3011,11 +3005,27 @@
 // Begin of protos/perfetto/trace/profiling/heap_graph.proto
 
 message HeapGraphRoot {
+  enum Type {
+    ROOT_UNKNOWN = 0;
+    ROOT_JNI_GLOBAL = 1;
+    ROOT_JNI_LOCAL = 2;
+    ROOT_JAVA_FRAME = 3;
+    ROOT_NATIVE_STACK = 4;
+    ROOT_STICKY_CLASS = 5;
+    ROOT_THREAD_BLOCK = 6;
+    ROOT_MONITOR_USED = 7;
+    ROOT_THREAD_OBJECT = 8;
+    ROOT_INTERNED_STRING = 9;
+    ROOT_FINALIZING = 10;
+    ROOT_DEBUGGER = 11;
+    ROOT_REFERENCE_CLEANUP = 12;
+    ROOT_VM_INTERNAL = 13;
+    ROOT_JNI_MONITOR = 14;
+  };
   // Objects retained by this root.
   repeated uint64 object_ids = 1;
 
-  // From art:RootType, e.g. "kRootThreadObject".
-  optional string root_type = 2;
+  optional Type root_type = 2;
 }
 
 message HeapGraphObject {
@@ -4270,9 +4280,6 @@
 
 // Begin of protos/perfetto/config/chrome/chrome_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ChromeConfig {
   optional string trace_config = 1;
 
@@ -4285,9 +4292,6 @@
 
 // Begin of protos/perfetto/config/data_source_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration that is passed to each data source when starting tracing.
 message DataSourceConfig {
   // Data source unique name, e.g., "linux.ftrace". This must match
@@ -4367,9 +4371,6 @@
 
 // Begin of protos/perfetto/config/ftrace/ftrace_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message FtraceConfig {
   repeated string ftrace_events = 1;
   repeated string atrace_categories = 2;
@@ -4397,9 +4398,6 @@
 
 // Begin of protos/perfetto/config/inode_file/inode_file_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message InodeFileConfig {
   message MountPointMappingEntry {
     optional string mountpoint = 1;
@@ -4450,9 +4448,6 @@
 
 // Begin of protos/perfetto/config/process_stats/process_stats_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message ProcessStatsConfig {
   enum Quirks {
     QUIRKS_UNSPECIFIED = 0;
@@ -4497,9 +4492,6 @@
 
 // Begin of protos/perfetto/config/sys_stats/sys_stats_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // This file defines the configuration for the Linux /proc poller data source,
 // which injects counters in the trace.
 // Counters that are needed in the trace must be explicitly listed in the
@@ -4543,9 +4535,6 @@
 
 // Begin of protos/perfetto/config/test_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 // The configuration for a fake producer used in tests.
 message TestConfig {
   message DummyFields {
@@ -4594,9 +4583,6 @@
 
 // Begin of protos/perfetto/config/trace_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos
-// to reflect changes in the corresponding C++ headers.
-
 // The overall config that is used when starting a new tracing session through
 // ProducerPort::StartTracing().
 // It contains the general config for the logging buffer(s) and the configs for
@@ -5012,9 +4998,6 @@
 
 // Begin of protos/perfetto/config/gpu/gpu_counter_config.proto
 
-// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
-// to reflect changes in the corresponding C++ headers.
-
 message GpuCounterConfig {
   // Desired sampling interval for counters.
   optional uint64 counter_period_ns = 1;
diff --git a/protos/perfetto/trace/profiling/heap_graph.proto b/protos/perfetto/trace/profiling/heap_graph.proto
index f037545..d29c292 100644
--- a/protos/perfetto/trace/profiling/heap_graph.proto
+++ b/protos/perfetto/trace/profiling/heap_graph.proto
@@ -25,11 +25,27 @@
 package perfetto.protos;
 
 message HeapGraphRoot {
+  enum Type {
+    ROOT_UNKNOWN = 0;
+    ROOT_JNI_GLOBAL = 1;
+    ROOT_JNI_LOCAL = 2;
+    ROOT_JAVA_FRAME = 3;
+    ROOT_NATIVE_STACK = 4;
+    ROOT_STICKY_CLASS = 5;
+    ROOT_THREAD_BLOCK = 6;
+    ROOT_MONITOR_USED = 7;
+    ROOT_THREAD_OBJECT = 8;
+    ROOT_INTERNED_STRING = 9;
+    ROOT_FINALIZING = 10;
+    ROOT_DEBUGGER = 11;
+    ROOT_REFERENCE_CLEANUP = 12;
+    ROOT_VM_INTERNAL = 13;
+    ROOT_JNI_MONITOR = 14;
+  };
   // Objects retained by this root.
   repeated uint64 object_ids = 1;
 
-  // From art:RootType, e.g. "kRootThreadObject".
-  optional string root_type = 2;
+  optional Type root_type = 2;
 }
 
 message HeapGraphObject {
diff --git a/src/perfetto_cmd/perfetto_config.descriptor.h b/src/perfetto_cmd/perfetto_config.descriptor.h
index 8582caa..3dad237 100644
--- a/src/perfetto_cmd/perfetto_config.descriptor.h
+++ b/src/perfetto_cmd/perfetto_config.descriptor.h
@@ -12,7 +12,7 @@
 // SHA1(tools/gen_binary_descriptors)
 // 192b582ae52bb07b3d3ba66a94bcfd3127a5f42f
 // SHA1(protos/perfetto/config/perfetto_config.proto)
-// 8e2725637f1e6b1cffdd2de91ebb6570a9d3f9e2
+// e30931f8b517934b4dface8ece1b00d2ec6c3ca6
 
 // This is the proto PerfettoConfig encoded as a ProtoFileDescriptor to allow
 // for reflection without libprotobuf full/non-lite protos.
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index 10af659..9ef32c2 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -153,6 +153,7 @@
   ]
   public_deps = [
     "../../../gn:libunwindstack",
+    "../../../protos/perfetto/config/profiling:cpp",
     "../../../protos/perfetto/trace:zero",
     "../../../protos/perfetto/trace/interned_data:zero",
     "../../../protos/perfetto/trace/profiling:zero",
@@ -162,13 +163,9 @@
     "bookkeeping.h",
     "bookkeeping_dump.cc",
     "bookkeeping_dump.h",
-    "heapprofd_config.cc",
-    "heapprofd_config.h",
     "heapprofd_producer.cc",
     "heapprofd_producer.h",
     "interner.h",
-    "java_hprof_config.cc",
-    "java_hprof_config.h",
     "java_hprof_producer.cc",
     "java_hprof_producer.h",
     "page_idle_checker.cc",
diff --git a/src/profiling/memory/heapprofd_config.cc b/src/profiling/memory/heapprofd_config.cc
deleted file mode 100644
index 9087f8f..0000000
--- a/src/profiling/memory/heapprofd_config.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/profiling/heapprofd_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "src/profiling/memory/heapprofd_config.h"
-
-#include "protos/perfetto/config/profiling/heapprofd_config.pb.h"
-
-namespace perfetto {
-
-HeapprofdConfig::HeapprofdConfig() = default;
-HeapprofdConfig::~HeapprofdConfig() = default;
-HeapprofdConfig::HeapprofdConfig(const HeapprofdConfig&) = default;
-HeapprofdConfig& HeapprofdConfig::operator=(const HeapprofdConfig&) = default;
-HeapprofdConfig::HeapprofdConfig(HeapprofdConfig&&) noexcept = default;
-HeapprofdConfig& HeapprofdConfig::operator=(HeapprofdConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool HeapprofdConfig::operator==(const HeapprofdConfig& other) const {
-  return (sampling_interval_bytes_ == other.sampling_interval_bytes_) &&
-         (process_cmdline_ == other.process_cmdline_) && (pid_ == other.pid_) &&
-         (all_ == other.all_) &&
-         (skip_symbol_prefix_ == other.skip_symbol_prefix_) &&
-         (continuous_dump_config_ == other.continuous_dump_config_) &&
-         (shmem_size_bytes_ == other.shmem_size_bytes_) &&
-         (block_client_ == other.block_client_) &&
-         (no_startup_ == other.no_startup_) &&
-         (no_running_ == other.no_running_) &&
-         (idle_allocations_ == other.idle_allocations_) &&
-         (dump_at_max_ == other.dump_at_max_);
-}
-#pragma GCC diagnostic pop
-
-void HeapprofdConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::HeapprofdConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void HeapprofdConfig::FromProto(
-    const perfetto::protos::HeapprofdConfig& proto) {
-  static_assert(sizeof(sampling_interval_bytes_) ==
-                    sizeof(proto.sampling_interval_bytes()),
-                "size mismatch");
-  sampling_interval_bytes_ = static_cast<decltype(sampling_interval_bytes_)>(
-      proto.sampling_interval_bytes());
-
-  process_cmdline_.clear();
-  for (const auto& field : proto.process_cmdline()) {
-    process_cmdline_.emplace_back();
-    static_assert(
-        sizeof(process_cmdline_.back()) == sizeof(proto.process_cmdline(0)),
-        "size mismatch");
-    process_cmdline_.back() =
-        static_cast<decltype(process_cmdline_)::value_type>(field);
-  }
-
-  pid_.clear();
-  for (const auto& field : proto.pid()) {
-    pid_.emplace_back();
-    static_assert(sizeof(pid_.back()) == sizeof(proto.pid(0)), "size mismatch");
-    pid_.back() = static_cast<decltype(pid_)::value_type>(field);
-  }
-
-  static_assert(sizeof(all_) == sizeof(proto.all()), "size mismatch");
-  all_ = static_cast<decltype(all_)>(proto.all());
-
-  skip_symbol_prefix_.clear();
-  for (const auto& field : proto.skip_symbol_prefix()) {
-    skip_symbol_prefix_.emplace_back();
-    static_assert(sizeof(skip_symbol_prefix_.back()) ==
-                      sizeof(proto.skip_symbol_prefix(0)),
-                  "size mismatch");
-    skip_symbol_prefix_.back() =
-        static_cast<decltype(skip_symbol_prefix_)::value_type>(field);
-  }
-
-  continuous_dump_config_->FromProto(proto.continuous_dump_config());
-
-  static_assert(sizeof(shmem_size_bytes_) == sizeof(proto.shmem_size_bytes()),
-                "size mismatch");
-  shmem_size_bytes_ =
-      static_cast<decltype(shmem_size_bytes_)>(proto.shmem_size_bytes());
-
-  static_assert(sizeof(block_client_) == sizeof(proto.block_client()),
-                "size mismatch");
-  block_client_ = static_cast<decltype(block_client_)>(proto.block_client());
-
-  static_assert(sizeof(no_startup_) == sizeof(proto.no_startup()),
-                "size mismatch");
-  no_startup_ = static_cast<decltype(no_startup_)>(proto.no_startup());
-
-  static_assert(sizeof(no_running_) == sizeof(proto.no_running()),
-                "size mismatch");
-  no_running_ = static_cast<decltype(no_running_)>(proto.no_running());
-
-  static_assert(sizeof(idle_allocations_) == sizeof(proto.idle_allocations()),
-                "size mismatch");
-  idle_allocations_ =
-      static_cast<decltype(idle_allocations_)>(proto.idle_allocations());
-
-  static_assert(sizeof(dump_at_max_) == sizeof(proto.dump_at_max()),
-                "size mismatch");
-  dump_at_max_ = static_cast<decltype(dump_at_max_)>(proto.dump_at_max());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void HeapprofdConfig::ToProto(perfetto::protos::HeapprofdConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(sampling_interval_bytes_) ==
-                    sizeof(proto->sampling_interval_bytes()),
-                "size mismatch");
-  proto->set_sampling_interval_bytes(
-      static_cast<decltype(proto->sampling_interval_bytes())>(
-          sampling_interval_bytes_));
-
-  for (const auto& it : process_cmdline_) {
-    proto->add_process_cmdline(
-        static_cast<decltype(proto->process_cmdline(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->process_cmdline(0)),
-                  "size mismatch");
-  }
-
-  for (const auto& it : pid_) {
-    proto->add_pid(static_cast<decltype(proto->pid(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->pid(0)), "size mismatch");
-  }
-
-  static_assert(sizeof(all_) == sizeof(proto->all()), "size mismatch");
-  proto->set_all(static_cast<decltype(proto->all())>(all_));
-
-  for (const auto& it : skip_symbol_prefix_) {
-    proto->add_skip_symbol_prefix(
-        static_cast<decltype(proto->skip_symbol_prefix(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->skip_symbol_prefix(0)),
-                  "size mismatch");
-  }
-
-  continuous_dump_config_->ToProto(proto->mutable_continuous_dump_config());
-
-  static_assert(sizeof(shmem_size_bytes_) == sizeof(proto->shmem_size_bytes()),
-                "size mismatch");
-  proto->set_shmem_size_bytes(
-      static_cast<decltype(proto->shmem_size_bytes())>(shmem_size_bytes_));
-
-  static_assert(sizeof(block_client_) == sizeof(proto->block_client()),
-                "size mismatch");
-  proto->set_block_client(
-      static_cast<decltype(proto->block_client())>(block_client_));
-
-  static_assert(sizeof(no_startup_) == sizeof(proto->no_startup()),
-                "size mismatch");
-  proto->set_no_startup(
-      static_cast<decltype(proto->no_startup())>(no_startup_));
-
-  static_assert(sizeof(no_running_) == sizeof(proto->no_running()),
-                "size mismatch");
-  proto->set_no_running(
-      static_cast<decltype(proto->no_running())>(no_running_));
-
-  static_assert(sizeof(idle_allocations_) == sizeof(proto->idle_allocations()),
-                "size mismatch");
-  proto->set_idle_allocations(
-      static_cast<decltype(proto->idle_allocations())>(idle_allocations_));
-
-  static_assert(sizeof(dump_at_max_) == sizeof(proto->dump_at_max()),
-                "size mismatch");
-  proto->set_dump_at_max(
-      static_cast<decltype(proto->dump_at_max())>(dump_at_max_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-HeapprofdConfig::ContinuousDumpConfig::ContinuousDumpConfig() = default;
-HeapprofdConfig::ContinuousDumpConfig::~ContinuousDumpConfig() = default;
-HeapprofdConfig::ContinuousDumpConfig::ContinuousDumpConfig(
-    const HeapprofdConfig::ContinuousDumpConfig&) = default;
-HeapprofdConfig::ContinuousDumpConfig& HeapprofdConfig::ContinuousDumpConfig::
-operator=(const HeapprofdConfig::ContinuousDumpConfig&) = default;
-HeapprofdConfig::ContinuousDumpConfig::ContinuousDumpConfig(
-    HeapprofdConfig::ContinuousDumpConfig&&) noexcept = default;
-HeapprofdConfig::ContinuousDumpConfig& HeapprofdConfig::ContinuousDumpConfig::
-operator=(HeapprofdConfig::ContinuousDumpConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool HeapprofdConfig::ContinuousDumpConfig::operator==(
-    const HeapprofdConfig::ContinuousDumpConfig& other) const {
-  return (dump_phase_ms_ == other.dump_phase_ms_) &&
-         (dump_interval_ms_ == other.dump_interval_ms_);
-}
-#pragma GCC diagnostic pop
-
-void HeapprofdConfig::ContinuousDumpConfig::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::HeapprofdConfig_ContinuousDumpConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void HeapprofdConfig::ContinuousDumpConfig::FromProto(
-    const perfetto::protos::HeapprofdConfig_ContinuousDumpConfig& proto) {
-  static_assert(sizeof(dump_phase_ms_) == sizeof(proto.dump_phase_ms()),
-                "size mismatch");
-  dump_phase_ms_ = static_cast<decltype(dump_phase_ms_)>(proto.dump_phase_ms());
-
-  static_assert(sizeof(dump_interval_ms_) == sizeof(proto.dump_interval_ms()),
-                "size mismatch");
-  dump_interval_ms_ =
-      static_cast<decltype(dump_interval_ms_)>(proto.dump_interval_ms());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void HeapprofdConfig::ContinuousDumpConfig::ToProto(
-    perfetto::protos::HeapprofdConfig_ContinuousDumpConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(dump_phase_ms_) == sizeof(proto->dump_phase_ms()),
-                "size mismatch");
-  proto->set_dump_phase_ms(
-      static_cast<decltype(proto->dump_phase_ms())>(dump_phase_ms_));
-
-  static_assert(sizeof(dump_interval_ms_) == sizeof(proto->dump_interval_ms()),
-                "size mismatch");
-  proto->set_dump_interval_ms(
-      static_cast<decltype(proto->dump_interval_ms())>(dump_interval_ms_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/profiling/memory/heapprofd_config.h b/src/profiling/memory/heapprofd_config.h
deleted file mode 100644
index 92ca95a..0000000
--- a/src/profiling/memory/heapprofd_config.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/profiling/heapprofd_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#ifndef SRC_PROFILING_MEMORY_HEAPPROFD_CONFIG_H_
-#define SRC_PROFILING_MEMORY_HEAPPROFD_CONFIG_H_
-
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class HeapprofdConfig;
-class HeapprofdConfig_ContinuousDumpConfig;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class HeapprofdConfig;
-
-class PERFETTO_EXPORT HeapprofdConfig {
- public:
-  class PERFETTO_EXPORT ContinuousDumpConfig {
-   public:
-    ContinuousDumpConfig();
-    ~ContinuousDumpConfig();
-    ContinuousDumpConfig(ContinuousDumpConfig&&) noexcept;
-    ContinuousDumpConfig& operator=(ContinuousDumpConfig&&);
-    ContinuousDumpConfig(const ContinuousDumpConfig&);
-    ContinuousDumpConfig& operator=(const ContinuousDumpConfig&);
-    bool operator==(const ContinuousDumpConfig&) const;
-    bool operator!=(const ContinuousDumpConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(
-        const perfetto::protos::HeapprofdConfig_ContinuousDumpConfig&);
-    void ToProto(perfetto::protos::HeapprofdConfig_ContinuousDumpConfig*) const;
-
-    uint32_t dump_phase_ms() const { return dump_phase_ms_; }
-    void set_dump_phase_ms(uint32_t value) { dump_phase_ms_ = value; }
-
-    uint32_t dump_interval_ms() const { return dump_interval_ms_; }
-    void set_dump_interval_ms(uint32_t value) { dump_interval_ms_ = value; }
-
-   private:
-    uint32_t dump_phase_ms_{};
-    uint32_t dump_interval_ms_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  HeapprofdConfig();
-  ~HeapprofdConfig();
-  HeapprofdConfig(HeapprofdConfig&&) noexcept;
-  HeapprofdConfig& operator=(HeapprofdConfig&&);
-  HeapprofdConfig(const HeapprofdConfig&);
-  HeapprofdConfig& operator=(const HeapprofdConfig&);
-  bool operator==(const HeapprofdConfig&) const;
-  bool operator!=(const HeapprofdConfig& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::HeapprofdConfig&);
-  void ToProto(perfetto::protos::HeapprofdConfig*) const;
-
-  uint64_t sampling_interval_bytes() const { return sampling_interval_bytes_; }
-  void set_sampling_interval_bytes(uint64_t value) {
-    sampling_interval_bytes_ = value;
-  }
-
-  int process_cmdline_size() const {
-    return static_cast<int>(process_cmdline_.size());
-  }
-  const std::vector<std::string>& process_cmdline() const {
-    return process_cmdline_;
-  }
-  std::vector<std::string>* mutable_process_cmdline() {
-    return &process_cmdline_;
-  }
-  void clear_process_cmdline() { process_cmdline_.clear(); }
-  std::string* add_process_cmdline() {
-    process_cmdline_.emplace_back();
-    return &process_cmdline_.back();
-  }
-
-  int pid_size() const { return static_cast<int>(pid_.size()); }
-  const std::vector<uint64_t>& pid() const { return pid_; }
-  std::vector<uint64_t>* mutable_pid() { return &pid_; }
-  void clear_pid() { pid_.clear(); }
-  uint64_t* add_pid() {
-    pid_.emplace_back();
-    return &pid_.back();
-  }
-
-  bool all() const { return all_; }
-  void set_all(bool value) { all_ = value; }
-
-  int skip_symbol_prefix_size() const {
-    return static_cast<int>(skip_symbol_prefix_.size());
-  }
-  const std::vector<std::string>& skip_symbol_prefix() const {
-    return skip_symbol_prefix_;
-  }
-  std::vector<std::string>* mutable_skip_symbol_prefix() {
-    return &skip_symbol_prefix_;
-  }
-  void clear_skip_symbol_prefix() { skip_symbol_prefix_.clear(); }
-  std::string* add_skip_symbol_prefix() {
-    skip_symbol_prefix_.emplace_back();
-    return &skip_symbol_prefix_.back();
-  }
-
-  const ContinuousDumpConfig& continuous_dump_config() const {
-    return *continuous_dump_config_;
-  }
-  ContinuousDumpConfig* mutable_continuous_dump_config() {
-    return continuous_dump_config_.get();
-  }
-
-  uint64_t shmem_size_bytes() const { return shmem_size_bytes_; }
-  void set_shmem_size_bytes(uint64_t value) { shmem_size_bytes_ = value; }
-
-  bool block_client() const { return block_client_; }
-  void set_block_client(bool value) { block_client_ = value; }
-
-  bool no_startup() const { return no_startup_; }
-  void set_no_startup(bool value) { no_startup_ = value; }
-
-  bool no_running() const { return no_running_; }
-  void set_no_running(bool value) { no_running_ = value; }
-
-  bool idle_allocations() const { return idle_allocations_; }
-  void set_idle_allocations(bool value) { idle_allocations_ = value; }
-
-  bool dump_at_max() const { return dump_at_max_; }
-  void set_dump_at_max(bool value) { dump_at_max_ = value; }
-
- private:
-  uint64_t sampling_interval_bytes_{};
-  std::vector<std::string> process_cmdline_;
-  std::vector<uint64_t> pid_;
-  bool all_{};
-  std::vector<std::string> skip_symbol_prefix_;
-  ::perfetto::base::CopyablePtr<ContinuousDumpConfig> continuous_dump_config_;
-  uint64_t shmem_size_bytes_{};
-  bool block_client_{};
-  bool no_startup_{};
-  bool no_running_{};
-  bool idle_allocations_{};
-  bool dump_at_max_{};
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
-
-#endif  // SRC_PROFILING_MEMORY_HEAPPROFD_CONFIG_H_
diff --git a/src/profiling/memory/heapprofd_producer.h b/src/profiling/memory/heapprofd_producer.h
index 732f6e9..e1299ae 100644
--- a/src/profiling/memory/heapprofd_producer.h
+++ b/src/profiling/memory/heapprofd_producer.h
@@ -35,12 +35,13 @@
 
 #include "src/profiling/memory/bookkeeping.h"
 #include "src/profiling/memory/bookkeeping_dump.h"
-#include "src/profiling/memory/heapprofd_config.h"
 #include "src/profiling/memory/page_idle_checker.h"
 #include "src/profiling/memory/proc_utils.h"
 #include "src/profiling/memory/system_property.h"
 #include "src/profiling/memory/unwinding.h"
 
+#include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+
 namespace perfetto {
 namespace profiling {
 
diff --git a/src/profiling/memory/java_hprof_config.cc b/src/profiling/memory/java_hprof_config.cc
deleted file mode 100644
index d8d757c..0000000
--- a/src/profiling/memory/java_hprof_config.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/profiling/java_hprof_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "src/profiling/memory/java_hprof_config.h"
-
-#include "protos/perfetto/config/profiling/java_hprof_config.pb.h"
-
-namespace perfetto {
-
-JavaHprofConfig::JavaHprofConfig() = default;
-JavaHprofConfig::~JavaHprofConfig() = default;
-JavaHprofConfig::JavaHprofConfig(const JavaHprofConfig&) = default;
-JavaHprofConfig& JavaHprofConfig::operator=(const JavaHprofConfig&) = default;
-JavaHprofConfig::JavaHprofConfig(JavaHprofConfig&&) noexcept = default;
-JavaHprofConfig& JavaHprofConfig::operator=(JavaHprofConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool JavaHprofConfig::operator==(const JavaHprofConfig& other) const {
-  return (process_cmdline_ == other.process_cmdline_) && (pid_ == other.pid_) &&
-         (continuous_dump_config_ == other.continuous_dump_config_);
-}
-#pragma GCC diagnostic pop
-
-void JavaHprofConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::JavaHprofConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void JavaHprofConfig::FromProto(
-    const perfetto::protos::JavaHprofConfig& proto) {
-  process_cmdline_.clear();
-  for (const auto& field : proto.process_cmdline()) {
-    process_cmdline_.emplace_back();
-    static_assert(
-        sizeof(process_cmdline_.back()) == sizeof(proto.process_cmdline(0)),
-        "size mismatch");
-    process_cmdline_.back() =
-        static_cast<decltype(process_cmdline_)::value_type>(field);
-  }
-
-  pid_.clear();
-  for (const auto& field : proto.pid()) {
-    pid_.emplace_back();
-    static_assert(sizeof(pid_.back()) == sizeof(proto.pid(0)), "size mismatch");
-    pid_.back() = static_cast<decltype(pid_)::value_type>(field);
-  }
-
-  continuous_dump_config_->FromProto(proto.continuous_dump_config());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void JavaHprofConfig::ToProto(perfetto::protos::JavaHprofConfig* proto) const {
-  proto->Clear();
-
-  for (const auto& it : process_cmdline_) {
-    proto->add_process_cmdline(
-        static_cast<decltype(proto->process_cmdline(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->process_cmdline(0)),
-                  "size mismatch");
-  }
-
-  for (const auto& it : pid_) {
-    proto->add_pid(static_cast<decltype(proto->pid(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->pid(0)), "size mismatch");
-  }
-
-  continuous_dump_config_->ToProto(proto->mutable_continuous_dump_config());
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-JavaHprofConfig::ContinuousDumpConfig::ContinuousDumpConfig() = default;
-JavaHprofConfig::ContinuousDumpConfig::~ContinuousDumpConfig() = default;
-JavaHprofConfig::ContinuousDumpConfig::ContinuousDumpConfig(
-    const JavaHprofConfig::ContinuousDumpConfig&) = default;
-JavaHprofConfig::ContinuousDumpConfig& JavaHprofConfig::ContinuousDumpConfig::
-operator=(const JavaHprofConfig::ContinuousDumpConfig&) = default;
-JavaHprofConfig::ContinuousDumpConfig::ContinuousDumpConfig(
-    JavaHprofConfig::ContinuousDumpConfig&&) noexcept = default;
-JavaHprofConfig::ContinuousDumpConfig& JavaHprofConfig::ContinuousDumpConfig::
-operator=(JavaHprofConfig::ContinuousDumpConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool JavaHprofConfig::ContinuousDumpConfig::operator==(
-    const JavaHprofConfig::ContinuousDumpConfig& other) const {
-  return (dump_phase_ms_ == other.dump_phase_ms_) &&
-         (dump_interval_ms_ == other.dump_interval_ms_);
-}
-#pragma GCC diagnostic pop
-
-void JavaHprofConfig::ContinuousDumpConfig::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::JavaHprofConfig_ContinuousDumpConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void JavaHprofConfig::ContinuousDumpConfig::FromProto(
-    const perfetto::protos::JavaHprofConfig_ContinuousDumpConfig& proto) {
-  static_assert(sizeof(dump_phase_ms_) == sizeof(proto.dump_phase_ms()),
-                "size mismatch");
-  dump_phase_ms_ = static_cast<decltype(dump_phase_ms_)>(proto.dump_phase_ms());
-
-  static_assert(sizeof(dump_interval_ms_) == sizeof(proto.dump_interval_ms()),
-                "size mismatch");
-  dump_interval_ms_ =
-      static_cast<decltype(dump_interval_ms_)>(proto.dump_interval_ms());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void JavaHprofConfig::ContinuousDumpConfig::ToProto(
-    perfetto::protos::JavaHprofConfig_ContinuousDumpConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(dump_phase_ms_) == sizeof(proto->dump_phase_ms()),
-                "size mismatch");
-  proto->set_dump_phase_ms(
-      static_cast<decltype(proto->dump_phase_ms())>(dump_phase_ms_));
-
-  static_assert(sizeof(dump_interval_ms_) == sizeof(proto->dump_interval_ms()),
-                "size mismatch");
-  proto->set_dump_interval_ms(
-      static_cast<decltype(proto->dump_interval_ms())>(dump_interval_ms_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/profiling/memory/java_hprof_config.h b/src/profiling/memory/java_hprof_config.h
deleted file mode 100644
index bcbea0d..0000000
--- a/src/profiling/memory/java_hprof_config.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/profiling/java_hprof_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#ifndef SRC_PROFILING_MEMORY_JAVA_HPROF_CONFIG_H_
-#define SRC_PROFILING_MEMORY_JAVA_HPROF_CONFIG_H_
-
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class JavaHprofConfig;
-class JavaHprofConfig_ContinuousDumpConfig;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class JavaHprofConfig;
-
-class PERFETTO_EXPORT JavaHprofConfig {
- public:
-  class PERFETTO_EXPORT ContinuousDumpConfig {
-   public:
-    ContinuousDumpConfig();
-    ~ContinuousDumpConfig();
-    ContinuousDumpConfig(ContinuousDumpConfig&&) noexcept;
-    ContinuousDumpConfig& operator=(ContinuousDumpConfig&&);
-    ContinuousDumpConfig(const ContinuousDumpConfig&);
-    ContinuousDumpConfig& operator=(const ContinuousDumpConfig&);
-    bool operator==(const ContinuousDumpConfig&) const;
-    bool operator!=(const ContinuousDumpConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(
-        const perfetto::protos::JavaHprofConfig_ContinuousDumpConfig&);
-    void ToProto(perfetto::protos::JavaHprofConfig_ContinuousDumpConfig*) const;
-
-    uint32_t dump_phase_ms() const { return dump_phase_ms_; }
-    void set_dump_phase_ms(uint32_t value) { dump_phase_ms_ = value; }
-
-    uint32_t dump_interval_ms() const { return dump_interval_ms_; }
-    void set_dump_interval_ms(uint32_t value) { dump_interval_ms_ = value; }
-
-   private:
-    uint32_t dump_phase_ms_{};
-    uint32_t dump_interval_ms_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  JavaHprofConfig();
-  ~JavaHprofConfig();
-  JavaHprofConfig(JavaHprofConfig&&) noexcept;
-  JavaHprofConfig& operator=(JavaHprofConfig&&);
-  JavaHprofConfig(const JavaHprofConfig&);
-  JavaHprofConfig& operator=(const JavaHprofConfig&);
-  bool operator==(const JavaHprofConfig&) const;
-  bool operator!=(const JavaHprofConfig& other) const {
-    return !(*this == other);
-  }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::JavaHprofConfig&);
-  void ToProto(perfetto::protos::JavaHprofConfig*) const;
-
-  int process_cmdline_size() const {
-    return static_cast<int>(process_cmdline_.size());
-  }
-  const std::vector<std::string>& process_cmdline() const {
-    return process_cmdline_;
-  }
-  std::vector<std::string>* mutable_process_cmdline() {
-    return &process_cmdline_;
-  }
-  void clear_process_cmdline() { process_cmdline_.clear(); }
-  std::string* add_process_cmdline() {
-    process_cmdline_.emplace_back();
-    return &process_cmdline_.back();
-  }
-
-  int pid_size() const { return static_cast<int>(pid_.size()); }
-  const std::vector<uint64_t>& pid() const { return pid_; }
-  std::vector<uint64_t>* mutable_pid() { return &pid_; }
-  void clear_pid() { pid_.clear(); }
-  uint64_t* add_pid() {
-    pid_.emplace_back();
-    return &pid_.back();
-  }
-
-  const ContinuousDumpConfig& continuous_dump_config() const {
-    return *continuous_dump_config_;
-  }
-  ContinuousDumpConfig* mutable_continuous_dump_config() {
-    return continuous_dump_config_.get();
-  }
-
- private:
-  std::vector<std::string> process_cmdline_;
-  std::vector<uint64_t> pid_;
-  ::perfetto::base::CopyablePtr<ContinuousDumpConfig> continuous_dump_config_;
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
-
-#endif  // SRC_PROFILING_MEMORY_JAVA_HPROF_CONFIG_H_
diff --git a/src/profiling/memory/java_hprof_producer.h b/src/profiling/memory/java_hprof_producer.h
index d7db887d..cabdeae 100644
--- a/src/profiling/memory/java_hprof_producer.h
+++ b/src/profiling/memory/java_hprof_producer.h
@@ -28,7 +28,8 @@
 #include "perfetto/ext/tracing/ipc/producer_ipc_client.h"
 #include "perfetto/tracing/core/data_source_config.h"
 #include "perfetto/tracing/core/data_source_descriptor.h"
-#include "src/profiling/memory/java_hprof_config.h"
+
+#include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
 
 namespace perfetto {
 namespace profiling {
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index b767a9a..398ad85 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -70,6 +70,10 @@
 # Generates both xxx.pbzero.h and xxx.pb.h (official proto).
 
 perfetto_proto_library("testing_messages_@TYPE@") {
+  proto_generators = [
+    "lite",
+    "zero",
+  ]
   sources = [
     "test/example_proto/library.proto",
     "test/example_proto/library_internals/galaxies.proto",
diff --git a/src/protozero/protoc_plugin/BUILD.gn b/src/protozero/protoc_plugin/BUILD.gn
index 432abd8..4a9c7f4 100644
--- a/src/protozero/protoc_plugin/BUILD.gn
+++ b/src/protozero/protoc_plugin/BUILD.gn
@@ -14,6 +14,8 @@
 
 import("../../../gn/perfetto_host_executable.gni")
 
+# The plugin that generates zero-copy serializers and deserializers. Those are
+# the xxx.pbzero.h headers used all over the codebase.
 perfetto_host_executable("protozero_plugin") {
   sources = [
     "protozero_plugin.cc",
@@ -24,3 +26,17 @@
     "../../../src/base",
   ]
 }
+
+# The plugin that generates standalone C++ objects from protos (xxx.gen.h).
+# This is used for core classes traced needs to know about such as
+# DataSourceDescriptor.
+perfetto_host_executable("cppgen_plugin") {
+  sources = [
+    "cppgen_plugin.cc",
+  ]
+  deps = [
+    "../../../gn:default_deps",
+    "../../../gn:protoc_lib",
+    "../../../src/base",
+  ]
+}
diff --git a/src/protozero/protoc_plugin/cppgen_plugin.cc b/src/protozero/protoc_plugin/cppgen_plugin.cc
new file mode 100644
index 0000000..817f078
--- /dev/null
+++ b/src/protozero/protoc_plugin/cppgen_plugin.cc
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <stack>
+#include <vector>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/importer.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/util/field_comparator.h>
+#include <google/protobuf/util/message_differencer.h>
+
+#include "perfetto/ext/base/string_utils.h"
+
+namespace protozero {
+namespace {
+
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace google::protobuf::io;
+using perfetto::base::SplitString;
+using perfetto::base::StripChars;
+using perfetto::base::StripSuffix;
+using perfetto::base::ToUpper;
+
+static constexpr auto TYPE_MESSAGE = FieldDescriptor::TYPE_MESSAGE;
+
+static const char kHeader[] =
+    "// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin\n";
+
+std::string GetProtoHeader(const FileDescriptor* file) {
+  return StripSuffix(file->name(), ".proto") + ".pb.h";
+}
+
+template <typename T = Descriptor>
+std::string GetFullName(const T* msg, bool with_namespace = false) {
+  std::string full_type;
+  full_type.append(msg->name());
+  for (const Descriptor* par = msg->containing_type(); par;
+       par = par->containing_type()) {
+    full_type.insert(0, par->name() + "_");
+  }
+  if (with_namespace) {
+    std::vector<std::string> namespaces =
+        SplitString(msg->file()->package(), ".");
+    for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) {
+      full_type.insert(0, *it + "::");
+    }
+  }
+  return full_type;
+}
+
+class CppObjGenerator : public ::google::protobuf::compiler::CodeGenerator {
+ public:
+  CppObjGenerator();
+  ~CppObjGenerator() override;
+
+  // CodeGenerator implementation
+  bool Generate(const google::protobuf::FileDescriptor* file,
+                const std::string& options,
+                GeneratorContext* context,
+                std::string* error) const override;
+
+ private:
+  std::string GetCppType(const FieldDescriptor* field, bool constref) const;
+  void GenEnum(const EnumDescriptor*, Printer*) const;
+  void GenEnumAliases(const EnumDescriptor*, Printer*) const;
+  void GenClassDecl(const Descriptor*, Printer*) const;
+  void GenClassDef(const Descriptor*, Printer*) const;
+};
+
+CppObjGenerator::CppObjGenerator() = default;
+CppObjGenerator::~CppObjGenerator() = default;
+
+bool CppObjGenerator::Generate(const google::protobuf::FileDescriptor* file,
+                               const std::string& /*options*/,
+                               GeneratorContext* context,
+                               std::string* error) const {
+  auto get_file_name = [](const FileDescriptor* proto) {
+    return StripSuffix(proto->name(), ".proto") + ".gen";
+  };
+
+  const std::unique_ptr<ZeroCopyOutputStream> h_fstream(
+      context->Open(get_file_name(file) + ".h"));
+  const std::unique_ptr<ZeroCopyOutputStream> cc_fstream(
+      context->Open(get_file_name(file) + ".cc"));
+
+  // Variables are delimited by $.
+  Printer h_printer(h_fstream.get(), '$');
+  Printer cc_printer(cc_fstream.get(), '$');
+
+  std::string include_guard = file->package() + "_" + file->name() + "_CPP_H_";
+  include_guard = ToUpper(include_guard);
+  include_guard = StripChars(include_guard, ".-/\\", '_');
+
+  h_printer.Print(kHeader);
+  h_printer.Print("#ifndef $g$\n#define $g$\n\n", "g", include_guard);
+  h_printer.Print("#include <stdint.h>\n");
+  h_printer.Print("#include <vector>\n");
+  h_printer.Print("#include <string>\n");
+  h_printer.Print("#include <type_traits>\n\n");
+  h_printer.Print("#include \"perfetto/base/copyable_ptr.h\"\n");
+  h_printer.Print("#include \"perfetto/base/export.h\"\n\n");
+
+  cc_printer.Print(kHeader);
+  cc_printer.Print("#pragma GCC diagnostic push\n");
+  cc_printer.Print("#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n");
+
+  // Generate includes for translated types of dependencies.
+
+  // Figure out the subset of imports that are used only for lazy fields. We
+  // won't emit a C++ #include for them. This code is overly aggressive at
+  // removing imports: it rules them out as soon as it sees one lazy field
+  // whose type is defined in that import. A 100% correct solution would require
+  // to check that *all* dependent types for a given import are lazy before
+  // excluding that. In practice we don't need that because we don't use imports
+  // for both lazy and non-lazy fields.
+  std::set<std::string> lazy_imports;
+  for (int m = 0; m < file->message_type_count(); m++) {
+    const Descriptor* msg = file->message_type(m);
+    for (int i = 0; i < msg->field_count(); i++) {
+      const FieldDescriptor* field = msg->field(i);
+      if (field->options().lazy()) {
+        lazy_imports.insert(field->message_type()->file()->name());
+      }
+    }
+  }
+
+  // Include the .pb.h for the current file.
+  cc_printer.Print("\n#include \"$f$\"\n", "f", GetProtoHeader(file));
+
+  // Recursively traverse all imports and turn them into #include(s).
+  std::vector<const FileDescriptor*> imports_to_visit;
+  std::set<const FileDescriptor*> imports_visited;
+  imports_to_visit.push_back(file);
+
+  while (!imports_to_visit.empty()) {
+    const FileDescriptor* cur = imports_to_visit.back();
+    imports_to_visit.pop_back();
+    imports_visited.insert(cur);
+    cc_printer.Print("#include \"$f$.h\"\n", "f", get_file_name(cur));
+    for (int i = 0; i < cur->dependency_count(); i++) {
+      const FileDescriptor* dep = cur->dependency(i);
+      if (imports_visited.count(dep) || lazy_imports.count(dep->name()))
+        continue;
+      imports_to_visit.push_back(dep);
+    }
+  }
+
+  // Compute all nested types to generate forward declarations later.
+
+  std::set<const Descriptor*> local_types;  // Cur .proto file only.
+  std::set<const Descriptor*> all_types;    // All deps
+  std::set<const EnumDescriptor*> local_enums;
+  std::set<const EnumDescriptor*> all_enums;
+
+  auto add_enum = [&local_enums, &all_enums,
+                   &file](const EnumDescriptor* enum_desc) {
+    if (all_enums.count(enum_desc))
+      return;
+    all_enums.insert(enum_desc);
+    if (enum_desc->file() == file)
+      local_enums.insert(enum_desc);
+  };
+
+  std::stack<const Descriptor*> recursion_stack;
+  for (int i = 0; i < file->message_type_count(); i++)
+    recursion_stack.push(file->message_type(i));
+
+  while (!recursion_stack.empty()) {
+    const Descriptor* msg = recursion_stack.top();
+    recursion_stack.pop();
+    if (all_types.count(msg))
+      continue;
+    all_types.insert(msg);
+    if (msg->file() == file)
+      local_types.insert(msg);
+
+    for (int i = 0; i < msg->nested_type_count(); i++)
+      recursion_stack.push(msg->nested_type(i));
+
+    for (int i = 0; i < msg->enum_type_count(); i++)
+      add_enum(msg->enum_type(i));
+
+    for (int i = 0; i < msg->field_count(); i++) {
+      const FieldDescriptor* field = msg->field(i);
+      if (field->has_default_value()) {
+        *error = "field " + field->name() +
+                 ": Explicitly declared default values are not supported";
+        return false;
+      }
+      if (field->options().lazy() &&
+          (field->is_repeated() || field->type() != TYPE_MESSAGE)) {
+        *error = "[lazy=true] is supported only on non-repeated fields\n";
+        return false;
+      }
+
+      if (field->type() == TYPE_MESSAGE && !field->options().lazy())
+        recursion_stack.push(field->message_type());
+
+      if (field->type() == FieldDescriptor::TYPE_ENUM)
+        add_enum(field->enum_type());
+    }
+  }  //  while (!recursion_stack.empty())
+
+  // Generate forward declarations in the header for proto types.
+  h_printer.Print("// Forward declarations for protobuf types.\n");
+  std::vector<std::string> namespaces = SplitString(file->package(), ".");
+  for (size_t i = 0; i < namespaces.size(); i++)
+    h_printer.Print("namespace $n$ {\n", "n", namespaces[i]);
+
+  for (const Descriptor* msg : all_types)
+    h_printer.Print("class $n$;\n", "n", GetFullName(msg));
+
+  for (size_t i = 0; i < namespaces.size(); i++)
+    h_printer.Print("}\n");
+
+  h_printer.Print("\nnamespace perfetto {\n");
+  cc_printer.Print("\nnamespace perfetto {\n");
+
+  // Generate fwd declarations for C++ types.
+  for (const EnumDescriptor* enm : all_enums) {
+    h_printer.Print("enum $n$ : int;\n", "n", GetFullName(enm));
+  }
+
+  for (const Descriptor* msg : all_types)
+    h_printer.Print("class $n$;\n", "n", GetFullName(msg));
+
+  // Generate declarations and definitions.
+  for (const EnumDescriptor* enm : local_enums)
+    GenEnum(enm, &h_printer);
+
+  for (const Descriptor* msg : local_types) {
+    GenClassDecl(msg, &h_printer);
+    GenClassDef(msg, &cc_printer);
+  }
+
+  cc_printer.Print("}  // namespace perfetto\n");
+  cc_printer.Print("#pragma GCC diagnostic pop\n");
+
+  h_printer.Print("}  // namespace perfetto\n");
+  h_printer.Print("\n#endif  // $g$\n", "g", include_guard);
+
+  return true;
+}
+
+std::string CppObjGenerator::GetCppType(const FieldDescriptor* field,
+                                        bool constref) const {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_UINT32:
+      return "uint32_t";
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+      return "int32_t";
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_UINT64:
+      return "uint64_t";
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_INT64:
+      return "int64_t";
+    case FieldDescriptor::TYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      return constref ? "const std::string&" : "std::string";
+    case FieldDescriptor::TYPE_MESSAGE:
+      assert(!field->options().lazy());
+      return constref ? "const " + GetFullName(field->message_type()) + "&"
+                      : GetFullName(field->message_type());
+    case FieldDescriptor::TYPE_ENUM:
+      return GetFullName(field->enum_type());
+    case FieldDescriptor::TYPE_GROUP:
+      abort();
+  }
+  abort();  // for gcc
+}
+
+void CppObjGenerator::GenEnum(const EnumDescriptor* enum_desc,
+                              Printer* p) const {
+  std::string full_name = GetFullName(enum_desc);
+  p->Print("enum $f$ : int {\n", "f", full_name);
+  for (int e = 0; e < enum_desc->value_count(); e++) {
+    const EnumValueDescriptor* value = enum_desc->value(e);
+    p->Print("  $f$_$n$ = $v$,\n", "f", full_name, "n", value->name(), "v",
+             std::to_string(value->number()));
+  }
+  p->Print("};\n");
+}
+
+void CppObjGenerator::GenEnumAliases(const EnumDescriptor* enum_desc,
+                                     Printer* p) const {
+  std::string full_name = GetFullName(enum_desc);
+  for (int e = 0; e < enum_desc->value_count(); e++) {
+    const EnumValueDescriptor* value = enum_desc->value(e);
+    p->Print("static constexpr auto $n$ = $f$_$n$;\n", "f", full_name, "n",
+             value->name());
+  }
+}
+
+void CppObjGenerator::GenClassDecl(const Descriptor* msg, Printer* p) const {
+  std::string full_name = GetFullName(msg);
+  p->Print("\nclass PERFETTO_EXPORT $n$ {\n", "n", full_name);
+  p->Print(" public:\n");
+  p->Indent();
+
+  // Do a first pass to generate aliases for nested types.
+  // e.g., using Foo = Parent_Foo;
+  for (int i = 0; i < msg->nested_type_count(); i++) {
+    const Descriptor* nested_msg = msg->nested_type(i);
+    p->Print("using $n$ = $f$;\n", "n", nested_msg->name(), "f",
+             GetFullName(nested_msg));
+  }
+  for (int i = 0; i < msg->enum_type_count(); i++) {
+    const EnumDescriptor* nested_enum = msg->enum_type(i);
+    p->Print("using $n$ = $f$;\n", "n", nested_enum->name(), "f",
+             GetFullName(nested_enum));
+    GenEnumAliases(nested_enum, p);
+  }
+
+  p->Print("$n$();\n", "n", full_name);
+  p->Print("~$n$();\n", "n", full_name);
+  p->Print("$n$($n$&&) noexcept;\n", "n", full_name);
+  p->Print("$n$& operator=($n$&&);\n", "n", full_name);
+  p->Print("$n$(const $n$&);\n", "n", full_name);
+  p->Print("$n$& operator=(const $n$&);\n", "n", full_name);
+  p->Print("bool operator==(const $n$&) const;\n", "n", full_name);
+  p->Print(
+      "bool operator!=(const $n$& other) const { return !(*this == other); }\n",
+      "n", full_name);
+  p->Print("\n");
+
+  std::string proto_type = GetFullName(msg, true);
+  p->Print("// Raw proto decoding.\n");
+  p->Print("void ParseRawProto(const std::string&);\n");
+  p->Print("// Conversion methods from/to the corresponding protobuf types.\n");
+  p->Print("void FromProto(const $p$&);\n", "p", proto_type);
+  p->Print("void ToProto($p$*) const;\n", "p", proto_type);
+
+  // Generate accessors.
+  for (int i = 0; i < msg->field_count(); i++) {
+    const FieldDescriptor* field = msg->field(i);
+    p->Print("\n");
+    if (field->options().lazy()) {
+      p->Print("const std::string& $n$_raw() const { return $n$_; }\n", "n",
+               field->lowercase_name());
+      p->Print("void set_$n$_raw(const std::string& raw) { $n$_ = raw; }\n",
+               "n", field->lowercase_name());
+    } else if (!field->is_repeated()) {
+      if (field->type() == TYPE_MESSAGE) {
+        p->Print("$t$ $n$() const { return *$n$_; }\n", "t",
+                 GetCppType(field, true), "n", field->lowercase_name());
+        p->Print("$t$* mutable_$n$() { return $n$_.get(); }\n", "t",
+                 GetCppType(field, false), "n", field->lowercase_name());
+      } else {
+        p->Print("$t$ $n$() const { return $n$_; }\n", "t",
+                 GetCppType(field, true), "n", field->lowercase_name());
+        p->Print("void set_$n$($t$ value) { $n$_ = value; }\n", "t",
+                 GetCppType(field, true), "n", field->lowercase_name());
+        if (field->type() == FieldDescriptor::TYPE_BYTES) {
+          p->Print(
+              "void set_$n$(const void* p, size_t s) { "
+              "$n$_.assign(reinterpret_cast<const char*>(p), s); }\n",
+              "n", field->lowercase_name());
+        }
+      }
+    } else {  // is_repeated()
+      p->Print(
+          "int $n$_size() const { return static_cast<int>($n$_.size()); }\n",
+          "t", GetCppType(field, false), "n", field->lowercase_name());
+      p->Print("const std::vector<$t$>& $n$() const { return $n$_; }\n", "t",
+               GetCppType(field, false), "n", field->lowercase_name());
+      p->Print("std::vector<$t$>* mutable_$n$() { return &$n$_; }\n", "t",
+               GetCppType(field, false), "n", field->lowercase_name());
+      p->Print("void clear_$n$() { $n$_.clear(); }\n", "n",
+               field->lowercase_name());
+
+      if (field->type() == TYPE_MESSAGE && !field->options().lazy()) {
+        p->Print(
+            "$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); "
+            "}\n",
+            "t", GetCppType(field, false), "n", field->lowercase_name());
+      } else {
+        p->Print(
+            "$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); }\n",
+            "t", GetCppType(field, false), "n", field->lowercase_name());
+      }
+    }
+  }
+  p->Outdent();
+  p->Print("\n private:\n");
+  p->Indent();
+
+  // Generate fields.
+  for (int i = 0; i < msg->field_count(); i++) {
+    const FieldDescriptor* field = msg->field(i);
+    if (field->options().lazy()) {
+      p->Print("std::string $n$_;  // [lazy=true]\n", "n",
+               field->lowercase_name());
+    } else if (!field->is_repeated()) {
+      std::string type = GetCppType(field, false);
+      if (field->type() == TYPE_MESSAGE) {
+        type = "::perfetto::base::CopyablePtr<" + type + ">";
+        p->Print("$t$ $n$_;\n", "t", type, "n", field->lowercase_name());
+      } else {
+        p->Print("$t$ $n$_{};\n", "t", type, "n", field->lowercase_name());
+      }
+    } else {  // is_repeated()
+      p->Print("std::vector<$t$> $n$_;\n", "t", GetCppType(field, false), "n",
+               field->lowercase_name());
+    }
+  }
+  p->Print("\n");
+  p->Print("// Allows to preserve unknown protobuf fields for compatibility\n");
+  p->Print("// with future versions of .proto files.\n");
+  p->Print("std::string unknown_fields_;\n");
+  p->Outdent();
+  p->Print("};\n\n");
+}
+
+void CppObjGenerator::GenClassDef(const Descriptor* msg, Printer* p) const {
+  p->Print("\n");
+  std::string full_name = GetFullName(msg);
+
+  p->Print("$n$::$n$() = default;\n", "n", full_name);
+  p->Print("$n$::~$n$() = default;\n", "n", full_name);
+  p->Print("$n$::$n$(const $n$&) = default;\n", "n", full_name);
+  p->Print("$n$& $n$::operator=(const $n$&) = default;\n", "n", full_name);
+  p->Print("$n$::$n$($n$&&) noexcept = default;\n", "n", full_name);
+  p->Print("$n$& $n$::operator=($n$&&) = default;\n", "n", full_name);
+
+  p->Print("\n");
+
+  // Comparison operator
+  p->Print("bool $n$::operator==(const $n$& other) const {\n", "n", full_name);
+  p->Indent();
+
+  p->Print("return unknown_fields_ == other.unknown_fields_");
+  for (int i = 0; i < msg->field_count(); i++)
+    p->Print("\n && $n$_ == other.$n$_", "n", msg->field(i)->lowercase_name());
+  p->Print(";");
+  p->Outdent();
+  p->Print("\n}\n\n");
+
+  std::string proto_type = GetFullName(msg, true);
+
+  // Genrate the ParseRawProto() method definition.
+  p->Print("void $f$::ParseRawProto(const std::string& raw) {\n", "f",
+           full_name);
+  p->Indent();
+  p->Print("$p$ proto;\n", "p", proto_type);
+  p->Print("proto.ParseFromString(raw);\n");
+  p->Print("FromProto(proto);\n");
+  p->Outdent();
+  p->Print("}\n\n");
+
+  // Genrate the FromProto() method definition.
+  p->Print("void $f$::FromProto(const $p$& proto) {\n", "f", full_name, "p",
+           proto_type);
+  p->Indent();
+  for (int i = 0; i < msg->field_count(); i++) {
+    p->Print("\n");
+    const FieldDescriptor* field = msg->field(i);
+    if (field->options().lazy()) {
+      p->Print("$n$_ = proto.$n$().SerializeAsString();\n", "n",
+               field->lowercase_name());
+    } else if (!field->is_repeated()) {
+      if (field->type() == TYPE_MESSAGE) {
+        p->Print("$n$_->FromProto(proto.$n$());\n", "n",
+                 field->lowercase_name());
+      } else {
+        p->Print(
+            "static_assert(sizeof($n$_) == sizeof(proto.$n$()), \"size "
+            "mismatch\");\n",
+            "n", field->lowercase_name());
+        p->Print("$n$_ = static_cast<decltype($n$_)>(proto.$n$());\n", "n",
+                 field->lowercase_name());
+      }
+    } else {  // is_repeated()
+      p->Print("$n$_.clear();\n", "n", field->lowercase_name());
+      p->Print("for (const auto& field : proto.$n$()) {\n", "n",
+               field->lowercase_name());
+      p->Print("  $n$_.emplace_back();\n", "n", field->lowercase_name());
+      if (field->type() == TYPE_MESSAGE) {
+        p->Print("  $n$_.back().FromProto(field);\n", "n",
+                 field->lowercase_name());
+      } else {
+        p->Print(
+            "static_assert(sizeof($n$_.back()) == sizeof(proto.$n$(0)), \"size "
+            "mismatch\");\n",
+            "n", field->lowercase_name());
+        p->Print(
+            "  $n$_.back() = static_cast<decltype($n$_)::value_type>(field);\n",
+            "n", field->lowercase_name());
+      }
+      p->Print("}\n");
+    }
+  }
+  p->Print("unknown_fields_ = proto.unknown_fields();\n");
+  p->Outdent();
+  p->Print("}\n\n");
+
+  // Genrate the ToProto() method definition.
+  p->Print("void $f$::ToProto($p$* proto) const {\n", "f", full_name, "p",
+           proto_type);
+  p->Indent();
+  p->Print("proto->Clear();\n");
+  for (int i = 0; i < msg->field_count(); i++) {
+    p->Print("\n");
+    const FieldDescriptor* field = msg->field(i);
+    if (field->options().lazy()) {
+      p->Print("proto->mutable_$n$()->ParseFromString($n$_);\n", "n",
+               field->lowercase_name());
+    } else if (!field->is_repeated()) {
+      if (field->type() == TYPE_MESSAGE) {
+        p->Print("$n$_->ToProto(proto->mutable_$n$());\n", "n",
+                 field->lowercase_name());
+      } else {
+        p->Print(
+            "static_assert(sizeof($n$_) == sizeof(proto->$n$()), \"size "
+            "mismatch\");\n",
+            "n", field->lowercase_name());
+        p->Print("proto->set_$n$(static_cast<decltype(proto->$n$())>($n$_));\n",
+                 "n", field->lowercase_name());
+      }
+    } else {  // is_repeated()
+      p->Print("for (const auto& it : $n$_) {\n", "n", field->lowercase_name());
+      if (field->type() == TYPE_MESSAGE) {
+        p->Print("  auto* entry = proto->add_$n$();\n", "n",
+                 field->lowercase_name());
+        p->Print("  it.ToProto(entry);\n");
+      } else {
+        p->Print(
+            "  proto->add_$n$(static_cast<decltype(proto->$n$(0))>(it));\n",
+            "n", field->lowercase_name());
+        p->Print(
+            "static_assert(sizeof(it) == sizeof(proto->$n$(0)), \"size "
+            "mismatch\");\n",
+            "n", field->lowercase_name());
+      }
+      p->Print("}\n");
+    }
+  }
+  p->Print("*(proto->mutable_unknown_fields()) = unknown_fields_;\n");
+  p->Outdent();
+  p->Print("}\n\n");
+}
+
+}  // namespace
+}  // namespace protozero
+
+int main(int argc, char** argv) {
+  ::protozero::CppObjGenerator generator;
+  return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index fe3ce2a..c99e665 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -151,6 +151,7 @@
     "systrace_trace_parser.h",
     "thread_table.cc",
     "thread_table.h",
+    "timestamped_trace_piece.h",
     "trace_blob_view.h",
     "trace_parser.h",
     "trace_processor.cc",
diff --git a/src/trace_processor/db/column.cc b/src/trace_processor/db/column.cc
index 91b22ef..62da919 100644
--- a/src/trace_processor/db/column.cc
+++ b/src/trace_processor/db/column.cc
@@ -66,9 +66,25 @@
     case FilterOp::kGt:
       iv->RemoveIf([this, value](uint32_t row) { return Get(row) <= value; });
       break;
-    case FilterOp::kNeq:
+    case FilterOp::kNe:
       iv->RemoveIf([this, value](uint32_t row) { return Get(row) == value; });
       break;
+    case FilterOp::kLe:
+      iv->RemoveIf([this, value](uint32_t row) { return Get(row) > value; });
+      break;
+    case FilterOp::kGe:
+      iv->RemoveIf([this, value](uint32_t row) { return Get(row) < value; });
+      break;
+    case FilterOp::kIsNull:
+      iv->RemoveIf([this](uint32_t row) {
+        return Get(row).type != SqlValue::Type::kNull;
+      });
+      break;
+    case FilterOp::kIsNotNull:
+      iv->RemoveIf([this](uint32_t row) {
+        return Get(row).type == SqlValue::Type::kNull;
+      });
+      break;
   }
 }
 
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index b545e10..e01a0da 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -32,9 +32,13 @@
 // Represents the possible filter operations on a column.
 enum class FilterOp {
   kEq,
-  kNeq,
+  kNe,
   kGt,
   kLt,
+  kGe,
+  kLe,
+  kIsNull,
+  kIsNotNull,
 };
 
 // Represents a constraint on a column.
@@ -190,8 +194,20 @@
   Constraint lt(SqlValue value) const {
     return Constraint{col_idx_, FilterOp::kLt, value};
   }
-  Constraint neq(SqlValue value) const {
-    return Constraint{col_idx_, FilterOp::kNeq, value};
+  Constraint ne(SqlValue value) const {
+    return Constraint{col_idx_, FilterOp::kNe, value};
+  }
+  Constraint ge(SqlValue value) const {
+    return Constraint{col_idx_, FilterOp::kGe, value};
+  }
+  Constraint le(SqlValue value) const {
+    return Constraint{col_idx_, FilterOp::kLe, value};
+  }
+  Constraint is_not_null() const {
+    return Constraint{col_idx_, FilterOp::kIsNotNull, SqlValue()};
+  }
+  Constraint is_null() const {
+    return Constraint{col_idx_, FilterOp::kIsNull, SqlValue()};
   }
 
   // Returns an Order for each Order type for this Column.
@@ -217,20 +233,30 @@
   base::Optional<T> GetTyped(uint32_t row) const {
     PERFETTO_DCHECK(ToColumnType<T>() == type_);
     auto idx = row_map().Get(row);
-    return static_cast<const SparseVector<T>*>(sparse_vector_)->Get(idx);
+    return sparse_vector<T>().Get(idx);
   }
 
   template <typename T>
   void SetTyped(uint32_t row, T value) {
     PERFETTO_DCHECK(ToColumnType<T>() == type_);
     auto idx = row_map().Get(row);
-    return static_cast<SparseVector<T>*>(sparse_vector_)->Set(idx, value);
+    return mutable_sparse_vector<T>()->Set(idx, value);
   }
 
   NullTermStringView GetStringPoolString(uint32_t row) const {
     return string_pool_->Get(*GetTyped<StringPool::Id>(row));
   }
 
+  template <typename T>
+  const SparseVector<T>& sparse_vector() const {
+    return *static_cast<const SparseVector<T>*>(sparse_vector_);
+  }
+
+  template <typename T>
+  SparseVector<T>* mutable_sparse_vector() {
+    return static_cast<SparseVector<T>*>(sparse_vector_);
+  }
+
   // type_ is used to cast sparse_vector_ to the correct type.
   ColumnType type_ = ColumnType::kInt64;
   void* sparse_vector_ = nullptr;
diff --git a/src/trace_processor/db/typed_column.h b/src/trace_processor/db/typed_column.h
index d07d034..7be27e2 100644
--- a/src/trace_processor/db/typed_column.h
+++ b/src/trace_processor/db/typed_column.h
@@ -34,6 +34,7 @@
 
   T operator[](uint32_t row) const { return *GetTyped<T>(row); }
   void Set(uint32_t row, T value) { SetTyped(row, value); }
+  void Append(T value) { return mutable_sparse_vector<T>()->Append(value); }
 };
 
 template <typename T>
@@ -42,6 +43,10 @@
 
   base::Optional<T> operator[](uint32_t row) const { return GetTyped<T>(row); }
   void Set(uint32_t row, T value) { SetTyped(row, value); }
+
+  void Append(base::Optional<T> value) {
+    return mutable_sparse_vector<T>()->Append(value);
+  }
 };
 
 template <>
@@ -55,6 +60,26 @@
     return GetStringPoolString(row);
   }
   void Set(uint32_t row, StringPool::Id value) { SetTyped(row, value); }
+  void Append(StringPool::Id value) {
+    return mutable_sparse_vector<StringPool::Id>()->Append(value);
+  }
+};
+
+template <>
+struct TypedColumn<base::Optional<StringPool::Id>>
+    : public TypedColumn<StringPool::Id> {
+  void Append(base::Optional<StringPool::Id> value) {
+    // Since StringPool::Id == 0 is always treated as null, rewrite
+    // base::nullopt -> 0 to remove an extra check at filter time for
+    // base::nullopt. Instead, that code can assume that the SparseVector layer
+    // always returns a valid id and can handle the nullability at the
+    // stringpool level.
+    // 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(value ? *value
+                                                     : StringPool::Id(0u));
+  }
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/event_tracker.cc b/src/trace_processor/event_tracker.cc
index 79757a9..2886c3a 100644
--- a/src/trace_processor/event_tracker.cc
+++ b/src/trace_processor/event_tracker.cc
@@ -240,7 +240,7 @@
     defn_id = definitions->AddCounterDefinition(name_id, ref, ref_type);
   }
   RowId row_id = PushCounter(timestamp, value, defn_id);
-  if (resolve_utid_to_upid) {
+  if (resolve_utid_to_upid && row_id != kInvalidRowId) {
     auto table_and_row = TraceStorage::ParseRowId(row_id);
     PendingUpidResolutionCounter pending;
     pending.row = table_and_row.second;
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 64f6644..b8960d3 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -38,6 +38,26 @@
 
 using IndexMap = perfetto::trace_processor::TraceStorage::Stats::IndexMap;
 
+const char kLegacyEventArgsKey[] = "legacy_event";
+const char kLegacyEventCategoryKey[] = "category";
+const char kLegacyEventNameKey[] = "name";
+const char kLegacyEventPhaseKey[] = "phase";
+const char kLegacyEventDurationNsKey[] = "duration_ns";
+const char kLegacyEventThreadTimestampNsKey[] = "thread_timestamp_ns";
+const char kLegacyEventThreadDurationNsKey[] = "thread_duration_ns";
+const char kLegacyEventThreadInstructionCountKey[] = "thread_instruction_count";
+const char kLegacyEventThreadInstructionDeltaKey[] = "thread_instruction_delta";
+const char kLegacyEventUseAsyncTtsKey[] = "use_async_tts";
+const char kLegacyEventGlobalIdKey[] = "global_id";
+const char kLegacyEventLocalIdKey[] = "local_id";
+const char kLegacyEventIdScopeKey[] = "id_scope";
+const char kLegacyEventBindIdKey[] = "bind_id";
+const char kLegacyEventBindToEnclosingKey[] = "bind_to_enclosing";
+const char kLegacyEventFlowDirectionKey[] = "flow_direction";
+const char kFlowDirectionValueIn[] = "in";
+const char kFlowDirectionValueOut[] = "out";
+const char kFlowDirectionValueInout[] = "inout";
+
 const char* GetNonNullString(const TraceStorage* storage, StringId id) {
   return id == kNullStringId ? "" : storage->GetString(id).c_str();
 }
@@ -267,6 +287,33 @@
   std::vector<Json::Value> args_sets_;
 };
 
+void ConvertLegacyFlowEventArgs(const Json::Value& legacy_args,
+                                Json::Value* event) {
+  if (legacy_args.isMember(kLegacyEventIdScopeKey))
+    (*event)["scope"] = legacy_args[kLegacyEventIdScopeKey];
+
+  if (legacy_args.isMember(kLegacyEventBindIdKey)) {
+    (*event)["bind_id"] =
+        PrintUint64(legacy_args[kLegacyEventBindIdKey].asUInt64());
+  }
+
+  if (legacy_args.isMember(kLegacyEventBindToEnclosingKey))
+    (*event)["bp"] = "e";
+
+  if (legacy_args.isMember(kLegacyEventFlowDirectionKey)) {
+    const char* val = legacy_args[kLegacyEventFlowDirectionKey].asCString();
+    if (strcmp(val, kFlowDirectionValueIn) == 0) {
+      (*event)["flow_in"] = true;
+    } else if (strcmp(val, kFlowDirectionValueOut) == 0) {
+      (*event)["flow_out"] = true;
+    } else {
+      PERFETTO_DCHECK(strcmp(val, kFlowDirectionValueInout) == 0);
+      (*event)["flow_in"] = true;
+      (*event)["flow_out"] = true;
+    }
+  }
+}
+
 ResultCode ExportThreadNames(const TraceStorage* storage,
                              TraceFormatWriter* writer) {
   for (UniqueTid i = 1; i < storage->thread_count(); ++i) {
@@ -304,7 +351,14 @@
     event["pid"] = 0;
     const Json::Value& args = args_builder.GetArgs(slices.arg_set_ids()[i]);
     if (!args.empty()) {
-      event["args"] = args;
+      event["args"] = args;  // Makes a copy of |args|.
+
+      if (event["args"].isMember(kLegacyEventArgsKey)) {
+        ConvertLegacyFlowEventArgs(event["args"][kLegacyEventArgsKey], &event);
+
+        if (event["args"].empty())
+          event.removeMember("args");
+      }
     }
 
     if (slices.types()[i] == RefType::kRefTrack) {  // Async event.
@@ -460,28 +514,6 @@
 Json::Value ConvertLegacyRawEventToJson(const TraceStorage* storage,
                                         const ArgsBuilder& args_builder,
                                         uint32_t index) {
-  const char kLegacyEventArgsKey[] = "legacy_event";
-  const char kLegacyEventCategoryKey[] = "category";
-  const char kLegacyEventNameKey[] = "name";
-  const char kLegacyEventPhaseKey[] = "phase";
-  const char kLegacyEventDurationNsKey[] = "duration_ns";
-  const char kLegacyEventThreadTimestampNsKey[] = "thread_timestamp_ns";
-  const char kLegacyEventThreadDurationNsKey[] = "thread_duration_ns";
-  const char kLegacyEventThreadInstructionCountKey[] =
-      "thread_instruction_count";
-  const char kLegacyEventThreadInstructionDeltaKey[] =
-      "thread_instruction_delta";
-  const char kLegacyEventUseAsyncTtsKey[] = "use_async_tts";
-  const char kLegacyEventGlobalIdKey[] = "global_id";
-  const char kLegacyEventLocalIdKey[] = "local_id";
-  const char kLegacyEventIdScopeKey[] = "id_scope";
-  const char kLegacyEventBindIdKey[] = "bind_id";
-  const char kLegacyEventBindToEnclosingKey[] = "bind_to_enclosing";
-  const char kLegacyEventFlowDirectionKey[] = "flow_direction";
-  const char kFlowDirectionValueIn[] = "in";
-  const char kFlowDirectionValueOut[] = "out";
-  const char kFlowDirectionValueInout[] = "inout";
-
   const auto& events = storage->raw_events();
 
   Json::Value event;
@@ -495,10 +527,9 @@
   }
 
   // Raw legacy events store all other params in the arg set. Make a copy of
-  // the converted args here and remove these params.
-  Json::Value args = args_builder.GetArgs(events.arg_set_ids()[index]);
-  Json::Value legacy_args = args[kLegacyEventArgsKey];
-  args.removeMember(kLegacyEventArgsKey);
+  // the converted args here, parse, and then remove the legacy params.
+  event["args"] = args_builder.GetArgs(events.arg_set_ids()[index]);
+  const Json::Value& legacy_args = event["args"][kLegacyEventArgsKey];
 
   PERFETTO_DCHECK(legacy_args.isMember(kLegacyEventCategoryKey));
   event["cat"] = legacy_args[kLegacyEventCategoryKey];
@@ -509,9 +540,8 @@
   PERFETTO_DCHECK(legacy_args.isMember(kLegacyEventPhaseKey));
   event["ph"] = legacy_args[kLegacyEventPhaseKey];
 
-  if (legacy_args.isMember(kLegacyEventDurationNsKey)) {
+  if (legacy_args.isMember(kLegacyEventDurationNsKey))
     event["dur"] = legacy_args[kLegacyEventDurationNsKey].asInt64() / 1000;
-  }
 
   if (legacy_args.isMember(kLegacyEventThreadTimestampNsKey)) {
     event["tts"] =
@@ -523,17 +553,14 @@
         legacy_args[kLegacyEventThreadDurationNsKey].asInt64() / 1000;
   }
 
-  if (legacy_args.isMember(kLegacyEventThreadInstructionCountKey)) {
+  if (legacy_args.isMember(kLegacyEventThreadInstructionCountKey))
     event["ticount"] = legacy_args[kLegacyEventThreadInstructionCountKey];
-  }
 
-  if (legacy_args.isMember(kLegacyEventThreadInstructionDeltaKey)) {
+  if (legacy_args.isMember(kLegacyEventThreadInstructionDeltaKey))
     event["tidelta"] = legacy_args[kLegacyEventThreadInstructionDeltaKey];
-  }
 
-  if (legacy_args.isMember(kLegacyEventUseAsyncTtsKey)) {
+  if (legacy_args.isMember(kLegacyEventUseAsyncTtsKey))
     event["use_async_tts"] = legacy_args[kLegacyEventUseAsyncTtsKey];
-  }
 
   if (legacy_args.isMember(kLegacyEventGlobalIdKey)) {
     event["id2"]["global"] =
@@ -545,35 +572,11 @@
         PrintUint64(legacy_args[kLegacyEventLocalIdKey].asUInt64());
   }
 
-  if (legacy_args.isMember(kLegacyEventIdScopeKey)) {
-    event["scope"] = legacy_args[kLegacyEventIdScopeKey];
-  }
+  ConvertLegacyFlowEventArgs(legacy_args, &event);
 
-  if (legacy_args.isMember(kLegacyEventBindIdKey)) {
-    event["bind_id"] =
-        PrintUint64(legacy_args[kLegacyEventBindIdKey].asUInt64());
-  }
-
-  if (legacy_args.isMember(kLegacyEventBindToEnclosingKey)) {
-    event["bp"] = "e";
-  }
-
-  if (legacy_args.isMember(kLegacyEventFlowDirectionKey)) {
-    const char* val = legacy_args[kLegacyEventFlowDirectionKey].asCString();
-    if (strcmp(val, kFlowDirectionValueIn) == 0) {
-      event["flow_in"] = true;
-    } else if (strcmp(val, kFlowDirectionValueOut) == 0) {
-      event["flow_out"] = true;
-    } else {
-      PERFETTO_DCHECK(strcmp(val, kFlowDirectionValueInout) == 0);
-      event["flow_in"] = true;
-      event["flow_out"] = true;
-    }
-  }
-
-  if (!args.empty()) {
-    event["args"] = args;
-  }
+  event["args"].removeMember(kLegacyEventArgsKey);
+  if (event["args"].empty())
+    event.removeMember("args");
 
   return event;
 }
@@ -655,8 +658,12 @@
                       frames.mappings()[frame_id] < mappings.size());
       size_t mapping_id = static_cast<size_t>(frames.mappings()[frame_id]);
 
-      NullTermStringView symbol_name =
-          storage->GetString(frames.names()[frame_id]);
+      NullTermStringView symbol_name;
+      uint32_t symbol_set_id = frames.symbol_set_ids()[frame_id];
+      if (symbol_set_id) {
+        symbol_name =
+            storage->GetString(storage->symbol_table().name()[symbol_set_id]);
+      }
 
       char frame_entry[1024];
       snprintf(
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 511f677..51e1b57 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -104,6 +104,7 @@
   EXPECT_EQ(event["name"].asString(), kName);
   EXPECT_FALSE(event.isMember("args"));
 }
+
 TEST(ExportJsonTest, StorageWithOneUnfinishedSlice) {
   const int64_t kTimestamp = 10000000;
   const int64_t kDuration = -1;
@@ -381,6 +382,63 @@
   EXPECT_EQ(event["args"]["src"].asString(), kSrc);
 }
 
+TEST(ExportJsonTest, StorageWithSliceAndFlowEventArgs) {
+  const char* kCategory = "cat";
+  const char* kName = "name";
+  constexpr TrackId track = 22;
+  const uint64_t kBindId = 0xaa00aa00aa00aa00;
+  const char* kFlowDirection = "inout";
+  const char* kArgName = "arg_name";
+  const int kArgValue = 123;
+
+  TraceProcessorContext context;
+  context.storage.reset(new TraceStorage());
+  TraceStorage* storage = context.storage.get();
+
+  UniqueTid utid = storage->AddEmptyThread(0);
+  StringId cat_id = storage->InternString(base::StringView(kCategory));
+  StringId name_id = storage->InternString(base::StringView(kName));
+  RowId row_id = TraceStorage::CreateRowId(
+      kNestableSlices,
+      storage->mutable_nestable_slices()->AddSlice(
+          0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0));
+
+  ArgsTracker args(&context);
+  auto add_arg = [&](const char* key, Variadic value) {
+    StringId key_id = storage->InternString(key);
+    args.AddArg(row_id, key_id, key_id, value);
+  };
+
+  add_arg("legacy_event.bind_id", Variadic::UnsignedInteger(kBindId));
+  add_arg("legacy_event.bind_to_enclosing", Variadic::Boolean(true));
+  StringId flow_direction_id = storage->InternString(kFlowDirection);
+  add_arg("legacy_event.flow_direction", Variadic::String(flow_direction_id));
+
+  add_arg(kArgName, Variadic::Integer(kArgValue));
+
+  args.Flush();
+
+  base::TempFile temp_file = base::TempFile::Create();
+  FILE* output = fopen(temp_file.path().c_str(), "w+");
+  int code = ExportJson(storage, output);
+
+  EXPECT_EQ(code, kResultOk);
+
+  Json::Reader reader;
+  Json::Value result;
+  EXPECT_TRUE(reader.parse(ReadFile(output), result));
+  EXPECT_EQ(result["traceEvents"].size(), 1u);
+
+  Json::Value event = result["traceEvents"][0];
+  EXPECT_EQ(event["cat"].asString(), kCategory);
+  EXPECT_EQ(event["name"].asString(), kName);
+  EXPECT_EQ(event["bind_id"].asString(), "0xaa00aa00aa00aa00");
+  EXPECT_EQ(event["bp"].asString(), "e");
+  EXPECT_EQ(event["flow_in"].asBool(), true);
+  EXPECT_EQ(event["flow_out"].asBool(), true);
+  EXPECT_EQ(event["args"][kArgName].asInt(), kArgValue);
+}
+
 TEST(ExportJsonTest, StorageWithListArgs) {
   const char* kCategory = "cat";
   const char* kName = "name";
@@ -1016,11 +1074,27 @@
       {storage->InternString("bar_module_id"), 0, 0, 0, 0, 0,
        storage->InternString("bar_module_name")});
 
+  // 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});
+
   RowId frame_row_id_1 = storage->mutable_stack_profile_frames()->Insert(
-      {storage->InternString("foo_func"), module_row_id_1, 0x42});
+      {/*name_id=*/0, module_row_id_1, 0x42});
+  uint32_t symbol_set_id = storage->symbol_table().size();
+  storage->mutable_symbol_table()->Insert(
+      {symbol_set_id, storage->InternString("foo_func"),
+       storage->InternString("foo_file"), 66});
+  storage->mutable_stack_profile_frames()->SetSymbolSetId(
+      static_cast<size_t>(frame_row_id_1), symbol_set_id);
 
   RowId frame_row_id_2 = storage->mutable_stack_profile_frames()->Insert(
-      {storage->InternString("bar_func"), module_row_id_2, 0x4242});
+      {/*name_id=*/0, module_row_id_2, 0x4242});
+  symbol_set_id = storage->symbol_table().size();
+  storage->mutable_symbol_table()->Insert(
+      {symbol_set_id, storage->InternString("bar_func"),
+       storage->InternString("bar_file"), 77});
+  storage->mutable_stack_profile_frames()->SetSymbolSetId(
+      static_cast<size_t>(frame_row_id_2), symbol_set_id);
 
   RowId frame_callsite_id_1 =
       storage->mutable_stack_profile_callsites()->Insert(
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
index 5f6a99f..765b0a5 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -24,6 +24,7 @@
 #include "src/trace_processor/proto_trace_parser.h"
 #include "src/trace_processor/proto_trace_tokenizer.h"
 #include "src/trace_processor/systrace_trace_parser.h"
+#include "src/trace_processor/trace_sorter.h"
 
 // JSON parsing and exporting is only supported in the standalone and
 // Chromium builds.
diff --git a/src/trace_processor/fuchsia_trace_parser.cc b/src/trace_processor/fuchsia_trace_parser.cc
index 15ce4d7..3423db9 100644
--- a/src/trace_processor/fuchsia_trace_parser.cc
+++ b/src/trace_processor/fuchsia_trace_parser.cc
@@ -63,13 +63,11 @@
 
 void FuchsiaTraceParser::ParseFtracePacket(uint32_t,
                                            int64_t,
-                                           TraceSorter::TimestampedTracePiece) {
+                                           TimestampedTracePiece) {
   PERFETTO_FATAL("Fuchsia Trace Parser cannot handle ftrace packets.");
 }
 
-void FuchsiaTraceParser::ParseTracePacket(
-    int64_t,
-    TraceSorter::TimestampedTracePiece ttp) {
+void FuchsiaTraceParser::ParseTracePacket(int64_t, TimestampedTracePiece ttp) {
   PERFETTO_DCHECK(ttp.fuchsia_provider_view != nullptr);
 
   // The timestamp is also present in the record, so we'll ignore the one passed
diff --git a/src/trace_processor/fuchsia_trace_parser.h b/src/trace_processor/fuchsia_trace_parser.h
index 67cc95b..8992ce6 100644
--- a/src/trace_processor/fuchsia_trace_parser.h
+++ b/src/trace_processor/fuchsia_trace_parser.h
@@ -18,6 +18,7 @@
 #define SRC_TRACE_PROCESSOR_FUCHSIA_TRACE_PARSER_H_
 
 #include "src/trace_processor/fuchsia_provider_view.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_parser.h"
 
 namespace perfetto {
@@ -31,11 +32,8 @@
   ~FuchsiaTraceParser() override;
 
   // TraceParser implementation
-  void ParseTracePacket(int64_t timestamp,
-                        TraceSorter::TimestampedTracePiece) override;
-  void ParseFtracePacket(uint32_t,
-                         int64_t,
-                         TraceSorter::TimestampedTracePiece) override;
+  void ParseTracePacket(int64_t timestamp, TimestampedTracePiece) override;
+  void ParseFtracePacket(uint32_t, int64_t, TimestampedTracePiece) override;
 
  private:
   TraceProcessorContext* const context_;
diff --git a/src/trace_processor/graphics_event_parser.cc b/src/trace_processor/graphics_event_parser.cc
index 7265028..3276db8 100644
--- a/src/trace_processor/graphics_event_parser.cc
+++ b/src/trace_processor/graphics_event_parser.cc
@@ -456,6 +456,8 @@
           vulkan_memory_event_row);
 
   if (vulkan_memory_event.has_annotations()) {
+    auto global_row_id =
+        TraceStorage::CreateRowId(TableId::kVulkanMemoryAllocation, row_id);
     for (auto itt = vulkan_memory_event.annotations(); itt; ++itt) {
       protos::pbzero::VulkanMemoryEventAnnotation::Decoder annotation(
           itt->data(), itt->size());
@@ -463,17 +465,17 @@
           *(context_->vulkan_memory_tracker->FindString(annotation.key_iid()));
       if (annotation.has_int_value()) {
         context_->args_tracker->AddArg(
-            row_id, annotation_id, annotation_id,
+            global_row_id, annotation_id, annotation_id,
             Variadic::Integer(annotation.int_value()));
 
       } else if (annotation.has_double_value()) {
         context_->args_tracker->AddArg(
-            row_id, annotation_id, annotation_id,
+            global_row_id, annotation_id, annotation_id,
             Variadic::Real(annotation.double_value()));
 
       } else if (annotation.has_string_iid()) {
         context_->args_tracker->AddArg(
-            row_id, annotation_id, annotation_id,
+            global_row_id, annotation_id, annotation_id,
             Variadic::String(*(context_->vulkan_memory_tracker->FindString(
                 annotation.string_iid()))));
       }
diff --git a/src/trace_processor/heap_graph_tracker.cc b/src/trace_processor/heap_graph_tracker.cc
index 57502e3..bd60ffa 100644
--- a/src/trace_processor/heap_graph_tracker.cc
+++ b/src/trace_processor/heap_graph_tracker.cc
@@ -22,20 +22,34 @@
 HeapGraphTracker::HeapGraphTracker(TraceProcessorContext* context)
     : context_(context) {}
 
-void HeapGraphTracker::AddObject(UniquePid upid, int64_t ts, SourceObject obj) {
+bool HeapGraphTracker::SetPidAndTimestamp(UniquePid upid, int64_t ts) {
   if (current_upid_ != 0 && current_upid_ != upid) {
     context_->storage->IncrementStats(stats::heap_graph_non_finalized_graph);
-    return;
+    return false;
   }
   if (current_ts_ != 0 && current_ts_ != ts) {
     context_->storage->IncrementStats(stats::heap_graph_non_finalized_graph);
-    return;
+    return false;
   }
   current_upid_ = upid;
   current_ts_ = ts;
+  return true;
+}
+
+void HeapGraphTracker::AddObject(UniquePid upid, int64_t ts, SourceObject obj) {
+  if (!SetPidAndTimestamp(upid, ts))
+    return;
+
   current_objects_.emplace_back(std::move(obj));
 }
 
+void HeapGraphTracker::AddRoot(UniquePid upid, int64_t ts, SourceRoot root) {
+  if (!SetPidAndTimestamp(upid, ts))
+    return;
+
+  current_roots_.emplace_back(std::move(root));
+}
+
 void HeapGraphTracker::AddInternedTypeName(uint64_t intern_id,
                                            StringPool::Id strid) {
   interned_type_names_.emplace(intern_id, strid);
@@ -66,7 +80,7 @@
     }
     context_->storage->mutable_heap_graph_object_table()->Insert(
         {current_upid_, current_ts_, static_cast<int64_t>(obj.object_id),
-         static_cast<int64_t>(obj.self_size), -1, it->second});
+         static_cast<int64_t>(obj.self_size), -1, it->second, base::nullopt});
     object_id_to_row_.emplace(
         obj.object_id, context_->storage->heap_graph_object_table().size() - 1);
   }
@@ -106,10 +120,26 @@
         ->mutable_reference_set_id()
         ->Set(static_cast<uint32_t>(owner_row), reference_set_id);
   }
+
+  for (const SourceRoot& root : current_roots_) {
+    for (uint64_t obj_id : root.object_ids) {
+      auto it = object_id_to_row_.find(obj_id);
+      // This can only happen for an invalid type string id, which is already
+      // reported as an error. Silently continue here.
+      if (it == object_id_to_row_.end())
+        continue;
+
+      int64_t obj_row = it->second;
+      context_->storage->mutable_heap_graph_object_table()
+          ->mutable_root_type()
+          ->Set(static_cast<uint32_t>(obj_row), root.root_type);
+    }
+  }
   interned_field_names_.clear();
   object_id_to_row_.clear();
   interned_type_names_.clear();
   current_objects_.clear();
+  current_roots_.clear();
   current_upid_ = 0;
   current_ts_ = 0;
 }
diff --git a/src/trace_processor/heap_graph_tracker.h b/src/trace_processor/heap_graph_tracker.h
index c65a7b1..7d0ec6a 100644
--- a/src/trace_processor/heap_graph_tracker.h
+++ b/src/trace_processor/heap_graph_tracker.h
@@ -46,8 +46,14 @@
     std::vector<Reference> references;
   };
 
+  struct SourceRoot {
+    StringPool::Id root_type;
+    std::vector<uint64_t> object_ids;
+  };
+
   explicit HeapGraphTracker(TraceProcessorContext* context);
 
+  void AddRoot(UniquePid upid, int64_t ts, SourceRoot root);
   void AddObject(UniquePid upid, int64_t ts, SourceObject obj);
   void AddInternedTypeName(uint64_t intern_id, StringPool::Id strid);
   void AddInternedFieldName(uint64_t intern_id, StringPool::Id strid);
@@ -55,11 +61,13 @@
   void SetPacketIndex(uint64_t index);
 
  private:
+  bool SetPidAndTimestamp(UniquePid upid, int64_t ts);
   TraceProcessorContext* const context_;
 
   UniquePid current_upid_ = 0;
   int64_t current_ts_ = 0;
   std::vector<SourceObject> current_objects_;
+  std::vector<SourceRoot> current_roots_;
   std::map<uint64_t, StringPool::Id> interned_type_names_;
   std::map<uint64_t, StringPool::Id> interned_field_names_;
   std::map<uint64_t, int64_t> object_id_to_row_;
diff --git a/src/trace_processor/json_trace_parser.cc b/src/trace_processor/json_trace_parser.cc
index 54a548f..2216eab 100644
--- a/src/trace_processor/json_trace_parser.cc
+++ b/src/trace_processor/json_trace_parser.cc
@@ -45,12 +45,12 @@
 
 void JsonTraceParser::ParseFtracePacket(uint32_t,
                                         int64_t,
-                                        TraceSorter::TimestampedTracePiece) {
+                                        TimestampedTracePiece) {
   PERFETTO_FATAL("Json Trace Parser cannot handle ftrace packets.");
 }
 
 void JsonTraceParser::ParseTracePacket(int64_t timestamp,
-                                       TraceSorter::TimestampedTracePiece ttp) {
+                                       TimestampedTracePiece ttp) {
   PERFETTO_DCHECK(ttp.json_value != nullptr);
   const Json::Value& value = *(ttp.json_value);
 
diff --git a/src/trace_processor/json_trace_parser.h b/src/trace_processor/json_trace_parser.h
index 9850924..bf0d5a5 100644
--- a/src/trace_processor/json_trace_parser.h
+++ b/src/trace_processor/json_trace_parser.h
@@ -23,8 +23,8 @@
 #include <tuple>
 #include <unordered_map>
 
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_parser.h"
-#include "src/trace_processor/trace_sorter.h"
 #include "src/trace_processor/trace_storage.h"
 
 namespace Json {
@@ -47,11 +47,8 @@
   ~JsonTraceParser() override;
 
   // TraceParser implementation.
-  void ParseTracePacket(int64_t timestamp,
-                        TraceSorter::TimestampedTracePiece) override;
-  void ParseFtracePacket(uint32_t,
-                         int64_t,
-                         TraceSorter::TimestampedTracePiece) override;
+  void ParseTracePacket(int64_t timestamp, TimestampedTracePiece) override;
+  void ParseFtracePacket(uint32_t, int64_t, TimestampedTracePiece) override;
 
  private:
   TraceProcessorContext* const context_;
diff --git a/src/trace_processor/json_trace_tokenizer.h b/src/trace_processor/json_trace_tokenizer.h
index 499342a..e5a1254 100644
--- a/src/trace_processor/json_trace_tokenizer.h
+++ b/src/trace_processor/json_trace_tokenizer.h
@@ -20,7 +20,6 @@
 #include <stdint.h>
 
 #include "src/trace_processor/chunked_trace_reader.h"
-#include "src/trace_processor/trace_sorter.h"
 #include "src/trace_processor/trace_storage.h"
 
 namespace Json {
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 0e15fc5..5a766d2 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -41,6 +41,7 @@
 #include "src/trace_processor/stack_profile_tracker.h"
 #include "src/trace_processor/syscall_tracker.h"
 #include "src/trace_processor/systrace_parser.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_processor_context.h"
 #include "src/trace_processor/track_tracker.h"
 #include "src/trace_processor/variadic.h"
@@ -205,6 +206,43 @@
 constexpr int64_t kPendingThreadInstructionDelta = -1;
 }  // namespace
 
+const char* HeapGraphRootTypeToString(int32_t type) {
+  switch (type) {
+    case protos::pbzero::HeapGraphRoot::ROOT_UNKNOWN:
+      return "ROOT_UNKNOWN";
+    case protos::pbzero::HeapGraphRoot::ROOT_JNI_GLOBAL:
+      return "ROOT_JNI_GLOBAL";
+    case protos::pbzero::HeapGraphRoot::ROOT_JNI_LOCAL:
+      return "ROOT_JNI_LOCAL";
+    case protos::pbzero::HeapGraphRoot::ROOT_JAVA_FRAME:
+      return "ROOT_JAVA_FRAME";
+    case protos::pbzero::HeapGraphRoot::ROOT_NATIVE_STACK:
+      return "ROOT_NATIVE_STACK";
+    case protos::pbzero::HeapGraphRoot::ROOT_STICKY_CLASS:
+      return "ROOT_STICKY_CLASS";
+    case protos::pbzero::HeapGraphRoot::ROOT_THREAD_BLOCK:
+      return "ROOT_THREAD_BLOCK";
+    case protos::pbzero::HeapGraphRoot::ROOT_MONITOR_USED:
+      return "ROOT_MONITOR_USED";
+    case protos::pbzero::HeapGraphRoot::ROOT_THREAD_OBJECT:
+      return "ROOT_THREAD_OBJECT";
+    case protos::pbzero::HeapGraphRoot::ROOT_INTERNED_STRING:
+      return "ROOT_INTERNED_STRING";
+    case protos::pbzero::HeapGraphRoot::ROOT_FINALIZING:
+      return "ROOT_FINALIZING";
+    case protos::pbzero::HeapGraphRoot::ROOT_DEBUGGER:
+      return "ROOT_DEBUGGER";
+    case protos::pbzero::HeapGraphRoot::ROOT_REFERENCE_CLEANUP:
+      return "ROOT_REFERENCE_CLEANUP";
+    case protos::pbzero::HeapGraphRoot::ROOT_VM_INTERNAL:
+      return "ROOT_VM_INTERNAL";
+    case protos::pbzero::HeapGraphRoot::ROOT_JNI_MONITOR:
+      return "ROOT_JNI_MONITOR";
+    default:
+      return "ROOT_UNKNOWN";
+  }
+}
+
 }  // namespace
 
 ProtoTraceParser::ProtoTraceParser(TraceProcessorContext* context)
@@ -394,9 +432,7 @@
 
 ProtoTraceParser::~ProtoTraceParser() = default;
 
-void ProtoTraceParser::ParseTracePacket(
-    int64_t ts,
-    TraceSorter::TimestampedTracePiece ttp) {
+void ProtoTraceParser::ParseTracePacket(int64_t ts, TimestampedTracePiece ttp) {
   PERFETTO_DCHECK(ttp.json_value == nullptr);
   const TraceBlobView& blob = ttp.blob_view;
 
@@ -677,14 +713,13 @@
   }
 }
 
-void ProtoTraceParser::ParseFtracePacket(
-    uint32_t cpu,
-    int64_t ts,
-    TraceSorter::TimestampedTracePiece ttp) {
+void ProtoTraceParser::ParseFtracePacket(uint32_t cpu,
+                                         int64_t ts,
+                                         TimestampedTracePiece ttp) {
   PERFETTO_DCHECK(ttp.json_value == nullptr);
 
   // Handle the (optional) alternative encoding format for sched_switch.
-  if (ttp.inline_event.type == TraceSorter::InlineEvent::Type::kSchedSwitch) {
+  if (ttp.inline_event.type == InlineEvent::Type::kSchedSwitch) {
     const auto& event = ttp.inline_event.sched_switch;
     context_->event_tracker->PushSchedSwitchCompact(
         cpu, ts, event.prev_state, static_cast<uint32_t>(event.next_pid),
@@ -1852,7 +1887,7 @@
     }
   }
 
-  auto args_callback = [this, &event, &sequence_state,
+  auto args_callback = [this, &event, &legacy_event, &sequence_state,
                         sequence_state_generation, ts,
                         utid](ArgsTracker* args_tracker, RowId row_id) {
     for (auto it = event.debug_annotations(); it; ++it) {
@@ -1870,6 +1905,42 @@
                       sequence_state_generation, ts, utid, args_tracker,
                       row_id);
     }
+
+    // TODO(eseckler): Parse legacy flow events into flow events table once we
+    // have a design for it.
+    if (legacy_event.has_bind_id()) {
+      args_tracker->AddArg(row_id, legacy_event_bind_id_key_id_,
+                           legacy_event_bind_id_key_id_,
+                           Variadic::UnsignedInteger(legacy_event.bind_id()));
+    }
+
+    if (legacy_event.bind_to_enclosing()) {
+      args_tracker->AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
+                           legacy_event_bind_to_enclosing_key_id_,
+                           Variadic::Boolean(true));
+    }
+
+    if (legacy_event.flow_direction()) {
+      StringId value;
+      switch (legacy_event.flow_direction()) {
+        case protos::pbzero::TrackEvent::LegacyEvent::FLOW_IN:
+          value = flow_direction_value_in_id_;
+          break;
+        case protos::pbzero::TrackEvent::LegacyEvent::FLOW_OUT:
+          value = flow_direction_value_out_id_;
+          break;
+        case protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT:
+          value = flow_direction_value_inout_id_;
+          break;
+        default:
+          PERFETTO_FATAL("Unknown flow direction: %d",
+                         legacy_event.flow_direction());
+          break;
+      }
+      args_tracker->AddArg(row_id, legacy_event_flow_direction_key_id_,
+                           legacy_event_flow_direction_key_id_,
+                           Variadic::String(value));
+    }
   };
 
   switch (static_cast<char>(phase)) {
@@ -2091,8 +2162,6 @@
     StringId name_id,
     const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
     SliceTracker::SetArgsCallback args_callback) {
-  using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
-
   if (!utid) {
     context_->storage->IncrementStats(stats::track_event_parser_errors);
     PERFETTO_DLOG("raw legacy event without thread association");
@@ -2170,41 +2239,6 @@
                     context_->storage->InternString(legacy_event.id_scope())));
   }
 
-  // TODO(eseckler): Parse legacy flow events into flow events table once we
-  // have a design for it.
-  if (legacy_event.has_bind_id()) {
-    args.AddArg(row_id, legacy_event_bind_id_key_id_,
-                legacy_event_bind_id_key_id_,
-                Variadic::UnsignedInteger(legacy_event.bind_id()));
-  }
-
-  if (legacy_event.bind_to_enclosing()) {
-    args.AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
-                legacy_event_bind_to_enclosing_key_id_,
-                Variadic::Boolean(true));
-  }
-
-  if (legacy_event.flow_direction()) {
-    StringId value;
-    switch (legacy_event.flow_direction()) {
-      case LegacyEvent::FLOW_IN:
-        value = flow_direction_value_in_id_;
-        break;
-      case LegacyEvent::FLOW_OUT:
-        value = flow_direction_value_out_id_;
-        break;
-      case LegacyEvent::FLOW_INOUT:
-        value = flow_direction_value_inout_id_;
-        break;
-      default:
-        PERFETTO_FATAL("Unknown flow direction: %d",
-                       legacy_event.flow_direction());
-        break;
-    }
-    args.AddArg(row_id, legacy_event_flow_direction_key_id_,
-                legacy_event_flow_direction_key_id_, Variadic::String(value));
-  }
-
   // No need to parse legacy_event.instant_event_scope() because we import
   // instant events into the slice table.
 
@@ -2687,6 +2721,17 @@
     context_->heap_graph_tracker->AddInternedFieldName(
         entry.iid(), context_->storage->InternString(str_view));
   }
+  for (auto it = heap_graph.roots(); it; ++it) {
+    protos::pbzero::HeapGraphRoot::Decoder entry(it->data(), it->size());
+    const char* str = HeapGraphRootTypeToString(entry.root_type());
+    auto str_view = base::StringView(str);
+
+    HeapGraphTracker::SourceRoot src_root;
+    src_root.root_type = context_->storage->InternString(str_view);
+    for (auto obj_it = entry.object_ids(); obj_it; ++obj_it)
+      src_root.object_ids.emplace_back(obj_it->as_uint64());
+    context_->heap_graph_tracker->AddRoot(upid, ts, std::move(src_root));
+  }
   if (!heap_graph.continued()) {
     context_->heap_graph_tracker->FinalizeProfile();
   }
diff --git a/src/trace_processor/proto_trace_parser.h b/src/trace_processor/proto_trace_parser.h
index 15f841e..7416702 100644
--- a/src/trace_processor/proto_trace_parser.h
+++ b/src/trace_processor/proto_trace_parser.h
@@ -29,10 +29,12 @@
 #include "src/trace_processor/graphics_event_parser.h"
 #include "src/trace_processor/proto_incremental_state.h"
 #include "src/trace_processor/slice_tracker.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_blob_view.h"
 #include "src/trace_processor/trace_parser.h"
 #include "src/trace_processor/trace_storage.h"
 
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
 
 namespace perfetto {
@@ -48,11 +50,10 @@
   ~ProtoTraceParser() override;
 
   // TraceParser implementation.
-  void ParseTracePacket(int64_t timestamp,
-                        TraceSorter::TimestampedTracePiece) override;
+  void ParseTracePacket(int64_t timestamp, TimestampedTracePiece) override;
   void ParseFtracePacket(uint32_t cpu,
                          int64_t timestamp,
-                         TraceSorter::TimestampedTracePiece) override;
+                         TimestampedTracePiece) override;
 
   void ParseProcessTree(ConstBytes);
   void ParseProcessStats(int64_t timestamp, ConstBytes);
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index fd52a0e..f17de27 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -949,6 +949,10 @@
     legacy_event->set_duration_us(23);               // absolute end: 1028.
     legacy_event->set_thread_duration_us(12);        // absolute end: 2015.
     legacy_event->set_thread_instruction_delta(50);  // absolute end: 3060.
+    legacy_event->set_bind_id(9999);
+    legacy_event->set_bind_to_enclosing(true);
+    legacy_event->set_flow_direction(
+        protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT);
 
     auto* interned_data = packet->set_interned_data();
     auto cat2 = interned_data->add_event_categories();
@@ -990,12 +994,17 @@
 
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
+  RowId first_slice_row_id =
+      TraceStorage::CreateRowId(TableId::kNestableSlices, 3u);
   EXPECT_CALL(*slice_, Scoped(1005000, thread_1_track, 1, RefType::kRefUtid,
                               StringId(1), StringId(2), 23000, _))
-      .WillOnce(DoAll(
-          InvokeArgument<7>(
-              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
-          Return(0u)));
+      .WillOnce(
+          DoAll(InvokeArgument<7>(&args, first_slice_row_id), Return(0u)));
+
+  EXPECT_CALL(
+      args, AddArg(first_slice_row_id, _, _, Variadic::UnsignedInteger(9999u)));
+  EXPECT_CALL(args, AddArg(first_slice_row_id, _, _, Variadic::Boolean(true)));
+  EXPECT_CALL(args, AddArg(first_slice_row_id, _, _, _));
 
   EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, 1, RefType::kRefUtid,
                              StringId(3), StringId(4), _))
diff --git a/src/trace_processor/proto_trace_tokenizer.cc b/src/trace_processor/proto_trace_tokenizer.cc
index e27ae54..70b6c0b 100644
--- a/src/trace_processor/proto_trace_tokenizer.cc
+++ b/src/trace_processor/proto_trace_tokenizer.cc
@@ -803,7 +803,7 @@
   auto comm_it = compact.switch_next_comm_index(&parse_error);
   for (; timestamp_it && pstate_it && npid_it && nprio_it && comm_it;
        ++timestamp_it, ++pstate_it, ++npid_it, ++nprio_it, ++comm_it) {
-    TraceSorter::InlineSchedSwitch event{};
+    InlineSchedSwitch event{};
 
     // delta-encoded timestamp
     timestamp_acc += static_cast<int64_t>(*timestamp_it);
@@ -817,8 +817,8 @@
     event.next_pid = *npid_it;
     event.next_prio = *nprio_it;
 
-    context_->sorter->PushInlineFtraceEvent(
-        cpu, event_timestamp, TraceSorter::InlineEvent::SchedSwitch(event));
+    context_->sorter->PushInlineFtraceEvent(cpu, event_timestamp,
+                                            InlineEvent::SchedSwitch(event));
   }
 
   // Check that all packed buffers were decoded correctly, and fully.
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index 341b1f7..dc176d6 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -32,8 +32,17 @@
       return FilterOp::kGt;
     case SQLITE_INDEX_CONSTRAINT_LT:
       return FilterOp::kLt;
+    case SQLITE_INDEX_CONSTRAINT_ISNOT:
     case SQLITE_INDEX_CONSTRAINT_NE:
-      return FilterOp::kNeq;
+      return FilterOp::kNe;
+    case SQLITE_INDEX_CONSTRAINT_GE:
+      return FilterOp::kGe;
+    case SQLITE_INDEX_CONSTRAINT_LE:
+      return FilterOp::kLe;
+    case SQLITE_INDEX_CONSTRAINT_ISNULL:
+      return FilterOp::kIsNull;
+    case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
+      return FilterOp::kIsNotNull;
     default:
       PERFETTO_FATAL("Currently unsupported constraint");
   }
diff --git a/src/trace_processor/tables/macros_internal.h b/src/trace_processor/tables/macros_internal.h
index 70068ac..b92a88f 100644
--- a/src/trace_processor/tables/macros_internal.h
+++ b/src/trace_processor/tables/macros_internal.h
@@ -190,7 +190,7 @@
 
 // Inserts the value into the corresponding column
 #define PERFETTO_TP_COLUMN_APPEND(type, name, ...) \
-  name##_.Append(std::move(row.name));
+  mutable_##name()->Append(std::move(row.name));
 
 // Defines the accessors for a column.
 #define PERFETTO_TP_TABLE_COL_ACCESSOR(type, name, ...)       \
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index 16133d8..c81ec7c 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -41,7 +41,8 @@
   C(int64_t, object_id)                                    \
   C(int64_t, self_size)                                    \
   C(int64_t, reference_set_id)                             \
-  C(StringPool::Id, type_name)
+  C(StringPool::Id, type_name)                             \
+  C(base::Optional<StringPool::Id>, root_type)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF);
 
diff --git a/src/trace_processor/timestamped_trace_piece.h b/src/trace_processor/timestamped_trace_piece.h
new file mode 100644
index 0000000..1a4f346
--- /dev/null
+++ b/src/trace_processor/timestamped_trace_piece.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
+#define SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/fuchsia_provider_view.h"
+#include "src/trace_processor/proto_incremental_state.h"
+#include "src/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/trace_storage.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
+#include <json/value.h>
+#else
+// Json traces are only supported in standalone and Chromium builds.
+namespace Json {
+class Value {};
+}  // namespace Json
+#endif
+
+namespace perfetto {
+namespace trace_processor {
+
+struct InlineSchedSwitch {
+  int64_t prev_state;
+  int32_t next_pid;
+  int32_t next_prio;
+  StringId next_comm;
+};
+
+// Discriminated union of events that are cannot be easily read from the
+// mapped trace.
+struct InlineEvent {
+  enum class Type { kInvalid = 0, kSchedSwitch };
+
+  static InlineEvent SchedSwitch(InlineSchedSwitch content) {
+    InlineEvent evt;
+    evt.type = Type::kSchedSwitch;
+    evt.sched_switch = content;
+    return evt;
+  }
+
+  Type type = Type::kInvalid;
+  union {
+    InlineSchedSwitch sched_switch;
+  };
+};
+
+// A TimestampedTracePiece is (usually a reference to) a piece of a trace that
+// is sorted by TraceSorter.
+struct TimestampedTracePiece {
+  TimestampedTracePiece(
+      int64_t ts,
+      uint64_t idx,
+      TraceBlobView tbv,
+      ProtoIncrementalState::PacketSequenceState* sequence_state)
+      : TimestampedTracePiece(ts,
+                              /*thread_ts=*/0,
+                              /*thread_instructions=*/0,
+                              idx,
+                              std::move(tbv),
+                              /*value=*/nullptr,
+                              /*fpv=*/nullptr,
+                              /*sequence_state=*/sequence_state,
+                              InlineEvent{}) {}
+
+  TimestampedTracePiece(int64_t ts, uint64_t idx, TraceBlobView tbv)
+      : TimestampedTracePiece(ts,
+                              /*thread_ts=*/0,
+                              /*thread_instructions=*/0,
+                              idx,
+                              std::move(tbv),
+                              /*value=*/nullptr,
+                              /*fpv=*/nullptr,
+                              /*sequence_state=*/nullptr,
+                              InlineEvent{}) {}
+
+  TimestampedTracePiece(int64_t ts,
+                        uint64_t idx,
+                        std::unique_ptr<Json::Value> value)
+      : TimestampedTracePiece(ts,
+                              /*thread_ts=*/0,
+                              /*thread_instructions=*/0,
+                              idx,
+                              // TODO(dproy): Stop requiring TraceBlobView in
+                              // TimestampedTracePiece.
+                              TraceBlobView(nullptr, 0, 0),
+                              std::move(value),
+                              /*fpv=*/nullptr,
+                              /*sequence_state=*/nullptr,
+                              InlineEvent{}) {}
+
+  TimestampedTracePiece(int64_t ts,
+                        uint64_t idx,
+                        TraceBlobView tbv,
+                        std::unique_ptr<FuchsiaProviderView> fpv)
+      : TimestampedTracePiece(ts,
+                              /*thread_ts=*/0,
+                              /*thread_instructions=*/0,
+                              idx,
+                              std::move(tbv),
+                              /*value=*/nullptr,
+                              std::move(fpv),
+                              /*sequence_state=*/nullptr,
+                              InlineEvent{}) {}
+
+  TimestampedTracePiece(
+      int64_t ts,
+      int64_t thread_ts,
+      int64_t thread_instructions,
+      uint64_t idx,
+      TraceBlobView tbv,
+      ProtoIncrementalState::PacketSequenceState* sequence_state)
+      : TimestampedTracePiece(ts,
+                              thread_ts,
+                              thread_instructions,
+                              idx,
+                              std::move(tbv),
+                              /*value=*/nullptr,
+                              /*fpv=*/nullptr,
+                              sequence_state,
+                              InlineEvent{}) {}
+
+  TimestampedTracePiece(int64_t ts, uint64_t idx, InlineEvent inline_evt)
+      : TimestampedTracePiece(ts,
+                              /*thread_ts=*/0,
+                              /*thread_instructions=*/0,
+                              idx,
+                              /*tbv=*/TraceBlobView(nullptr, 0, 0),
+                              /*value=*/nullptr,
+                              /*fpv=*/nullptr,
+                              /*sequence_state=*/nullptr,
+                              inline_evt) {}
+
+  TimestampedTracePiece(
+      int64_t ts,
+      int64_t thread_ts,
+      int64_t thread_instructions,
+      uint64_t idx,
+      TraceBlobView tbv,
+      std::unique_ptr<Json::Value> value,
+      std::unique_ptr<FuchsiaProviderView> fpv,
+      ProtoIncrementalState::PacketSequenceState* sequence_state,
+      InlineEvent inline_evt)
+      : json_value(std::move(value)),
+        fuchsia_provider_view(std::move(fpv)),
+        packet_sequence_state(sequence_state),
+        packet_sequence_state_generation(
+            sequence_state ? sequence_state->current_generation() : 0),
+        timestamp(ts),
+        thread_timestamp(thread_ts),
+        thread_instruction_count(thread_instructions),
+        packet_idx_(idx),
+        blob_view(std::move(tbv)),
+        inline_event(inline_evt) {}
+
+  TimestampedTracePiece(TimestampedTracePiece&&) noexcept = default;
+  TimestampedTracePiece& operator=(TimestampedTracePiece&&) = default;
+
+  // For std::lower_bound().
+  static inline bool Compare(const TimestampedTracePiece& x, int64_t ts) {
+    return x.timestamp < ts;
+  }
+
+  // For std::sort().
+  inline bool operator<(const TimestampedTracePiece& o) const {
+    return timestamp < o.timestamp ||
+           (timestamp == o.timestamp && packet_idx_ < o.packet_idx_);
+  }
+
+  std::unique_ptr<Json::Value> json_value;
+  std::unique_ptr<FuchsiaProviderView> fuchsia_provider_view;
+  ProtoIncrementalState::PacketSequenceState* packet_sequence_state;
+  size_t packet_sequence_state_generation;
+
+  int64_t timestamp;
+  int64_t thread_timestamp;
+  int64_t thread_instruction_count;
+  uint64_t packet_idx_;
+  TraceBlobView blob_view;
+  InlineEvent inline_event;
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_TIMESTAMPED_TRACE_PIECE_H_
diff --git a/src/trace_processor/trace_parser.h b/src/trace_processor/trace_parser.h
index 63c2ce1..fa3b4ef 100644
--- a/src/trace_processor/trace_parser.h
+++ b/src/trace_processor/trace_parser.h
@@ -19,7 +19,7 @@
 
 #include <stdint.h>
 
-#include "src/trace_processor/trace_sorter.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -28,11 +28,10 @@
  public:
   virtual ~TraceParser();
 
-  virtual void ParseTracePacket(int64_t timestamp,
-                                TraceSorter::TimestampedTracePiece) = 0;
+  virtual void ParseTracePacket(int64_t timestamp, TimestampedTracePiece) = 0;
   virtual void ParseFtracePacket(uint32_t cpu,
                                  int64_t timestamp,
-                                 TraceSorter::TimestampedTracePiece) = 0;
+                                 TimestampedTracePiece) = 0;
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/trace_sorter.h b/src/trace_processor/trace_sorter.h
index d0df2cf..4aababf 100644
--- a/src/trace_processor/trace_sorter.h
+++ b/src/trace_processor/trace_sorter.h
@@ -23,18 +23,14 @@
 #include "perfetto/trace_processor/basic_types.h"
 #include "src/trace_processor/fuchsia_provider_view.h"
 #include "src/trace_processor/proto_incremental_state.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_blob_view.h"
 #include "src/trace_processor/trace_processor_context.h"
 #include "src/trace_processor/trace_storage.h"
 
-#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
-#include <json/value.h>
-#else
-// Json traces are only supported in standalone and Chromium builds.
 namespace Json {
-class Value {};
+class Value;
 }  // namespace Json
-#endif
 
 namespace perfetto {
 namespace trace_processor {
@@ -68,164 +64,6 @@
 // from there to the end.
 class TraceSorter {
  public:
-  struct InlineSchedSwitch {
-    int64_t prev_state;
-    int32_t next_pid;
-    int32_t next_prio;
-    StringId next_comm;
-  };
-
-  // Discriminated union of events that are cannot be easily read from the
-  // mapped trace.
-  struct InlineEvent {
-    enum class Type { kInvalid = 0, kSchedSwitch };
-
-    static InlineEvent SchedSwitch(InlineSchedSwitch content) {
-      InlineEvent evt;
-      evt.type = Type::kSchedSwitch;
-      evt.sched_switch = content;
-      return evt;
-    }
-
-    Type type = Type::kInvalid;
-    union {
-      InlineSchedSwitch sched_switch;
-    };
-  };
-
-  struct TimestampedTracePiece {
-    TimestampedTracePiece(
-        int64_t ts,
-        uint64_t idx,
-        TraceBlobView tbv,
-        ProtoIncrementalState::PacketSequenceState* sequence_state)
-        : TimestampedTracePiece(ts,
-                                /*thread_ts=*/0,
-                                /*thread_instructions=*/0,
-                                idx,
-                                std::move(tbv),
-                                /*value=*/nullptr,
-                                /*fpv=*/nullptr,
-                                /*sequence_state=*/sequence_state,
-                                InlineEvent{}) {}
-
-    TimestampedTracePiece(int64_t ts, uint64_t idx, TraceBlobView tbv)
-        : TimestampedTracePiece(ts,
-                                /*thread_ts=*/0,
-                                /*thread_instructions=*/0,
-                                idx,
-                                std::move(tbv),
-                                /*value=*/nullptr,
-                                /*fpv=*/nullptr,
-                                /*sequence_state=*/nullptr,
-                                InlineEvent{}) {}
-
-    TimestampedTracePiece(int64_t ts,
-                          uint64_t idx,
-                          std::unique_ptr<Json::Value> value)
-        : TimestampedTracePiece(ts,
-                                /*thread_ts=*/0,
-                                /*thread_instructions=*/0,
-                                idx,
-                                // TODO(dproy): Stop requiring TraceBlobView in
-                                // TimestampedTracePiece.
-                                TraceBlobView(nullptr, 0, 0),
-                                std::move(value),
-                                /*fpv=*/nullptr,
-                                /*sequence_state=*/nullptr,
-                                InlineEvent{}) {}
-
-    TimestampedTracePiece(int64_t ts,
-                          uint64_t idx,
-                          TraceBlobView tbv,
-                          std::unique_ptr<FuchsiaProviderView> fpv)
-        : TimestampedTracePiece(ts,
-                                /*thread_ts=*/0,
-                                /*thread_instructions=*/0,
-                                idx,
-                                std::move(tbv),
-                                /*value=*/nullptr,
-                                std::move(fpv),
-                                /*sequence_state=*/nullptr,
-                                InlineEvent{}) {}
-
-    TimestampedTracePiece(
-        int64_t ts,
-        int64_t thread_ts,
-        int64_t thread_instructions,
-        uint64_t idx,
-        TraceBlobView tbv,
-        ProtoIncrementalState::PacketSequenceState* sequence_state)
-        : TimestampedTracePiece(ts,
-                                thread_ts,
-                                thread_instructions,
-                                idx,
-                                std::move(tbv),
-                                /*value=*/nullptr,
-                                /*fpv=*/nullptr,
-                                sequence_state,
-                                InlineEvent{}) {}
-
-    TimestampedTracePiece(int64_t ts, uint64_t idx, InlineEvent inline_evt)
-        : TimestampedTracePiece(ts,
-                                /*thread_ts=*/0,
-                                /*thread_instructions=*/0,
-                                idx,
-                                /*tbv=*/TraceBlobView(nullptr, 0, 0),
-                                /*value=*/nullptr,
-                                /*fpv=*/nullptr,
-                                /*sequence_state=*/nullptr,
-                                inline_evt) {}
-
-    TimestampedTracePiece(
-        int64_t ts,
-        int64_t thread_ts,
-        int64_t thread_instructions,
-        uint64_t idx,
-        TraceBlobView tbv,
-        std::unique_ptr<Json::Value> value,
-        std::unique_ptr<FuchsiaProviderView> fpv,
-        ProtoIncrementalState::PacketSequenceState* sequence_state,
-        InlineEvent inline_evt)
-        : json_value(std::move(value)),
-          fuchsia_provider_view(std::move(fpv)),
-          packet_sequence_state(sequence_state),
-          packet_sequence_state_generation(
-              sequence_state ? sequence_state->current_generation() : 0),
-          timestamp(ts),
-          thread_timestamp(thread_ts),
-          thread_instruction_count(thread_instructions),
-          packet_idx_(idx),
-          blob_view(std::move(tbv)),
-          inline_event(inline_evt) {}
-
-    TimestampedTracePiece(TimestampedTracePiece&&) noexcept = default;
-    TimestampedTracePiece& operator=(TimestampedTracePiece&&) = default;
-
-    // For std::lower_bound().
-    static inline bool Compare(const TimestampedTracePiece& x, int64_t ts) {
-      return x.timestamp < ts;
-    }
-
-    // For std::sort().
-    inline bool operator<(const TimestampedTracePiece& o) const {
-      return timestamp < o.timestamp ||
-             (timestamp == o.timestamp && packet_idx_ < o.packet_idx_);
-    }
-
-    std::unique_ptr<Json::Value> json_value;
-    std::unique_ptr<FuchsiaProviderView> fuchsia_provider_view;
-    ProtoIncrementalState::PacketSequenceState* packet_sequence_state;
-    size_t packet_sequence_state_generation;
-
-    int64_t timestamp;
-    int64_t thread_timestamp;
-    int64_t thread_instruction_count;
-    uint64_t packet_idx_;
-    TraceBlobView blob_view;
-    InlineEvent inline_event;
-  };
-
   TraceSorter(TraceProcessorContext*, int64_t window_size_ns);
 
   inline void PushTracePacket(int64_t timestamp,
diff --git a/src/trace_processor/trace_sorter_unittest.cc b/src/trace_processor/trace_sorter_unittest.cc
index 116902e..da93c61 100644
--- a/src/trace_processor/trace_sorter_unittest.cc
+++ b/src/trace_processor/trace_sorter_unittest.cc
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
 #include "src/trace_processor/trace_processor_context.h"
 #include "src/trace_processor/trace_sorter.h"
 #include "test/gtest_and_gmock.h"
@@ -46,7 +47,7 @@
 
   void ParseFtracePacket(uint32_t cpu,
                          int64_t timestamp,
-                         TraceSorter::TimestampedTracePiece ttp) override {
+                         TimestampedTracePiece ttp) override {
     TraceBlobView& tbv = ttp.blob_view;
     MOCK_ParseFtracePacket(cpu, timestamp, tbv.data(), tbv.length());
   }
@@ -54,8 +55,7 @@
   MOCK_METHOD3(MOCK_ParseTracePacket,
                void(int64_t ts, const uint8_t* data, size_t length));
 
-  void ParseTracePacket(int64_t ts,
-                        TraceSorter::TimestampedTracePiece ttp) override {
+  void ParseTracePacket(int64_t ts, TimestampedTracePiece ttp) override {
     TraceBlobView& tbv = ttp.blob_view;
     MOCK_ParseTracePacket(ts, tbv.data(), tbv.length());
   }
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index 662c460..1b9f256 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -131,6 +131,9 @@
   if (start_ns == std::numeric_limits<int64_t>::max()) {
     return std::make_pair(0, 0);
   }
+  if (start_ns == end_ns) {
+    end_ns += 1;
+  }
   return std::make_pair(start_ns, end_ns);
 }
 
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index ca0b1db..7001f7c 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -51,6 +51,7 @@
     ":data_source",
     "../../../gn:default_deps",
     "../../../include/perfetto/ext/traced",
+    "../../../protos/perfetto/config/ftrace:cpp",
     "../../../protos/perfetto/trace/ps:zero",
     "../../base",
     "../../tracing:ipc",
diff --git a/src/traced/probes/ftrace/BUILD.gn b/src/traced/probes/ftrace/BUILD.gn
index eddd44d..ddac4e8 100644
--- a/src/traced/probes/ftrace/BUILD.gn
+++ b/src/traced/probes/ftrace/BUILD.gn
@@ -70,6 +70,10 @@
 }
 
 perfetto_proto_library("test_messages_@TYPE@") {
+  proto_generators = [
+    "lite",
+    "zero",
+  ]
   sources = [
     "test/test_messages.proto",
   ]
@@ -104,6 +108,7 @@
     "..:data_source",
     "../../../../gn:default_deps",
     "../../../../include/perfetto/ext/traced",
+    "../../../../protos/perfetto/config/ftrace:cpp",
     "../../../../protos/perfetto/config/ftrace:lite",
     "../../../android_internal:lazy_library_loader",
     "../../../base",
@@ -124,8 +129,6 @@
     "event_info.h",
     "event_info_constants.cc",
     "event_info_constants.h",
-    "ftrace_config.cc",
-    "ftrace_config.h",
     "ftrace_config_muxer.cc",
     "ftrace_config_muxer.h",
     "ftrace_config_utils.cc",
diff --git a/src/traced/probes/ftrace/compact_sched.cc b/src/traced/probes/ftrace/compact_sched.cc
index 85ab487..6bc7619 100644
--- a/src/traced/probes/ftrace/compact_sched.cc
+++ b/src/traced/probes/ftrace/compact_sched.cc
@@ -19,10 +19,10 @@
 #include <stdint.h>
 
 #include "perfetto/ext/base/optional.h"
+#include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
 #include "src/traced/probes/ftrace/event_info_constants.h"
-#include "src/traced/probes/ftrace/ftrace_config.h"
 
 namespace perfetto {
 
diff --git a/src/traced/probes/ftrace/compact_sched.h b/src/traced/probes/ftrace/compact_sched.h
index 029649e..bebe9ff 100644
--- a/src/traced/probes/ftrace/compact_sched.h
+++ b/src/traced/probes/ftrace/compact_sched.h
@@ -23,10 +23,11 @@
 #include "perfetto/protozero/packed_repeated_fields.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "src/traced/probes/ftrace/event_info_constants.h"
-#include "src/traced/probes/ftrace/ftrace_config.h"
 
 namespace perfetto {
 
+class FtraceConfig;
+
 // The subset of the sched_switch event's format that is used when parsing &
 // encoding into the compact format.
 struct CompactSchedSwitchFormat {
diff --git a/src/traced/probes/ftrace/ftrace_config.cc b/src/traced/probes/ftrace/ftrace_config.cc
deleted file mode 100644
index 92bc28a..0000000
--- a/src/traced/probes/ftrace/ftrace_config.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/ftrace/ftrace_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "src/traced/probes/ftrace/ftrace_config.h"
-
-#include "protos/perfetto/config/ftrace/ftrace_config.pb.h"
-
-namespace perfetto {
-
-FtraceConfig::FtraceConfig() = default;
-FtraceConfig::~FtraceConfig() = default;
-FtraceConfig::FtraceConfig(const FtraceConfig&) = default;
-FtraceConfig& FtraceConfig::operator=(const FtraceConfig&) = default;
-FtraceConfig::FtraceConfig(FtraceConfig&&) noexcept = default;
-FtraceConfig& FtraceConfig::operator=(FtraceConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool FtraceConfig::operator==(const FtraceConfig& other) const {
-  return (ftrace_events_ == other.ftrace_events_) &&
-         (atrace_categories_ == other.atrace_categories_) &&
-         (atrace_apps_ == other.atrace_apps_) &&
-         (buffer_size_kb_ == other.buffer_size_kb_) &&
-         (drain_period_ms_ == other.drain_period_ms_) &&
-         (compact_sched_ == other.compact_sched_);
-}
-#pragma GCC diagnostic pop
-
-void FtraceConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::FtraceConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void FtraceConfig::FromProto(const perfetto::protos::FtraceConfig& proto) {
-  ftrace_events_.clear();
-  for (const auto& field : proto.ftrace_events()) {
-    ftrace_events_.emplace_back();
-    static_assert(
-        sizeof(ftrace_events_.back()) == sizeof(proto.ftrace_events(0)),
-        "size mismatch");
-    ftrace_events_.back() =
-        static_cast<decltype(ftrace_events_)::value_type>(field);
-  }
-
-  atrace_categories_.clear();
-  for (const auto& field : proto.atrace_categories()) {
-    atrace_categories_.emplace_back();
-    static_assert(
-        sizeof(atrace_categories_.back()) == sizeof(proto.atrace_categories(0)),
-        "size mismatch");
-    atrace_categories_.back() =
-        static_cast<decltype(atrace_categories_)::value_type>(field);
-  }
-
-  atrace_apps_.clear();
-  for (const auto& field : proto.atrace_apps()) {
-    atrace_apps_.emplace_back();
-    static_assert(sizeof(atrace_apps_.back()) == sizeof(proto.atrace_apps(0)),
-                  "size mismatch");
-    atrace_apps_.back() =
-        static_cast<decltype(atrace_apps_)::value_type>(field);
-  }
-
-  static_assert(sizeof(buffer_size_kb_) == sizeof(proto.buffer_size_kb()),
-                "size mismatch");
-  buffer_size_kb_ =
-      static_cast<decltype(buffer_size_kb_)>(proto.buffer_size_kb());
-
-  static_assert(sizeof(drain_period_ms_) == sizeof(proto.drain_period_ms()),
-                "size mismatch");
-  drain_period_ms_ =
-      static_cast<decltype(drain_period_ms_)>(proto.drain_period_ms());
-
-  compact_sched_->FromProto(proto.compact_sched());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void FtraceConfig::ToProto(perfetto::protos::FtraceConfig* proto) const {
-  proto->Clear();
-
-  for (const auto& it : ftrace_events_) {
-    proto->add_ftrace_events(
-        static_cast<decltype(proto->ftrace_events(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->ftrace_events(0)),
-                  "size mismatch");
-  }
-
-  for (const auto& it : atrace_categories_) {
-    proto->add_atrace_categories(
-        static_cast<decltype(proto->atrace_categories(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->atrace_categories(0)),
-                  "size mismatch");
-  }
-
-  for (const auto& it : atrace_apps_) {
-    proto->add_atrace_apps(static_cast<decltype(proto->atrace_apps(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->atrace_apps(0)), "size mismatch");
-  }
-
-  static_assert(sizeof(buffer_size_kb_) == sizeof(proto->buffer_size_kb()),
-                "size mismatch");
-  proto->set_buffer_size_kb(
-      static_cast<decltype(proto->buffer_size_kb())>(buffer_size_kb_));
-
-  static_assert(sizeof(drain_period_ms_) == sizeof(proto->drain_period_ms()),
-                "size mismatch");
-  proto->set_drain_period_ms(
-      static_cast<decltype(proto->drain_period_ms())>(drain_period_ms_));
-
-  compact_sched_->ToProto(proto->mutable_compact_sched());
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-FtraceConfig::CompactSchedConfig::CompactSchedConfig() = default;
-FtraceConfig::CompactSchedConfig::~CompactSchedConfig() = default;
-FtraceConfig::CompactSchedConfig::CompactSchedConfig(
-    const FtraceConfig::CompactSchedConfig&) = default;
-FtraceConfig::CompactSchedConfig& FtraceConfig::CompactSchedConfig::operator=(
-    const FtraceConfig::CompactSchedConfig&) = default;
-FtraceConfig::CompactSchedConfig::CompactSchedConfig(
-    FtraceConfig::CompactSchedConfig&&) noexcept = default;
-FtraceConfig::CompactSchedConfig& FtraceConfig::CompactSchedConfig::operator=(
-    FtraceConfig::CompactSchedConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool FtraceConfig::CompactSchedConfig::operator==(
-    const FtraceConfig::CompactSchedConfig& other) const {
-  return (enabled_ == other.enabled_);
-}
-#pragma GCC diagnostic pop
-
-void FtraceConfig::CompactSchedConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::FtraceConfig_CompactSchedConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void FtraceConfig::CompactSchedConfig::FromProto(
-    const perfetto::protos::FtraceConfig_CompactSchedConfig& proto) {
-  static_assert(sizeof(enabled_) == sizeof(proto.enabled()), "size mismatch");
-  enabled_ = static_cast<decltype(enabled_)>(proto.enabled());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void FtraceConfig::CompactSchedConfig::ToProto(
-    perfetto::protos::FtraceConfig_CompactSchedConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(enabled_) == sizeof(proto->enabled()), "size mismatch");
-  proto->set_enabled(static_cast<decltype(proto->enabled())>(enabled_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/traced/probes/ftrace/ftrace_config.h b/src/traced/probes/ftrace/ftrace_config.h
deleted file mode 100644
index 0567cc3..0000000
--- a/src/traced/probes/ftrace/ftrace_config.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/ftrace/ftrace_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#ifndef SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_H_
-#define SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_H_
-
-#include <stdint.h>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/copyable_ptr.h"
-#include "perfetto/base/export.h"
-
-// Forward declarations for protobuf types.
-namespace perfetto {
-namespace protos {
-class FtraceConfig;
-class FtraceConfig_CompactSchedConfig;
-}  // namespace protos
-}  // namespace perfetto
-
-namespace perfetto {
-class FtraceConfig;
-
-class PERFETTO_EXPORT FtraceConfig {
- public:
-  class PERFETTO_EXPORT CompactSchedConfig {
-   public:
-    CompactSchedConfig();
-    ~CompactSchedConfig();
-    CompactSchedConfig(CompactSchedConfig&&) noexcept;
-    CompactSchedConfig& operator=(CompactSchedConfig&&);
-    CompactSchedConfig(const CompactSchedConfig&);
-    CompactSchedConfig& operator=(const CompactSchedConfig&);
-    bool operator==(const CompactSchedConfig&) const;
-    bool operator!=(const CompactSchedConfig& other) const {
-      return !(*this == other);
-    }
-
-    // Raw proto decoding.
-    void ParseRawProto(const std::string&);
-    // Conversion methods from/to the corresponding protobuf types.
-    void FromProto(const perfetto::protos::FtraceConfig_CompactSchedConfig&);
-    void ToProto(perfetto::protos::FtraceConfig_CompactSchedConfig*) const;
-
-    bool enabled() const { return enabled_; }
-    void set_enabled(bool value) { enabled_ = value; }
-
-   private:
-    bool enabled_{};
-
-    // Allows to preserve unknown protobuf fields for compatibility
-    // with future versions of .proto files.
-    std::string unknown_fields_;
-  };
-
-  FtraceConfig();
-  ~FtraceConfig();
-  FtraceConfig(FtraceConfig&&) noexcept;
-  FtraceConfig& operator=(FtraceConfig&&);
-  FtraceConfig(const FtraceConfig&);
-  FtraceConfig& operator=(const FtraceConfig&);
-  bool operator==(const FtraceConfig&) const;
-  bool operator!=(const FtraceConfig& other) const { return !(*this == other); }
-
-  // Raw proto decoding.
-  void ParseRawProto(const std::string&);
-  // Conversion methods from/to the corresponding protobuf types.
-  void FromProto(const perfetto::protos::FtraceConfig&);
-  void ToProto(perfetto::protos::FtraceConfig*) const;
-
-  int ftrace_events_size() const {
-    return static_cast<int>(ftrace_events_.size());
-  }
-  const std::vector<std::string>& ftrace_events() const {
-    return ftrace_events_;
-  }
-  std::vector<std::string>* mutable_ftrace_events() { return &ftrace_events_; }
-  void clear_ftrace_events() { ftrace_events_.clear(); }
-  std::string* add_ftrace_events() {
-    ftrace_events_.emplace_back();
-    return &ftrace_events_.back();
-  }
-
-  int atrace_categories_size() const {
-    return static_cast<int>(atrace_categories_.size());
-  }
-  const std::vector<std::string>& atrace_categories() const {
-    return atrace_categories_;
-  }
-  std::vector<std::string>* mutable_atrace_categories() {
-    return &atrace_categories_;
-  }
-  void clear_atrace_categories() { atrace_categories_.clear(); }
-  std::string* add_atrace_categories() {
-    atrace_categories_.emplace_back();
-    return &atrace_categories_.back();
-  }
-
-  int atrace_apps_size() const { return static_cast<int>(atrace_apps_.size()); }
-  const std::vector<std::string>& atrace_apps() const { return atrace_apps_; }
-  std::vector<std::string>* mutable_atrace_apps() { return &atrace_apps_; }
-  void clear_atrace_apps() { atrace_apps_.clear(); }
-  std::string* add_atrace_apps() {
-    atrace_apps_.emplace_back();
-    return &atrace_apps_.back();
-  }
-
-  uint32_t buffer_size_kb() const { return buffer_size_kb_; }
-  void set_buffer_size_kb(uint32_t value) { buffer_size_kb_ = value; }
-
-  uint32_t drain_period_ms() const { return drain_period_ms_; }
-  void set_drain_period_ms(uint32_t value) { drain_period_ms_ = value; }
-
-  const CompactSchedConfig& compact_sched() const { return *compact_sched_; }
-  CompactSchedConfig* mutable_compact_sched() { return compact_sched_.get(); }
-
- private:
-  std::vector<std::string> ftrace_events_;
-  std::vector<std::string> atrace_categories_;
-  std::vector<std::string> atrace_apps_;
-  uint32_t buffer_size_kb_{};
-  uint32_t drain_period_ms_{};
-  ::perfetto::base::CopyablePtr<CompactSchedConfig> compact_sched_;
-
-  // Allows to preserve unknown protobuf fields for compatibility
-  // with future versions of .proto files.
-  std::string unknown_fields_;
-};
-
-}  // namespace perfetto
-
-#endif  // SRC_TRACED_PROBES_FTRACE_FTRACE_CONFIG_H_
diff --git a/src/traced/probes/ftrace/ftrace_config_utils.h b/src/traced/probes/ftrace/ftrace_config_utils.h
index c37a64a..8af3c52 100644
--- a/src/traced/probes/ftrace/ftrace_config_utils.h
+++ b/src/traced/probes/ftrace/ftrace_config_utils.h
@@ -20,7 +20,7 @@
 #include <set>
 #include <string>
 
-#include "src/traced/probes/ftrace/ftrace_config.h"
+#include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
 
 namespace perfetto {
 
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index c73cded..0c3a5de 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -34,7 +34,6 @@
 #include "perfetto/tracing/core/trace_config.h"
 #include "src/traced/probes/android_log/android_log_data_source.h"
 #include "src/traced/probes/filesystem/inode_file_data_source.h"
-#include "src/traced/probes/ftrace/ftrace_config.h"
 #include "src/traced/probes/ftrace/ftrace_data_source.h"
 #include "src/traced/probes/metatrace/metatrace_data_source.h"
 #include "src/traced/probes/packages_list/packages_list_data_source.h"
@@ -43,6 +42,7 @@
 #include "src/traced/probes/ps/process_stats_data_source.h"
 #include "src/traced/probes/sys_stats/sys_stats_data_source.h"
 
+#include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
 #include "protos/perfetto/trace/filesystem/inode_file_map.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h"
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index fcb67cb..e426793 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -38,17 +38,12 @@
     "../protozero",
   ]
   sources = [
-    "core/chrome_config.cc",
-    "core/commit_data_request.cc",
-    "core/data_source_config.cc",
-    "core/data_source_descriptor.cc",
     "core/id_allocator.cc",
     "core/id_allocator.h",
     "core/metatrace_writer.cc",
     "core/metatrace_writer.h",
     "core/null_trace_writer.cc",
     "core/null_trace_writer.h",
-    "core/observable_events.cc",
     "core/packet_stream_validator.cc",
     "core/packet_stream_validator.h",
     "core/patch_list.h",
@@ -58,17 +53,13 @@
     "core/sliced_protobuf_input_stream.cc",
     "core/startup_trace_writer.cc",
     "core/startup_trace_writer_registry.cc",
-    "core/test_config.cc",
     "core/trace_buffer.cc",
     "core/trace_buffer.h",
-    "core/trace_config.cc",
     "core/trace_packet.cc",
-    "core/trace_stats.cc",
     "core/trace_writer_impl.cc",
     "core/trace_writer_impl.h",
     "core/tracing_service_impl.cc",
     "core/tracing_service_impl.h",
-    "core/tracing_service_state.cc",
     "core/virtual_destructors.cc",
   ]
 }
diff --git a/src/tracing/core/chrome_config.cc b/src/tracing/core/chrome_config.cc
deleted file mode 100644
index 3a0cd83..0000000
--- a/src/tracing/core/chrome_config.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/chrome/chrome_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/chrome_config.h"
-
-#include "protos/perfetto/config/chrome/chrome_config.pb.h"
-
-namespace perfetto {
-
-ChromeConfig::ChromeConfig() = default;
-ChromeConfig::~ChromeConfig() = default;
-ChromeConfig::ChromeConfig(const ChromeConfig&) = default;
-ChromeConfig& ChromeConfig::operator=(const ChromeConfig&) = default;
-ChromeConfig::ChromeConfig(ChromeConfig&&) noexcept = default;
-ChromeConfig& ChromeConfig::operator=(ChromeConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool ChromeConfig::operator==(const ChromeConfig& other) const {
-  return (trace_config_ == other.trace_config_) &&
-         (privacy_filtering_enabled_ == other.privacy_filtering_enabled_);
-}
-#pragma GCC diagnostic pop
-
-void ChromeConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::ChromeConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void ChromeConfig::FromProto(const perfetto::protos::ChromeConfig& proto) {
-  static_assert(sizeof(trace_config_) == sizeof(proto.trace_config()),
-                "size mismatch");
-  trace_config_ = static_cast<decltype(trace_config_)>(proto.trace_config());
-
-  static_assert(sizeof(privacy_filtering_enabled_) ==
-                    sizeof(proto.privacy_filtering_enabled()),
-                "size mismatch");
-  privacy_filtering_enabled_ =
-      static_cast<decltype(privacy_filtering_enabled_)>(
-          proto.privacy_filtering_enabled());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void ChromeConfig::ToProto(perfetto::protos::ChromeConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(trace_config_) == sizeof(proto->trace_config()),
-                "size mismatch");
-  proto->set_trace_config(
-      static_cast<decltype(proto->trace_config())>(trace_config_));
-
-  static_assert(sizeof(privacy_filtering_enabled_) ==
-                    sizeof(proto->privacy_filtering_enabled()),
-                "size mismatch");
-  proto->set_privacy_filtering_enabled(
-      static_cast<decltype(proto->privacy_filtering_enabled())>(
-          privacy_filtering_enabled_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/commit_data_request.cc b/src/tracing/core/commit_data_request.cc
deleted file mode 100644
index 8e495df..0000000
--- a/src/tracing/core/commit_data_request.cc
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/commit_data_request.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/ext/tracing/core/commit_data_request.h"
-
-#include "protos/perfetto/common/commit_data_request.pb.h"
-
-namespace perfetto {
-
-CommitDataRequest::CommitDataRequest() = default;
-CommitDataRequest::~CommitDataRequest() = default;
-CommitDataRequest::CommitDataRequest(const CommitDataRequest&) = default;
-CommitDataRequest& CommitDataRequest::operator=(const CommitDataRequest&) =
-    default;
-CommitDataRequest::CommitDataRequest(CommitDataRequest&&) noexcept = default;
-CommitDataRequest& CommitDataRequest::operator=(CommitDataRequest&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool CommitDataRequest::operator==(const CommitDataRequest& other) const {
-  return (chunks_to_move_ == other.chunks_to_move_) &&
-         (chunks_to_patch_ == other.chunks_to_patch_) &&
-         (flush_request_id_ == other.flush_request_id_);
-}
-#pragma GCC diagnostic pop
-
-void CommitDataRequest::ParseRawProto(const std::string& raw) {
-  perfetto::protos::CommitDataRequest proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void CommitDataRequest::FromProto(
-    const perfetto::protos::CommitDataRequest& proto) {
-  chunks_to_move_.clear();
-  for (const auto& field : proto.chunks_to_move()) {
-    chunks_to_move_.emplace_back();
-    chunks_to_move_.back().FromProto(field);
-  }
-
-  chunks_to_patch_.clear();
-  for (const auto& field : proto.chunks_to_patch()) {
-    chunks_to_patch_.emplace_back();
-    chunks_to_patch_.back().FromProto(field);
-  }
-
-  static_assert(sizeof(flush_request_id_) == sizeof(proto.flush_request_id()),
-                "size mismatch");
-  flush_request_id_ =
-      static_cast<decltype(flush_request_id_)>(proto.flush_request_id());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void CommitDataRequest::ToProto(
-    perfetto::protos::CommitDataRequest* proto) const {
-  proto->Clear();
-
-  for (const auto& it : chunks_to_move_) {
-    auto* entry = proto->add_chunks_to_move();
-    it.ToProto(entry);
-  }
-
-  for (const auto& it : chunks_to_patch_) {
-    auto* entry = proto->add_chunks_to_patch();
-    it.ToProto(entry);
-  }
-
-  static_assert(sizeof(flush_request_id_) == sizeof(proto->flush_request_id()),
-                "size mismatch");
-  proto->set_flush_request_id(
-      static_cast<decltype(proto->flush_request_id())>(flush_request_id_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-CommitDataRequest::ChunksToMove::ChunksToMove() = default;
-CommitDataRequest::ChunksToMove::~ChunksToMove() = default;
-CommitDataRequest::ChunksToMove::ChunksToMove(
-    const CommitDataRequest::ChunksToMove&) = default;
-CommitDataRequest::ChunksToMove& CommitDataRequest::ChunksToMove::operator=(
-    const CommitDataRequest::ChunksToMove&) = default;
-CommitDataRequest::ChunksToMove::ChunksToMove(
-    CommitDataRequest::ChunksToMove&&) noexcept = default;
-CommitDataRequest::ChunksToMove& CommitDataRequest::ChunksToMove::operator=(
-    CommitDataRequest::ChunksToMove&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool CommitDataRequest::ChunksToMove::operator==(
-    const CommitDataRequest::ChunksToMove& other) const {
-  return (page_ == other.page_) && (chunk_ == other.chunk_) &&
-         (target_buffer_ == other.target_buffer_);
-}
-#pragma GCC diagnostic pop
-
-void CommitDataRequest::ChunksToMove::ParseRawProto(const std::string& raw) {
-  perfetto::protos::CommitDataRequest_ChunksToMove proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void CommitDataRequest::ChunksToMove::FromProto(
-    const perfetto::protos::CommitDataRequest_ChunksToMove& proto) {
-  static_assert(sizeof(page_) == sizeof(proto.page()), "size mismatch");
-  page_ = static_cast<decltype(page_)>(proto.page());
-
-  static_assert(sizeof(chunk_) == sizeof(proto.chunk()), "size mismatch");
-  chunk_ = static_cast<decltype(chunk_)>(proto.chunk());
-
-  static_assert(sizeof(target_buffer_) == sizeof(proto.target_buffer()),
-                "size mismatch");
-  target_buffer_ = static_cast<decltype(target_buffer_)>(proto.target_buffer());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void CommitDataRequest::ChunksToMove::ToProto(
-    perfetto::protos::CommitDataRequest_ChunksToMove* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(page_) == sizeof(proto->page()), "size mismatch");
-  proto->set_page(static_cast<decltype(proto->page())>(page_));
-
-  static_assert(sizeof(chunk_) == sizeof(proto->chunk()), "size mismatch");
-  proto->set_chunk(static_cast<decltype(proto->chunk())>(chunk_));
-
-  static_assert(sizeof(target_buffer_) == sizeof(proto->target_buffer()),
-                "size mismatch");
-  proto->set_target_buffer(
-      static_cast<decltype(proto->target_buffer())>(target_buffer_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-CommitDataRequest::ChunkToPatch::ChunkToPatch() = default;
-CommitDataRequest::ChunkToPatch::~ChunkToPatch() = default;
-CommitDataRequest::ChunkToPatch::ChunkToPatch(
-    const CommitDataRequest::ChunkToPatch&) = default;
-CommitDataRequest::ChunkToPatch& CommitDataRequest::ChunkToPatch::operator=(
-    const CommitDataRequest::ChunkToPatch&) = default;
-CommitDataRequest::ChunkToPatch::ChunkToPatch(
-    CommitDataRequest::ChunkToPatch&&) noexcept = default;
-CommitDataRequest::ChunkToPatch& CommitDataRequest::ChunkToPatch::operator=(
-    CommitDataRequest::ChunkToPatch&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool CommitDataRequest::ChunkToPatch::operator==(
-    const CommitDataRequest::ChunkToPatch& other) const {
-  return (target_buffer_ == other.target_buffer_) &&
-         (writer_id_ == other.writer_id_) && (chunk_id_ == other.chunk_id_) &&
-         (patches_ == other.patches_) &&
-         (has_more_patches_ == other.has_more_patches_);
-}
-#pragma GCC diagnostic pop
-
-void CommitDataRequest::ChunkToPatch::ParseRawProto(const std::string& raw) {
-  perfetto::protos::CommitDataRequest_ChunkToPatch proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void CommitDataRequest::ChunkToPatch::FromProto(
-    const perfetto::protos::CommitDataRequest_ChunkToPatch& proto) {
-  static_assert(sizeof(target_buffer_) == sizeof(proto.target_buffer()),
-                "size mismatch");
-  target_buffer_ = static_cast<decltype(target_buffer_)>(proto.target_buffer());
-
-  static_assert(sizeof(writer_id_) == sizeof(proto.writer_id()),
-                "size mismatch");
-  writer_id_ = static_cast<decltype(writer_id_)>(proto.writer_id());
-
-  static_assert(sizeof(chunk_id_) == sizeof(proto.chunk_id()), "size mismatch");
-  chunk_id_ = static_cast<decltype(chunk_id_)>(proto.chunk_id());
-
-  patches_.clear();
-  for (const auto& field : proto.patches()) {
-    patches_.emplace_back();
-    patches_.back().FromProto(field);
-  }
-
-  static_assert(sizeof(has_more_patches_) == sizeof(proto.has_more_patches()),
-                "size mismatch");
-  has_more_patches_ =
-      static_cast<decltype(has_more_patches_)>(proto.has_more_patches());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void CommitDataRequest::ChunkToPatch::ToProto(
-    perfetto::protos::CommitDataRequest_ChunkToPatch* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(target_buffer_) == sizeof(proto->target_buffer()),
-                "size mismatch");
-  proto->set_target_buffer(
-      static_cast<decltype(proto->target_buffer())>(target_buffer_));
-
-  static_assert(sizeof(writer_id_) == sizeof(proto->writer_id()),
-                "size mismatch");
-  proto->set_writer_id(static_cast<decltype(proto->writer_id())>(writer_id_));
-
-  static_assert(sizeof(chunk_id_) == sizeof(proto->chunk_id()),
-                "size mismatch");
-  proto->set_chunk_id(static_cast<decltype(proto->chunk_id())>(chunk_id_));
-
-  for (const auto& it : patches_) {
-    auto* entry = proto->add_patches();
-    it.ToProto(entry);
-  }
-
-  static_assert(sizeof(has_more_patches_) == sizeof(proto->has_more_patches()),
-                "size mismatch");
-  proto->set_has_more_patches(
-      static_cast<decltype(proto->has_more_patches())>(has_more_patches_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-CommitDataRequest::ChunkToPatch::Patch::Patch() = default;
-CommitDataRequest::ChunkToPatch::Patch::~Patch() = default;
-CommitDataRequest::ChunkToPatch::Patch::Patch(
-    const CommitDataRequest::ChunkToPatch::Patch&) = default;
-CommitDataRequest::ChunkToPatch::Patch& CommitDataRequest::ChunkToPatch::Patch::
-operator=(const CommitDataRequest::ChunkToPatch::Patch&) = default;
-CommitDataRequest::ChunkToPatch::Patch::Patch(
-    CommitDataRequest::ChunkToPatch::Patch&&) noexcept = default;
-CommitDataRequest::ChunkToPatch::Patch& CommitDataRequest::ChunkToPatch::Patch::
-operator=(CommitDataRequest::ChunkToPatch::Patch&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool CommitDataRequest::ChunkToPatch::Patch::operator==(
-    const CommitDataRequest::ChunkToPatch::Patch& other) const {
-  return (offset_ == other.offset_) && (data_ == other.data_);
-}
-#pragma GCC diagnostic pop
-
-void CommitDataRequest::ChunkToPatch::Patch::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::CommitDataRequest_ChunkToPatch_Patch proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void CommitDataRequest::ChunkToPatch::Patch::FromProto(
-    const perfetto::protos::CommitDataRequest_ChunkToPatch_Patch& proto) {
-  static_assert(sizeof(offset_) == sizeof(proto.offset()), "size mismatch");
-  offset_ = static_cast<decltype(offset_)>(proto.offset());
-
-  static_assert(sizeof(data_) == sizeof(proto.data()), "size mismatch");
-  data_ = static_cast<decltype(data_)>(proto.data());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void CommitDataRequest::ChunkToPatch::Patch::ToProto(
-    perfetto::protos::CommitDataRequest_ChunkToPatch_Patch* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(offset_) == sizeof(proto->offset()), "size mismatch");
-  proto->set_offset(static_cast<decltype(proto->offset())>(offset_));
-
-  static_assert(sizeof(data_) == sizeof(proto->data()), "size mismatch");
-  proto->set_data(static_cast<decltype(proto->data())>(data_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/data_source_config.cc b/src/tracing/core/data_source_config.cc
deleted file mode 100644
index 55e3ed2..0000000
--- a/src/tracing/core/data_source_config.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/data_source_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/data_source_config.h"
-
-#include "protos/perfetto/config/data_source_config.pb.h"
-
-#include "perfetto/tracing/core/chrome_config.h"
-#include "protos/perfetto/config/chrome/chrome_config.pb.h"
-
-#include "perfetto/tracing/core/test_config.h"
-#include "protos/perfetto/config/test_config.pb.h"
-
-namespace perfetto {
-
-DataSourceConfig::DataSourceConfig() = default;
-DataSourceConfig::~DataSourceConfig() = default;
-DataSourceConfig::DataSourceConfig(const DataSourceConfig&) = default;
-DataSourceConfig& DataSourceConfig::operator=(const DataSourceConfig&) =
-    default;
-DataSourceConfig::DataSourceConfig(DataSourceConfig&&) noexcept = default;
-DataSourceConfig& DataSourceConfig::operator=(DataSourceConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool DataSourceConfig::operator==(const DataSourceConfig& other) const {
-  return (name_ == other.name_) && (target_buffer_ == other.target_buffer_) &&
-         (trace_duration_ms_ == other.trace_duration_ms_) &&
-         (stop_timeout_ms_ == other.stop_timeout_ms_) &&
-         (enable_extra_guardrails_ == other.enable_extra_guardrails_) &&
-         (tracing_session_id_ == other.tracing_session_id_) &&
-         (ftrace_config_ == other.ftrace_config_) &&
-         (inode_file_config_ == other.inode_file_config_) &&
-         (process_stats_config_ == other.process_stats_config_) &&
-         (sys_stats_config_ == other.sys_stats_config_) &&
-         (heapprofd_config_ == other.heapprofd_config_) &&
-         (java_hprof_config_ == other.java_hprof_config_) &&
-         (android_power_config_ == other.android_power_config_) &&
-         (android_log_config_ == other.android_log_config_) &&
-         (gpu_counter_config_ == other.gpu_counter_config_) &&
-         (packages_list_config_ == other.packages_list_config_) &&
-         (chrome_config_ == other.chrome_config_) &&
-         (legacy_config_ == other.legacy_config_) &&
-         (for_testing_ == other.for_testing_);
-}
-#pragma GCC diagnostic pop
-
-void DataSourceConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::DataSourceConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void DataSourceConfig::FromProto(
-    const perfetto::protos::DataSourceConfig& proto) {
-  static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
-  name_ = static_cast<decltype(name_)>(proto.name());
-
-  static_assert(sizeof(target_buffer_) == sizeof(proto.target_buffer()),
-                "size mismatch");
-  target_buffer_ = static_cast<decltype(target_buffer_)>(proto.target_buffer());
-
-  static_assert(sizeof(trace_duration_ms_) == sizeof(proto.trace_duration_ms()),
-                "size mismatch");
-  trace_duration_ms_ =
-      static_cast<decltype(trace_duration_ms_)>(proto.trace_duration_ms());
-
-  static_assert(sizeof(stop_timeout_ms_) == sizeof(proto.stop_timeout_ms()),
-                "size mismatch");
-  stop_timeout_ms_ =
-      static_cast<decltype(stop_timeout_ms_)>(proto.stop_timeout_ms());
-
-  static_assert(sizeof(enable_extra_guardrails_) ==
-                    sizeof(proto.enable_extra_guardrails()),
-                "size mismatch");
-  enable_extra_guardrails_ = static_cast<decltype(enable_extra_guardrails_)>(
-      proto.enable_extra_guardrails());
-
-  static_assert(
-      sizeof(tracing_session_id_) == sizeof(proto.tracing_session_id()),
-      "size mismatch");
-  tracing_session_id_ =
-      static_cast<decltype(tracing_session_id_)>(proto.tracing_session_id());
-
-  ftrace_config_ = proto.ftrace_config().SerializeAsString();
-
-  inode_file_config_ = proto.inode_file_config().SerializeAsString();
-
-  process_stats_config_ = proto.process_stats_config().SerializeAsString();
-
-  sys_stats_config_ = proto.sys_stats_config().SerializeAsString();
-
-  heapprofd_config_ = proto.heapprofd_config().SerializeAsString();
-
-  java_hprof_config_ = proto.java_hprof_config().SerializeAsString();
-
-  android_power_config_ = proto.android_power_config().SerializeAsString();
-
-  android_log_config_ = proto.android_log_config().SerializeAsString();
-
-  gpu_counter_config_ = proto.gpu_counter_config().SerializeAsString();
-
-  packages_list_config_ = proto.packages_list_config().SerializeAsString();
-
-  chrome_config_->FromProto(proto.chrome_config());
-
-  static_assert(sizeof(legacy_config_) == sizeof(proto.legacy_config()),
-                "size mismatch");
-  legacy_config_ = static_cast<decltype(legacy_config_)>(proto.legacy_config());
-
-  for_testing_->FromProto(proto.for_testing());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void DataSourceConfig::ToProto(
-    perfetto::protos::DataSourceConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(name_) == sizeof(proto->name()), "size mismatch");
-  proto->set_name(static_cast<decltype(proto->name())>(name_));
-
-  static_assert(sizeof(target_buffer_) == sizeof(proto->target_buffer()),
-                "size mismatch");
-  proto->set_target_buffer(
-      static_cast<decltype(proto->target_buffer())>(target_buffer_));
-
-  static_assert(
-      sizeof(trace_duration_ms_) == sizeof(proto->trace_duration_ms()),
-      "size mismatch");
-  proto->set_trace_duration_ms(
-      static_cast<decltype(proto->trace_duration_ms())>(trace_duration_ms_));
-
-  static_assert(sizeof(stop_timeout_ms_) == sizeof(proto->stop_timeout_ms()),
-                "size mismatch");
-  proto->set_stop_timeout_ms(
-      static_cast<decltype(proto->stop_timeout_ms())>(stop_timeout_ms_));
-
-  static_assert(sizeof(enable_extra_guardrails_) ==
-                    sizeof(proto->enable_extra_guardrails()),
-                "size mismatch");
-  proto->set_enable_extra_guardrails(
-      static_cast<decltype(proto->enable_extra_guardrails())>(
-          enable_extra_guardrails_));
-
-  static_assert(
-      sizeof(tracing_session_id_) == sizeof(proto->tracing_session_id()),
-      "size mismatch");
-  proto->set_tracing_session_id(
-      static_cast<decltype(proto->tracing_session_id())>(tracing_session_id_));
-
-  proto->mutable_ftrace_config()->ParseFromString(ftrace_config_);
-
-  proto->mutable_inode_file_config()->ParseFromString(inode_file_config_);
-
-  proto->mutable_process_stats_config()->ParseFromString(process_stats_config_);
-
-  proto->mutable_sys_stats_config()->ParseFromString(sys_stats_config_);
-
-  proto->mutable_heapprofd_config()->ParseFromString(heapprofd_config_);
-
-  proto->mutable_java_hprof_config()->ParseFromString(java_hprof_config_);
-
-  proto->mutable_android_power_config()->ParseFromString(android_power_config_);
-
-  proto->mutable_android_log_config()->ParseFromString(android_log_config_);
-
-  proto->mutable_gpu_counter_config()->ParseFromString(gpu_counter_config_);
-
-  proto->mutable_packages_list_config()->ParseFromString(packages_list_config_);
-
-  chrome_config_->ToProto(proto->mutable_chrome_config());
-
-  static_assert(sizeof(legacy_config_) == sizeof(proto->legacy_config()),
-                "size mismatch");
-  proto->set_legacy_config(
-      static_cast<decltype(proto->legacy_config())>(legacy_config_));
-
-  for_testing_->ToProto(proto->mutable_for_testing());
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/data_source_descriptor.cc b/src/tracing/core/data_source_descriptor.cc
deleted file mode 100644
index 91a3eb1..0000000
--- a/src/tracing/core/data_source_descriptor.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/data_source_descriptor.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/data_source_descriptor.h"
-
-#include "protos/perfetto/common/data_source_descriptor.pb.h"
-
-namespace perfetto {
-
-DataSourceDescriptor::DataSourceDescriptor() = default;
-DataSourceDescriptor::~DataSourceDescriptor() = default;
-DataSourceDescriptor::DataSourceDescriptor(const DataSourceDescriptor&) =
-    default;
-DataSourceDescriptor& DataSourceDescriptor::operator=(
-    const DataSourceDescriptor&) = default;
-DataSourceDescriptor::DataSourceDescriptor(DataSourceDescriptor&&) noexcept =
-    default;
-DataSourceDescriptor& DataSourceDescriptor::operator=(DataSourceDescriptor&&) =
-    default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool DataSourceDescriptor::operator==(const DataSourceDescriptor& other) const {
-  return (name_ == other.name_) &&
-         (will_notify_on_stop_ == other.will_notify_on_stop_) &&
-         (will_notify_on_start_ == other.will_notify_on_start_) &&
-         (handles_incremental_state_clear_ ==
-          other.handles_incremental_state_clear_) &&
-         (gpu_counter_descriptor_ == other.gpu_counter_descriptor_) &&
-         (track_event_descriptor_ == other.track_event_descriptor_);
-}
-#pragma GCC diagnostic pop
-
-void DataSourceDescriptor::ParseRawProto(const std::string& raw) {
-  perfetto::protos::DataSourceDescriptor proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void DataSourceDescriptor::FromProto(
-    const perfetto::protos::DataSourceDescriptor& proto) {
-  static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
-  name_ = static_cast<decltype(name_)>(proto.name());
-
-  static_assert(
-      sizeof(will_notify_on_stop_) == sizeof(proto.will_notify_on_stop()),
-      "size mismatch");
-  will_notify_on_stop_ =
-      static_cast<decltype(will_notify_on_stop_)>(proto.will_notify_on_stop());
-
-  static_assert(
-      sizeof(will_notify_on_start_) == sizeof(proto.will_notify_on_start()),
-      "size mismatch");
-  will_notify_on_start_ = static_cast<decltype(will_notify_on_start_)>(
-      proto.will_notify_on_start());
-
-  static_assert(sizeof(handles_incremental_state_clear_) ==
-                    sizeof(proto.handles_incremental_state_clear()),
-                "size mismatch");
-  handles_incremental_state_clear_ =
-      static_cast<decltype(handles_incremental_state_clear_)>(
-          proto.handles_incremental_state_clear());
-
-  gpu_counter_descriptor_ = proto.gpu_counter_descriptor().SerializeAsString();
-
-  track_event_descriptor_ = proto.track_event_descriptor().SerializeAsString();
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void DataSourceDescriptor::ToProto(
-    perfetto::protos::DataSourceDescriptor* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(name_) == sizeof(proto->name()), "size mismatch");
-  proto->set_name(static_cast<decltype(proto->name())>(name_));
-
-  static_assert(
-      sizeof(will_notify_on_stop_) == sizeof(proto->will_notify_on_stop()),
-      "size mismatch");
-  proto->set_will_notify_on_stop(
-      static_cast<decltype(proto->will_notify_on_stop())>(
-          will_notify_on_stop_));
-
-  static_assert(
-      sizeof(will_notify_on_start_) == sizeof(proto->will_notify_on_start()),
-      "size mismatch");
-  proto->set_will_notify_on_start(
-      static_cast<decltype(proto->will_notify_on_start())>(
-          will_notify_on_start_));
-
-  static_assert(sizeof(handles_incremental_state_clear_) ==
-                    sizeof(proto->handles_incremental_state_clear()),
-                "size mismatch");
-  proto->set_handles_incremental_state_clear(
-      static_cast<decltype(proto->handles_incremental_state_clear())>(
-          handles_incremental_state_clear_));
-
-  proto->mutable_gpu_counter_descriptor()->ParseFromString(
-      gpu_counter_descriptor_);
-
-  proto->mutable_track_event_descriptor()->ParseFromString(
-      track_event_descriptor_);
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/observable_events.cc b/src/tracing/core/observable_events.cc
deleted file mode 100644
index 8e17747..0000000
--- a/src/tracing/core/observable_events.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/observable_events.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/ext/tracing/core/observable_events.h"
-
-#include "protos/perfetto/common/observable_events.pb.h"
-
-namespace perfetto {
-
-ObservableEvents::ObservableEvents() = default;
-ObservableEvents::~ObservableEvents() = default;
-ObservableEvents::ObservableEvents(const ObservableEvents&) = default;
-ObservableEvents& ObservableEvents::operator=(const ObservableEvents&) =
-    default;
-ObservableEvents::ObservableEvents(ObservableEvents&&) noexcept = default;
-ObservableEvents& ObservableEvents::operator=(ObservableEvents&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool ObservableEvents::operator==(const ObservableEvents& other) const {
-  return (instance_state_changes_ == other.instance_state_changes_);
-}
-#pragma GCC diagnostic pop
-
-void ObservableEvents::ParseRawProto(const std::string& raw) {
-  perfetto::protos::ObservableEvents proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void ObservableEvents::FromProto(
-    const perfetto::protos::ObservableEvents& proto) {
-  instance_state_changes_.clear();
-  for (const auto& field : proto.instance_state_changes()) {
-    instance_state_changes_.emplace_back();
-    instance_state_changes_.back().FromProto(field);
-  }
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void ObservableEvents::ToProto(
-    perfetto::protos::ObservableEvents* proto) const {
-  proto->Clear();
-
-  for (const auto& it : instance_state_changes_) {
-    auto* entry = proto->add_instance_state_changes();
-    it.ToProto(entry);
-  }
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-ObservableEvents::DataSourceInstanceStateChange::
-    DataSourceInstanceStateChange() = default;
-ObservableEvents::DataSourceInstanceStateChange::
-    ~DataSourceInstanceStateChange() = default;
-ObservableEvents::DataSourceInstanceStateChange::DataSourceInstanceStateChange(
-    const ObservableEvents::DataSourceInstanceStateChange&) = default;
-ObservableEvents::DataSourceInstanceStateChange&
-ObservableEvents::DataSourceInstanceStateChange::operator=(
-    const ObservableEvents::DataSourceInstanceStateChange&) = default;
-ObservableEvents::DataSourceInstanceStateChange::DataSourceInstanceStateChange(
-    ObservableEvents::DataSourceInstanceStateChange&&) noexcept = default;
-ObservableEvents::DataSourceInstanceStateChange&
-ObservableEvents::DataSourceInstanceStateChange::operator=(
-    ObservableEvents::DataSourceInstanceStateChange&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool ObservableEvents::DataSourceInstanceStateChange::operator==(
-    const ObservableEvents::DataSourceInstanceStateChange& other) const {
-  return (producer_name_ == other.producer_name_) &&
-         (data_source_name_ == other.data_source_name_) &&
-         (state_ == other.state_);
-}
-#pragma GCC diagnostic pop
-
-void ObservableEvents::DataSourceInstanceStateChange::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::ObservableEvents_DataSourceInstanceStateChange proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void ObservableEvents::DataSourceInstanceStateChange::FromProto(
-    const perfetto::protos::ObservableEvents_DataSourceInstanceStateChange&
-        proto) {
-  static_assert(sizeof(producer_name_) == sizeof(proto.producer_name()),
-                "size mismatch");
-  producer_name_ = static_cast<decltype(producer_name_)>(proto.producer_name());
-
-  static_assert(sizeof(data_source_name_) == sizeof(proto.data_source_name()),
-                "size mismatch");
-  data_source_name_ =
-      static_cast<decltype(data_source_name_)>(proto.data_source_name());
-
-  static_assert(sizeof(state_) == sizeof(proto.state()), "size mismatch");
-  state_ = static_cast<decltype(state_)>(proto.state());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void ObservableEvents::DataSourceInstanceStateChange::ToProto(
-    perfetto::protos::ObservableEvents_DataSourceInstanceStateChange* proto)
-    const {
-  proto->Clear();
-
-  static_assert(sizeof(producer_name_) == sizeof(proto->producer_name()),
-                "size mismatch");
-  proto->set_producer_name(
-      static_cast<decltype(proto->producer_name())>(producer_name_));
-
-  static_assert(sizeof(data_source_name_) == sizeof(proto->data_source_name()),
-                "size mismatch");
-  proto->set_data_source_name(
-      static_cast<decltype(proto->data_source_name())>(data_source_name_));
-
-  static_assert(sizeof(state_) == sizeof(proto->state()), "size mismatch");
-  proto->set_state(static_cast<decltype(proto->state())>(state_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/test_config.cc b/src/tracing/core/test_config.cc
deleted file mode 100644
index decebf7..0000000
--- a/src/tracing/core/test_config.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/test_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/test_config.h"
-
-#include "protos/perfetto/config/test_config.pb.h"
-
-namespace perfetto {
-
-TestConfig::TestConfig() = default;
-TestConfig::~TestConfig() = default;
-TestConfig::TestConfig(const TestConfig&) = default;
-TestConfig& TestConfig::operator=(const TestConfig&) = default;
-TestConfig::TestConfig(TestConfig&&) noexcept = default;
-TestConfig& TestConfig::operator=(TestConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TestConfig::operator==(const TestConfig& other) const {
-  return (message_count_ == other.message_count_) &&
-         (max_messages_per_second_ == other.max_messages_per_second_) &&
-         (seed_ == other.seed_) && (message_size_ == other.message_size_) &&
-         (send_batch_on_register_ == other.send_batch_on_register_) &&
-         (dummy_fields_ == other.dummy_fields_);
-}
-#pragma GCC diagnostic pop
-
-void TestConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TestConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TestConfig::FromProto(const perfetto::protos::TestConfig& proto) {
-  static_assert(sizeof(message_count_) == sizeof(proto.message_count()),
-                "size mismatch");
-  message_count_ = static_cast<decltype(message_count_)>(proto.message_count());
-
-  static_assert(sizeof(max_messages_per_second_) ==
-                    sizeof(proto.max_messages_per_second()),
-                "size mismatch");
-  max_messages_per_second_ = static_cast<decltype(max_messages_per_second_)>(
-      proto.max_messages_per_second());
-
-  static_assert(sizeof(seed_) == sizeof(proto.seed()), "size mismatch");
-  seed_ = static_cast<decltype(seed_)>(proto.seed());
-
-  static_assert(sizeof(message_size_) == sizeof(proto.message_size()),
-                "size mismatch");
-  message_size_ = static_cast<decltype(message_size_)>(proto.message_size());
-
-  static_assert(
-      sizeof(send_batch_on_register_) == sizeof(proto.send_batch_on_register()),
-      "size mismatch");
-  send_batch_on_register_ = static_cast<decltype(send_batch_on_register_)>(
-      proto.send_batch_on_register());
-
-  dummy_fields_->FromProto(proto.dummy_fields());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TestConfig::ToProto(perfetto::protos::TestConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(message_count_) == sizeof(proto->message_count()),
-                "size mismatch");
-  proto->set_message_count(
-      static_cast<decltype(proto->message_count())>(message_count_));
-
-  static_assert(sizeof(max_messages_per_second_) ==
-                    sizeof(proto->max_messages_per_second()),
-                "size mismatch");
-  proto->set_max_messages_per_second(
-      static_cast<decltype(proto->max_messages_per_second())>(
-          max_messages_per_second_));
-
-  static_assert(sizeof(seed_) == sizeof(proto->seed()), "size mismatch");
-  proto->set_seed(static_cast<decltype(proto->seed())>(seed_));
-
-  static_assert(sizeof(message_size_) == sizeof(proto->message_size()),
-                "size mismatch");
-  proto->set_message_size(
-      static_cast<decltype(proto->message_size())>(message_size_));
-
-  static_assert(sizeof(send_batch_on_register_) ==
-                    sizeof(proto->send_batch_on_register()),
-                "size mismatch");
-  proto->set_send_batch_on_register(
-      static_cast<decltype(proto->send_batch_on_register())>(
-          send_batch_on_register_));
-
-  dummy_fields_->ToProto(proto->mutable_dummy_fields());
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TestConfig::DummyFields::DummyFields() = default;
-TestConfig::DummyFields::~DummyFields() = default;
-TestConfig::DummyFields::DummyFields(const TestConfig::DummyFields&) = default;
-TestConfig::DummyFields& TestConfig::DummyFields::operator=(
-    const TestConfig::DummyFields&) = default;
-TestConfig::DummyFields::DummyFields(TestConfig::DummyFields&&) noexcept =
-    default;
-TestConfig::DummyFields& TestConfig::DummyFields::operator=(
-    TestConfig::DummyFields&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TestConfig::DummyFields::operator==(
-    const TestConfig::DummyFields& other) const {
-  return (field_uint32_ == other.field_uint32_) &&
-         (field_int32_ == other.field_int32_) &&
-         (field_uint64_ == other.field_uint64_) &&
-         (field_int64_ == other.field_int64_) &&
-         (field_fixed64_ == other.field_fixed64_) &&
-         (field_sfixed64_ == other.field_sfixed64_) &&
-         (field_fixed32_ == other.field_fixed32_) &&
-         (field_sfixed32_ == other.field_sfixed32_) &&
-         (field_double_ == other.field_double_) &&
-         (field_float_ == other.field_float_) &&
-         (field_sint64_ == other.field_sint64_) &&
-         (field_sint32_ == other.field_sint32_) &&
-         (field_string_ == other.field_string_) &&
-         (field_bytes_ == other.field_bytes_);
-}
-#pragma GCC diagnostic pop
-
-void TestConfig::DummyFields::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TestConfig_DummyFields proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TestConfig::DummyFields::FromProto(
-    const perfetto::protos::TestConfig_DummyFields& proto) {
-  static_assert(sizeof(field_uint32_) == sizeof(proto.field_uint32()),
-                "size mismatch");
-  field_uint32_ = static_cast<decltype(field_uint32_)>(proto.field_uint32());
-
-  static_assert(sizeof(field_int32_) == sizeof(proto.field_int32()),
-                "size mismatch");
-  field_int32_ = static_cast<decltype(field_int32_)>(proto.field_int32());
-
-  static_assert(sizeof(field_uint64_) == sizeof(proto.field_uint64()),
-                "size mismatch");
-  field_uint64_ = static_cast<decltype(field_uint64_)>(proto.field_uint64());
-
-  static_assert(sizeof(field_int64_) == sizeof(proto.field_int64()),
-                "size mismatch");
-  field_int64_ = static_cast<decltype(field_int64_)>(proto.field_int64());
-
-  static_assert(sizeof(field_fixed64_) == sizeof(proto.field_fixed64()),
-                "size mismatch");
-  field_fixed64_ = static_cast<decltype(field_fixed64_)>(proto.field_fixed64());
-
-  static_assert(sizeof(field_sfixed64_) == sizeof(proto.field_sfixed64()),
-                "size mismatch");
-  field_sfixed64_ =
-      static_cast<decltype(field_sfixed64_)>(proto.field_sfixed64());
-
-  static_assert(sizeof(field_fixed32_) == sizeof(proto.field_fixed32()),
-                "size mismatch");
-  field_fixed32_ = static_cast<decltype(field_fixed32_)>(proto.field_fixed32());
-
-  static_assert(sizeof(field_sfixed32_) == sizeof(proto.field_sfixed32()),
-                "size mismatch");
-  field_sfixed32_ =
-      static_cast<decltype(field_sfixed32_)>(proto.field_sfixed32());
-
-  static_assert(sizeof(field_double_) == sizeof(proto.field_double()),
-                "size mismatch");
-  field_double_ = static_cast<decltype(field_double_)>(proto.field_double());
-
-  static_assert(sizeof(field_float_) == sizeof(proto.field_float()),
-                "size mismatch");
-  field_float_ = static_cast<decltype(field_float_)>(proto.field_float());
-
-  static_assert(sizeof(field_sint64_) == sizeof(proto.field_sint64()),
-                "size mismatch");
-  field_sint64_ = static_cast<decltype(field_sint64_)>(proto.field_sint64());
-
-  static_assert(sizeof(field_sint32_) == sizeof(proto.field_sint32()),
-                "size mismatch");
-  field_sint32_ = static_cast<decltype(field_sint32_)>(proto.field_sint32());
-
-  static_assert(sizeof(field_string_) == sizeof(proto.field_string()),
-                "size mismatch");
-  field_string_ = static_cast<decltype(field_string_)>(proto.field_string());
-
-  static_assert(sizeof(field_bytes_) == sizeof(proto.field_bytes()),
-                "size mismatch");
-  field_bytes_ = static_cast<decltype(field_bytes_)>(proto.field_bytes());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TestConfig::DummyFields::ToProto(
-    perfetto::protos::TestConfig_DummyFields* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(field_uint32_) == sizeof(proto->field_uint32()),
-                "size mismatch");
-  proto->set_field_uint32(
-      static_cast<decltype(proto->field_uint32())>(field_uint32_));
-
-  static_assert(sizeof(field_int32_) == sizeof(proto->field_int32()),
-                "size mismatch");
-  proto->set_field_int32(
-      static_cast<decltype(proto->field_int32())>(field_int32_));
-
-  static_assert(sizeof(field_uint64_) == sizeof(proto->field_uint64()),
-                "size mismatch");
-  proto->set_field_uint64(
-      static_cast<decltype(proto->field_uint64())>(field_uint64_));
-
-  static_assert(sizeof(field_int64_) == sizeof(proto->field_int64()),
-                "size mismatch");
-  proto->set_field_int64(
-      static_cast<decltype(proto->field_int64())>(field_int64_));
-
-  static_assert(sizeof(field_fixed64_) == sizeof(proto->field_fixed64()),
-                "size mismatch");
-  proto->set_field_fixed64(
-      static_cast<decltype(proto->field_fixed64())>(field_fixed64_));
-
-  static_assert(sizeof(field_sfixed64_) == sizeof(proto->field_sfixed64()),
-                "size mismatch");
-  proto->set_field_sfixed64(
-      static_cast<decltype(proto->field_sfixed64())>(field_sfixed64_));
-
-  static_assert(sizeof(field_fixed32_) == sizeof(proto->field_fixed32()),
-                "size mismatch");
-  proto->set_field_fixed32(
-      static_cast<decltype(proto->field_fixed32())>(field_fixed32_));
-
-  static_assert(sizeof(field_sfixed32_) == sizeof(proto->field_sfixed32()),
-                "size mismatch");
-  proto->set_field_sfixed32(
-      static_cast<decltype(proto->field_sfixed32())>(field_sfixed32_));
-
-  static_assert(sizeof(field_double_) == sizeof(proto->field_double()),
-                "size mismatch");
-  proto->set_field_double(
-      static_cast<decltype(proto->field_double())>(field_double_));
-
-  static_assert(sizeof(field_float_) == sizeof(proto->field_float()),
-                "size mismatch");
-  proto->set_field_float(
-      static_cast<decltype(proto->field_float())>(field_float_));
-
-  static_assert(sizeof(field_sint64_) == sizeof(proto->field_sint64()),
-                "size mismatch");
-  proto->set_field_sint64(
-      static_cast<decltype(proto->field_sint64())>(field_sint64_));
-
-  static_assert(sizeof(field_sint32_) == sizeof(proto->field_sint32()),
-                "size mismatch");
-  proto->set_field_sint32(
-      static_cast<decltype(proto->field_sint32())>(field_sint32_));
-
-  static_assert(sizeof(field_string_) == sizeof(proto->field_string()),
-                "size mismatch");
-  proto->set_field_string(
-      static_cast<decltype(proto->field_string())>(field_string_));
-
-  static_assert(sizeof(field_bytes_) == sizeof(proto->field_bytes()),
-                "size mismatch");
-  proto->set_field_bytes(
-      static_cast<decltype(proto->field_bytes())>(field_bytes_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/trace_config.cc b/src/tracing/core/trace_config.cc
deleted file mode 100644
index 5c83362..0000000
--- a/src/tracing/core/trace_config.cc
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/config/trace_config.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/trace_config.h"
-
-#include "protos/perfetto/config/trace_config.pb.h"
-
-#include "perfetto/tracing/core/data_source_config.h"
-#include "protos/perfetto/config/data_source_config.pb.h"
-
-namespace perfetto {
-
-TraceConfig::TraceConfig() = default;
-TraceConfig::~TraceConfig() = default;
-TraceConfig::TraceConfig(const TraceConfig&) = default;
-TraceConfig& TraceConfig::operator=(const TraceConfig&) = default;
-TraceConfig::TraceConfig(TraceConfig&&) noexcept = default;
-TraceConfig& TraceConfig::operator=(TraceConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::operator==(const TraceConfig& other) const {
-  return (buffers_ == other.buffers_) &&
-         (data_sources_ == other.data_sources_) &&
-         (builtin_data_sources_ == other.builtin_data_sources_) &&
-         (duration_ms_ == other.duration_ms_) &&
-         (enable_extra_guardrails_ == other.enable_extra_guardrails_) &&
-         (lockdown_mode_ == other.lockdown_mode_) &&
-         (producers_ == other.producers_) &&
-         (statsd_metadata_ == other.statsd_metadata_) &&
-         (write_into_file_ == other.write_into_file_) &&
-         (file_write_period_ms_ == other.file_write_period_ms_) &&
-         (max_file_size_bytes_ == other.max_file_size_bytes_) &&
-         (guardrail_overrides_ == other.guardrail_overrides_) &&
-         (deferred_start_ == other.deferred_start_) &&
-         (flush_period_ms_ == other.flush_period_ms_) &&
-         (flush_timeout_ms_ == other.flush_timeout_ms_) &&
-         (data_source_stop_timeout_ms_ == other.data_source_stop_timeout_ms_) &&
-         (notify_traceur_ == other.notify_traceur_) &&
-         (trigger_config_ == other.trigger_config_) &&
-         (activate_triggers_ == other.activate_triggers_) &&
-         (incremental_state_config_ == other.incremental_state_config_) &&
-         (allow_user_build_tracing_ == other.allow_user_build_tracing_) &&
-         (unique_session_name_ == other.unique_session_name_) &&
-         (compression_type_ == other.compression_type_) &&
-         (incident_report_config_ == other.incident_report_config_) &&
-         (trace_uuid_ == other.trace_uuid_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::FromProto(const perfetto::protos::TraceConfig& proto) {
-  buffers_.clear();
-  for (const auto& field : proto.buffers()) {
-    buffers_.emplace_back();
-    buffers_.back().FromProto(field);
-  }
-
-  data_sources_.clear();
-  for (const auto& field : proto.data_sources()) {
-    data_sources_.emplace_back();
-    data_sources_.back().FromProto(field);
-  }
-
-  builtin_data_sources_->FromProto(proto.builtin_data_sources());
-
-  static_assert(sizeof(duration_ms_) == sizeof(proto.duration_ms()),
-                "size mismatch");
-  duration_ms_ = static_cast<decltype(duration_ms_)>(proto.duration_ms());
-
-  static_assert(sizeof(enable_extra_guardrails_) ==
-                    sizeof(proto.enable_extra_guardrails()),
-                "size mismatch");
-  enable_extra_guardrails_ = static_cast<decltype(enable_extra_guardrails_)>(
-      proto.enable_extra_guardrails());
-
-  static_assert(sizeof(lockdown_mode_) == sizeof(proto.lockdown_mode()),
-                "size mismatch");
-  lockdown_mode_ = static_cast<decltype(lockdown_mode_)>(proto.lockdown_mode());
-
-  producers_.clear();
-  for (const auto& field : proto.producers()) {
-    producers_.emplace_back();
-    producers_.back().FromProto(field);
-  }
-
-  statsd_metadata_->FromProto(proto.statsd_metadata());
-
-  static_assert(sizeof(write_into_file_) == sizeof(proto.write_into_file()),
-                "size mismatch");
-  write_into_file_ =
-      static_cast<decltype(write_into_file_)>(proto.write_into_file());
-
-  static_assert(
-      sizeof(file_write_period_ms_) == sizeof(proto.file_write_period_ms()),
-      "size mismatch");
-  file_write_period_ms_ = static_cast<decltype(file_write_period_ms_)>(
-      proto.file_write_period_ms());
-
-  static_assert(
-      sizeof(max_file_size_bytes_) == sizeof(proto.max_file_size_bytes()),
-      "size mismatch");
-  max_file_size_bytes_ =
-      static_cast<decltype(max_file_size_bytes_)>(proto.max_file_size_bytes());
-
-  guardrail_overrides_->FromProto(proto.guardrail_overrides());
-
-  static_assert(sizeof(deferred_start_) == sizeof(proto.deferred_start()),
-                "size mismatch");
-  deferred_start_ =
-      static_cast<decltype(deferred_start_)>(proto.deferred_start());
-
-  static_assert(sizeof(flush_period_ms_) == sizeof(proto.flush_period_ms()),
-                "size mismatch");
-  flush_period_ms_ =
-      static_cast<decltype(flush_period_ms_)>(proto.flush_period_ms());
-
-  static_assert(sizeof(flush_timeout_ms_) == sizeof(proto.flush_timeout_ms()),
-                "size mismatch");
-  flush_timeout_ms_ =
-      static_cast<decltype(flush_timeout_ms_)>(proto.flush_timeout_ms());
-
-  static_assert(sizeof(data_source_stop_timeout_ms_) ==
-                    sizeof(proto.data_source_stop_timeout_ms()),
-                "size mismatch");
-  data_source_stop_timeout_ms_ =
-      static_cast<decltype(data_source_stop_timeout_ms_)>(
-          proto.data_source_stop_timeout_ms());
-
-  static_assert(sizeof(notify_traceur_) == sizeof(proto.notify_traceur()),
-                "size mismatch");
-  notify_traceur_ =
-      static_cast<decltype(notify_traceur_)>(proto.notify_traceur());
-
-  trigger_config_->FromProto(proto.trigger_config());
-
-  activate_triggers_.clear();
-  for (const auto& field : proto.activate_triggers()) {
-    activate_triggers_.emplace_back();
-    static_assert(
-        sizeof(activate_triggers_.back()) == sizeof(proto.activate_triggers(0)),
-        "size mismatch");
-    activate_triggers_.back() =
-        static_cast<decltype(activate_triggers_)::value_type>(field);
-  }
-
-  incremental_state_config_->FromProto(proto.incremental_state_config());
-
-  static_assert(sizeof(allow_user_build_tracing_) ==
-                    sizeof(proto.allow_user_build_tracing()),
-                "size mismatch");
-  allow_user_build_tracing_ = static_cast<decltype(allow_user_build_tracing_)>(
-      proto.allow_user_build_tracing());
-
-  static_assert(
-      sizeof(unique_session_name_) == sizeof(proto.unique_session_name()),
-      "size mismatch");
-  unique_session_name_ =
-      static_cast<decltype(unique_session_name_)>(proto.unique_session_name());
-
-  static_assert(sizeof(compression_type_) == sizeof(proto.compression_type()),
-                "size mismatch");
-  compression_type_ =
-      static_cast<decltype(compression_type_)>(proto.compression_type());
-
-  incident_report_config_->FromProto(proto.incident_report_config());
-
-  static_assert(sizeof(trace_uuid_) == sizeof(proto.trace_uuid()),
-                "size mismatch");
-  trace_uuid_ = static_cast<decltype(trace_uuid_)>(proto.trace_uuid());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::ToProto(perfetto::protos::TraceConfig* proto) const {
-  proto->Clear();
-
-  for (const auto& it : buffers_) {
-    auto* entry = proto->add_buffers();
-    it.ToProto(entry);
-  }
-
-  for (const auto& it : data_sources_) {
-    auto* entry = proto->add_data_sources();
-    it.ToProto(entry);
-  }
-
-  builtin_data_sources_->ToProto(proto->mutable_builtin_data_sources());
-
-  static_assert(sizeof(duration_ms_) == sizeof(proto->duration_ms()),
-                "size mismatch");
-  proto->set_duration_ms(
-      static_cast<decltype(proto->duration_ms())>(duration_ms_));
-
-  static_assert(sizeof(enable_extra_guardrails_) ==
-                    sizeof(proto->enable_extra_guardrails()),
-                "size mismatch");
-  proto->set_enable_extra_guardrails(
-      static_cast<decltype(proto->enable_extra_guardrails())>(
-          enable_extra_guardrails_));
-
-  static_assert(sizeof(lockdown_mode_) == sizeof(proto->lockdown_mode()),
-                "size mismatch");
-  proto->set_lockdown_mode(
-      static_cast<decltype(proto->lockdown_mode())>(lockdown_mode_));
-
-  for (const auto& it : producers_) {
-    auto* entry = proto->add_producers();
-    it.ToProto(entry);
-  }
-
-  statsd_metadata_->ToProto(proto->mutable_statsd_metadata());
-
-  static_assert(sizeof(write_into_file_) == sizeof(proto->write_into_file()),
-                "size mismatch");
-  proto->set_write_into_file(
-      static_cast<decltype(proto->write_into_file())>(write_into_file_));
-
-  static_assert(
-      sizeof(file_write_period_ms_) == sizeof(proto->file_write_period_ms()),
-      "size mismatch");
-  proto->set_file_write_period_ms(
-      static_cast<decltype(proto->file_write_period_ms())>(
-          file_write_period_ms_));
-
-  static_assert(
-      sizeof(max_file_size_bytes_) == sizeof(proto->max_file_size_bytes()),
-      "size mismatch");
-  proto->set_max_file_size_bytes(
-      static_cast<decltype(proto->max_file_size_bytes())>(
-          max_file_size_bytes_));
-
-  guardrail_overrides_->ToProto(proto->mutable_guardrail_overrides());
-
-  static_assert(sizeof(deferred_start_) == sizeof(proto->deferred_start()),
-                "size mismatch");
-  proto->set_deferred_start(
-      static_cast<decltype(proto->deferred_start())>(deferred_start_));
-
-  static_assert(sizeof(flush_period_ms_) == sizeof(proto->flush_period_ms()),
-                "size mismatch");
-  proto->set_flush_period_ms(
-      static_cast<decltype(proto->flush_period_ms())>(flush_period_ms_));
-
-  static_assert(sizeof(flush_timeout_ms_) == sizeof(proto->flush_timeout_ms()),
-                "size mismatch");
-  proto->set_flush_timeout_ms(
-      static_cast<decltype(proto->flush_timeout_ms())>(flush_timeout_ms_));
-
-  static_assert(sizeof(data_source_stop_timeout_ms_) ==
-                    sizeof(proto->data_source_stop_timeout_ms()),
-                "size mismatch");
-  proto->set_data_source_stop_timeout_ms(
-      static_cast<decltype(proto->data_source_stop_timeout_ms())>(
-          data_source_stop_timeout_ms_));
-
-  static_assert(sizeof(notify_traceur_) == sizeof(proto->notify_traceur()),
-                "size mismatch");
-  proto->set_notify_traceur(
-      static_cast<decltype(proto->notify_traceur())>(notify_traceur_));
-
-  trigger_config_->ToProto(proto->mutable_trigger_config());
-
-  for (const auto& it : activate_triggers_) {
-    proto->add_activate_triggers(
-        static_cast<decltype(proto->activate_triggers(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->activate_triggers(0)),
-                  "size mismatch");
-  }
-
-  incremental_state_config_->ToProto(proto->mutable_incremental_state_config());
-
-  static_assert(sizeof(allow_user_build_tracing_) ==
-                    sizeof(proto->allow_user_build_tracing()),
-                "size mismatch");
-  proto->set_allow_user_build_tracing(
-      static_cast<decltype(proto->allow_user_build_tracing())>(
-          allow_user_build_tracing_));
-
-  static_assert(
-      sizeof(unique_session_name_) == sizeof(proto->unique_session_name()),
-      "size mismatch");
-  proto->set_unique_session_name(
-      static_cast<decltype(proto->unique_session_name())>(
-          unique_session_name_));
-
-  static_assert(sizeof(compression_type_) == sizeof(proto->compression_type()),
-                "size mismatch");
-  proto->set_compression_type(
-      static_cast<decltype(proto->compression_type())>(compression_type_));
-
-  incident_report_config_->ToProto(proto->mutable_incident_report_config());
-
-  static_assert(sizeof(trace_uuid_) == sizeof(proto->trace_uuid()),
-                "size mismatch");
-  proto->set_trace_uuid(
-      static_cast<decltype(proto->trace_uuid())>(trace_uuid_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::BufferConfig::BufferConfig() = default;
-TraceConfig::BufferConfig::~BufferConfig() = default;
-TraceConfig::BufferConfig::BufferConfig(const TraceConfig::BufferConfig&) =
-    default;
-TraceConfig::BufferConfig& TraceConfig::BufferConfig::operator=(
-    const TraceConfig::BufferConfig&) = default;
-TraceConfig::BufferConfig::BufferConfig(TraceConfig::BufferConfig&&) noexcept =
-    default;
-TraceConfig::BufferConfig& TraceConfig::BufferConfig::operator=(
-    TraceConfig::BufferConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::BufferConfig::operator==(
-    const TraceConfig::BufferConfig& other) const {
-  return (size_kb_ == other.size_kb_) && (fill_policy_ == other.fill_policy_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::BufferConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_BufferConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::BufferConfig::FromProto(
-    const perfetto::protos::TraceConfig_BufferConfig& proto) {
-  static_assert(sizeof(size_kb_) == sizeof(proto.size_kb()), "size mismatch");
-  size_kb_ = static_cast<decltype(size_kb_)>(proto.size_kb());
-
-  static_assert(sizeof(fill_policy_) == sizeof(proto.fill_policy()),
-                "size mismatch");
-  fill_policy_ = static_cast<decltype(fill_policy_)>(proto.fill_policy());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::BufferConfig::ToProto(
-    perfetto::protos::TraceConfig_BufferConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(size_kb_) == sizeof(proto->size_kb()), "size mismatch");
-  proto->set_size_kb(static_cast<decltype(proto->size_kb())>(size_kb_));
-
-  static_assert(sizeof(fill_policy_) == sizeof(proto->fill_policy()),
-                "size mismatch");
-  proto->set_fill_policy(
-      static_cast<decltype(proto->fill_policy())>(fill_policy_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::DataSource::DataSource() = default;
-TraceConfig::DataSource::~DataSource() = default;
-TraceConfig::DataSource::DataSource(const TraceConfig::DataSource&) = default;
-TraceConfig::DataSource& TraceConfig::DataSource::operator=(
-    const TraceConfig::DataSource&) = default;
-TraceConfig::DataSource::DataSource(TraceConfig::DataSource&&) noexcept =
-    default;
-TraceConfig::DataSource& TraceConfig::DataSource::operator=(
-    TraceConfig::DataSource&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::DataSource::operator==(
-    const TraceConfig::DataSource& other) const {
-  return (config_ == other.config_) &&
-         (producer_name_filter_ == other.producer_name_filter_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::DataSource::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_DataSource proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::DataSource::FromProto(
-    const perfetto::protos::TraceConfig_DataSource& proto) {
-  config_->FromProto(proto.config());
-
-  producer_name_filter_.clear();
-  for (const auto& field : proto.producer_name_filter()) {
-    producer_name_filter_.emplace_back();
-    static_assert(sizeof(producer_name_filter_.back()) ==
-                      sizeof(proto.producer_name_filter(0)),
-                  "size mismatch");
-    producer_name_filter_.back() =
-        static_cast<decltype(producer_name_filter_)::value_type>(field);
-  }
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::DataSource::ToProto(
-    perfetto::protos::TraceConfig_DataSource* proto) const {
-  proto->Clear();
-
-  config_->ToProto(proto->mutable_config());
-
-  for (const auto& it : producer_name_filter_) {
-    proto->add_producer_name_filter(
-        static_cast<decltype(proto->producer_name_filter(0))>(it));
-    static_assert(sizeof(it) == sizeof(proto->producer_name_filter(0)),
-                  "size mismatch");
-  }
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::BuiltinDataSource::BuiltinDataSource() = default;
-TraceConfig::BuiltinDataSource::~BuiltinDataSource() = default;
-TraceConfig::BuiltinDataSource::BuiltinDataSource(
-    const TraceConfig::BuiltinDataSource&) = default;
-TraceConfig::BuiltinDataSource& TraceConfig::BuiltinDataSource::operator=(
-    const TraceConfig::BuiltinDataSource&) = default;
-TraceConfig::BuiltinDataSource::BuiltinDataSource(
-    TraceConfig::BuiltinDataSource&&) noexcept = default;
-TraceConfig::BuiltinDataSource& TraceConfig::BuiltinDataSource::operator=(
-    TraceConfig::BuiltinDataSource&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::BuiltinDataSource::operator==(
-    const TraceConfig::BuiltinDataSource& other) const {
-  return (disable_clock_snapshotting_ == other.disable_clock_snapshotting_) &&
-         (disable_trace_config_ == other.disable_trace_config_) &&
-         (disable_system_info_ == other.disable_system_info_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::BuiltinDataSource::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_BuiltinDataSource proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::BuiltinDataSource::FromProto(
-    const perfetto::protos::TraceConfig_BuiltinDataSource& proto) {
-  static_assert(sizeof(disable_clock_snapshotting_) ==
-                    sizeof(proto.disable_clock_snapshotting()),
-                "size mismatch");
-  disable_clock_snapshotting_ =
-      static_cast<decltype(disable_clock_snapshotting_)>(
-          proto.disable_clock_snapshotting());
-
-  static_assert(
-      sizeof(disable_trace_config_) == sizeof(proto.disable_trace_config()),
-      "size mismatch");
-  disable_trace_config_ = static_cast<decltype(disable_trace_config_)>(
-      proto.disable_trace_config());
-
-  static_assert(
-      sizeof(disable_system_info_) == sizeof(proto.disable_system_info()),
-      "size mismatch");
-  disable_system_info_ =
-      static_cast<decltype(disable_system_info_)>(proto.disable_system_info());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::BuiltinDataSource::ToProto(
-    perfetto::protos::TraceConfig_BuiltinDataSource* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(disable_clock_snapshotting_) ==
-                    sizeof(proto->disable_clock_snapshotting()),
-                "size mismatch");
-  proto->set_disable_clock_snapshotting(
-      static_cast<decltype(proto->disable_clock_snapshotting())>(
-          disable_clock_snapshotting_));
-
-  static_assert(
-      sizeof(disable_trace_config_) == sizeof(proto->disable_trace_config()),
-      "size mismatch");
-  proto->set_disable_trace_config(
-      static_cast<decltype(proto->disable_trace_config())>(
-          disable_trace_config_));
-
-  static_assert(
-      sizeof(disable_system_info_) == sizeof(proto->disable_system_info()),
-      "size mismatch");
-  proto->set_disable_system_info(
-      static_cast<decltype(proto->disable_system_info())>(
-          disable_system_info_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::ProducerConfig::ProducerConfig() = default;
-TraceConfig::ProducerConfig::~ProducerConfig() = default;
-TraceConfig::ProducerConfig::ProducerConfig(
-    const TraceConfig::ProducerConfig&) = default;
-TraceConfig::ProducerConfig& TraceConfig::ProducerConfig::operator=(
-    const TraceConfig::ProducerConfig&) = default;
-TraceConfig::ProducerConfig::ProducerConfig(
-    TraceConfig::ProducerConfig&&) noexcept = default;
-TraceConfig::ProducerConfig& TraceConfig::ProducerConfig::operator=(
-    TraceConfig::ProducerConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::ProducerConfig::operator==(
-    const TraceConfig::ProducerConfig& other) const {
-  return (producer_name_ == other.producer_name_) &&
-         (shm_size_kb_ == other.shm_size_kb_) &&
-         (page_size_kb_ == other.page_size_kb_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::ProducerConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_ProducerConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::ProducerConfig::FromProto(
-    const perfetto::protos::TraceConfig_ProducerConfig& proto) {
-  static_assert(sizeof(producer_name_) == sizeof(proto.producer_name()),
-                "size mismatch");
-  producer_name_ = static_cast<decltype(producer_name_)>(proto.producer_name());
-
-  static_assert(sizeof(shm_size_kb_) == sizeof(proto.shm_size_kb()),
-                "size mismatch");
-  shm_size_kb_ = static_cast<decltype(shm_size_kb_)>(proto.shm_size_kb());
-
-  static_assert(sizeof(page_size_kb_) == sizeof(proto.page_size_kb()),
-                "size mismatch");
-  page_size_kb_ = static_cast<decltype(page_size_kb_)>(proto.page_size_kb());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::ProducerConfig::ToProto(
-    perfetto::protos::TraceConfig_ProducerConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(producer_name_) == sizeof(proto->producer_name()),
-                "size mismatch");
-  proto->set_producer_name(
-      static_cast<decltype(proto->producer_name())>(producer_name_));
-
-  static_assert(sizeof(shm_size_kb_) == sizeof(proto->shm_size_kb()),
-                "size mismatch");
-  proto->set_shm_size_kb(
-      static_cast<decltype(proto->shm_size_kb())>(shm_size_kb_));
-
-  static_assert(sizeof(page_size_kb_) == sizeof(proto->page_size_kb()),
-                "size mismatch");
-  proto->set_page_size_kb(
-      static_cast<decltype(proto->page_size_kb())>(page_size_kb_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::StatsdMetadata::StatsdMetadata() = default;
-TraceConfig::StatsdMetadata::~StatsdMetadata() = default;
-TraceConfig::StatsdMetadata::StatsdMetadata(
-    const TraceConfig::StatsdMetadata&) = default;
-TraceConfig::StatsdMetadata& TraceConfig::StatsdMetadata::operator=(
-    const TraceConfig::StatsdMetadata&) = default;
-TraceConfig::StatsdMetadata::StatsdMetadata(
-    TraceConfig::StatsdMetadata&&) noexcept = default;
-TraceConfig::StatsdMetadata& TraceConfig::StatsdMetadata::operator=(
-    TraceConfig::StatsdMetadata&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::StatsdMetadata::operator==(
-    const TraceConfig::StatsdMetadata& other) const {
-  return (triggering_alert_id_ == other.triggering_alert_id_) &&
-         (triggering_config_uid_ == other.triggering_config_uid_) &&
-         (triggering_config_id_ == other.triggering_config_id_) &&
-         (triggering_subscription_id_ == other.triggering_subscription_id_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::StatsdMetadata::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_StatsdMetadata proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::StatsdMetadata::FromProto(
-    const perfetto::protos::TraceConfig_StatsdMetadata& proto) {
-  static_assert(
-      sizeof(triggering_alert_id_) == sizeof(proto.triggering_alert_id()),
-      "size mismatch");
-  triggering_alert_id_ =
-      static_cast<decltype(triggering_alert_id_)>(proto.triggering_alert_id());
-
-  static_assert(
-      sizeof(triggering_config_uid_) == sizeof(proto.triggering_config_uid()),
-      "size mismatch");
-  triggering_config_uid_ = static_cast<decltype(triggering_config_uid_)>(
-      proto.triggering_config_uid());
-
-  static_assert(
-      sizeof(triggering_config_id_) == sizeof(proto.triggering_config_id()),
-      "size mismatch");
-  triggering_config_id_ = static_cast<decltype(triggering_config_id_)>(
-      proto.triggering_config_id());
-
-  static_assert(sizeof(triggering_subscription_id_) ==
-                    sizeof(proto.triggering_subscription_id()),
-                "size mismatch");
-  triggering_subscription_id_ =
-      static_cast<decltype(triggering_subscription_id_)>(
-          proto.triggering_subscription_id());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::StatsdMetadata::ToProto(
-    perfetto::protos::TraceConfig_StatsdMetadata* proto) const {
-  proto->Clear();
-
-  static_assert(
-      sizeof(triggering_alert_id_) == sizeof(proto->triggering_alert_id()),
-      "size mismatch");
-  proto->set_triggering_alert_id(
-      static_cast<decltype(proto->triggering_alert_id())>(
-          triggering_alert_id_));
-
-  static_assert(
-      sizeof(triggering_config_uid_) == sizeof(proto->triggering_config_uid()),
-      "size mismatch");
-  proto->set_triggering_config_uid(
-      static_cast<decltype(proto->triggering_config_uid())>(
-          triggering_config_uid_));
-
-  static_assert(
-      sizeof(triggering_config_id_) == sizeof(proto->triggering_config_id()),
-      "size mismatch");
-  proto->set_triggering_config_id(
-      static_cast<decltype(proto->triggering_config_id())>(
-          triggering_config_id_));
-
-  static_assert(sizeof(triggering_subscription_id_) ==
-                    sizeof(proto->triggering_subscription_id()),
-                "size mismatch");
-  proto->set_triggering_subscription_id(
-      static_cast<decltype(proto->triggering_subscription_id())>(
-          triggering_subscription_id_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::GuardrailOverrides::GuardrailOverrides() = default;
-TraceConfig::GuardrailOverrides::~GuardrailOverrides() = default;
-TraceConfig::GuardrailOverrides::GuardrailOverrides(
-    const TraceConfig::GuardrailOverrides&) = default;
-TraceConfig::GuardrailOverrides& TraceConfig::GuardrailOverrides::operator=(
-    const TraceConfig::GuardrailOverrides&) = default;
-TraceConfig::GuardrailOverrides::GuardrailOverrides(
-    TraceConfig::GuardrailOverrides&&) noexcept = default;
-TraceConfig::GuardrailOverrides& TraceConfig::GuardrailOverrides::operator=(
-    TraceConfig::GuardrailOverrides&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::GuardrailOverrides::operator==(
-    const TraceConfig::GuardrailOverrides& other) const {
-  return (max_upload_per_day_bytes_ == other.max_upload_per_day_bytes_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::GuardrailOverrides::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_GuardrailOverrides proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::GuardrailOverrides::FromProto(
-    const perfetto::protos::TraceConfig_GuardrailOverrides& proto) {
-  static_assert(sizeof(max_upload_per_day_bytes_) ==
-                    sizeof(proto.max_upload_per_day_bytes()),
-                "size mismatch");
-  max_upload_per_day_bytes_ = static_cast<decltype(max_upload_per_day_bytes_)>(
-      proto.max_upload_per_day_bytes());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::GuardrailOverrides::ToProto(
-    perfetto::protos::TraceConfig_GuardrailOverrides* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(max_upload_per_day_bytes_) ==
-                    sizeof(proto->max_upload_per_day_bytes()),
-                "size mismatch");
-  proto->set_max_upload_per_day_bytes(
-      static_cast<decltype(proto->max_upload_per_day_bytes())>(
-          max_upload_per_day_bytes_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::TriggerConfig::TriggerConfig() = default;
-TraceConfig::TriggerConfig::~TriggerConfig() = default;
-TraceConfig::TriggerConfig::TriggerConfig(const TraceConfig::TriggerConfig&) =
-    default;
-TraceConfig::TriggerConfig& TraceConfig::TriggerConfig::operator=(
-    const TraceConfig::TriggerConfig&) = default;
-TraceConfig::TriggerConfig::TriggerConfig(
-    TraceConfig::TriggerConfig&&) noexcept = default;
-TraceConfig::TriggerConfig& TraceConfig::TriggerConfig::operator=(
-    TraceConfig::TriggerConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::TriggerConfig::operator==(
-    const TraceConfig::TriggerConfig& other) const {
-  return (trigger_mode_ == other.trigger_mode_) &&
-         (triggers_ == other.triggers_) &&
-         (trigger_timeout_ms_ == other.trigger_timeout_ms_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::TriggerConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_TriggerConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::TriggerConfig::FromProto(
-    const perfetto::protos::TraceConfig_TriggerConfig& proto) {
-  static_assert(sizeof(trigger_mode_) == sizeof(proto.trigger_mode()),
-                "size mismatch");
-  trigger_mode_ = static_cast<decltype(trigger_mode_)>(proto.trigger_mode());
-
-  triggers_.clear();
-  for (const auto& field : proto.triggers()) {
-    triggers_.emplace_back();
-    triggers_.back().FromProto(field);
-  }
-
-  static_assert(
-      sizeof(trigger_timeout_ms_) == sizeof(proto.trigger_timeout_ms()),
-      "size mismatch");
-  trigger_timeout_ms_ =
-      static_cast<decltype(trigger_timeout_ms_)>(proto.trigger_timeout_ms());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::TriggerConfig::ToProto(
-    perfetto::protos::TraceConfig_TriggerConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(trigger_mode_) == sizeof(proto->trigger_mode()),
-                "size mismatch");
-  proto->set_trigger_mode(
-      static_cast<decltype(proto->trigger_mode())>(trigger_mode_));
-
-  for (const auto& it : triggers_) {
-    auto* entry = proto->add_triggers();
-    it.ToProto(entry);
-  }
-
-  static_assert(
-      sizeof(trigger_timeout_ms_) == sizeof(proto->trigger_timeout_ms()),
-      "size mismatch");
-  proto->set_trigger_timeout_ms(
-      static_cast<decltype(proto->trigger_timeout_ms())>(trigger_timeout_ms_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::TriggerConfig::Trigger::Trigger() = default;
-TraceConfig::TriggerConfig::Trigger::~Trigger() = default;
-TraceConfig::TriggerConfig::Trigger::Trigger(
-    const TraceConfig::TriggerConfig::Trigger&) = default;
-TraceConfig::TriggerConfig::Trigger& TraceConfig::TriggerConfig::Trigger::
-operator=(const TraceConfig::TriggerConfig::Trigger&) = default;
-TraceConfig::TriggerConfig::Trigger::Trigger(
-    TraceConfig::TriggerConfig::Trigger&&) noexcept = default;
-TraceConfig::TriggerConfig::Trigger& TraceConfig::TriggerConfig::Trigger::
-operator=(TraceConfig::TriggerConfig::Trigger&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::TriggerConfig::Trigger::operator==(
-    const TraceConfig::TriggerConfig::Trigger& other) const {
-  return (name_ == other.name_) &&
-         (producer_name_regex_ == other.producer_name_regex_) &&
-         (stop_delay_ms_ == other.stop_delay_ms_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::TriggerConfig::Trigger::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::TraceConfig_TriggerConfig_Trigger proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::TriggerConfig::Trigger::FromProto(
-    const perfetto::protos::TraceConfig_TriggerConfig_Trigger& proto) {
-  static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
-  name_ = static_cast<decltype(name_)>(proto.name());
-
-  static_assert(
-      sizeof(producer_name_regex_) == sizeof(proto.producer_name_regex()),
-      "size mismatch");
-  producer_name_regex_ =
-      static_cast<decltype(producer_name_regex_)>(proto.producer_name_regex());
-
-  static_assert(sizeof(stop_delay_ms_) == sizeof(proto.stop_delay_ms()),
-                "size mismatch");
-  stop_delay_ms_ = static_cast<decltype(stop_delay_ms_)>(proto.stop_delay_ms());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::TriggerConfig::Trigger::ToProto(
-    perfetto::protos::TraceConfig_TriggerConfig_Trigger* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(name_) == sizeof(proto->name()), "size mismatch");
-  proto->set_name(static_cast<decltype(proto->name())>(name_));
-
-  static_assert(
-      sizeof(producer_name_regex_) == sizeof(proto->producer_name_regex()),
-      "size mismatch");
-  proto->set_producer_name_regex(
-      static_cast<decltype(proto->producer_name_regex())>(
-          producer_name_regex_));
-
-  static_assert(sizeof(stop_delay_ms_) == sizeof(proto->stop_delay_ms()),
-                "size mismatch");
-  proto->set_stop_delay_ms(
-      static_cast<decltype(proto->stop_delay_ms())>(stop_delay_ms_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::IncrementalStateConfig::IncrementalStateConfig() = default;
-TraceConfig::IncrementalStateConfig::~IncrementalStateConfig() = default;
-TraceConfig::IncrementalStateConfig::IncrementalStateConfig(
-    const TraceConfig::IncrementalStateConfig&) = default;
-TraceConfig::IncrementalStateConfig& TraceConfig::IncrementalStateConfig::
-operator=(const TraceConfig::IncrementalStateConfig&) = default;
-TraceConfig::IncrementalStateConfig::IncrementalStateConfig(
-    TraceConfig::IncrementalStateConfig&&) noexcept = default;
-TraceConfig::IncrementalStateConfig& TraceConfig::IncrementalStateConfig::
-operator=(TraceConfig::IncrementalStateConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::IncrementalStateConfig::operator==(
-    const TraceConfig::IncrementalStateConfig& other) const {
-  return (clear_period_ms_ == other.clear_period_ms_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::IncrementalStateConfig::ParseRawProto(
-    const std::string& raw) {
-  perfetto::protos::TraceConfig_IncrementalStateConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::IncrementalStateConfig::FromProto(
-    const perfetto::protos::TraceConfig_IncrementalStateConfig& proto) {
-  static_assert(sizeof(clear_period_ms_) == sizeof(proto.clear_period_ms()),
-                "size mismatch");
-  clear_period_ms_ =
-      static_cast<decltype(clear_period_ms_)>(proto.clear_period_ms());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::IncrementalStateConfig::ToProto(
-    perfetto::protos::TraceConfig_IncrementalStateConfig* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(clear_period_ms_) == sizeof(proto->clear_period_ms()),
-                "size mismatch");
-  proto->set_clear_period_ms(
-      static_cast<decltype(proto->clear_period_ms())>(clear_period_ms_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceConfig::IncidentReportConfig::IncidentReportConfig() = default;
-TraceConfig::IncidentReportConfig::~IncidentReportConfig() = default;
-TraceConfig::IncidentReportConfig::IncidentReportConfig(
-    const TraceConfig::IncidentReportConfig&) = default;
-TraceConfig::IncidentReportConfig& TraceConfig::IncidentReportConfig::operator=(
-    const TraceConfig::IncidentReportConfig&) = default;
-TraceConfig::IncidentReportConfig::IncidentReportConfig(
-    TraceConfig::IncidentReportConfig&&) noexcept = default;
-TraceConfig::IncidentReportConfig& TraceConfig::IncidentReportConfig::operator=(
-    TraceConfig::IncidentReportConfig&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceConfig::IncidentReportConfig::operator==(
-    const TraceConfig::IncidentReportConfig& other) const {
-  return (destination_package_ == other.destination_package_) &&
-         (destination_class_ == other.destination_class_) &&
-         (privacy_level_ == other.privacy_level_) &&
-         (skip_dropbox_ == other.skip_dropbox_);
-}
-#pragma GCC diagnostic pop
-
-void TraceConfig::IncidentReportConfig::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceConfig_IncidentReportConfig proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceConfig::IncidentReportConfig::FromProto(
-    const perfetto::protos::TraceConfig_IncidentReportConfig& proto) {
-  static_assert(
-      sizeof(destination_package_) == sizeof(proto.destination_package()),
-      "size mismatch");
-  destination_package_ =
-      static_cast<decltype(destination_package_)>(proto.destination_package());
-
-  static_assert(sizeof(destination_class_) == sizeof(proto.destination_class()),
-                "size mismatch");
-  destination_class_ =
-      static_cast<decltype(destination_class_)>(proto.destination_class());
-
-  static_assert(sizeof(privacy_level_) == sizeof(proto.privacy_level()),
-                "size mismatch");
-  privacy_level_ = static_cast<decltype(privacy_level_)>(proto.privacy_level());
-
-  static_assert(sizeof(skip_dropbox_) == sizeof(proto.skip_dropbox()),
-                "size mismatch");
-  skip_dropbox_ = static_cast<decltype(skip_dropbox_)>(proto.skip_dropbox());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceConfig::IncidentReportConfig::ToProto(
-    perfetto::protos::TraceConfig_IncidentReportConfig* proto) const {
-  proto->Clear();
-
-  static_assert(
-      sizeof(destination_package_) == sizeof(proto->destination_package()),
-      "size mismatch");
-  proto->set_destination_package(
-      static_cast<decltype(proto->destination_package())>(
-          destination_package_));
-
-  static_assert(
-      sizeof(destination_class_) == sizeof(proto->destination_class()),
-      "size mismatch");
-  proto->set_destination_class(
-      static_cast<decltype(proto->destination_class())>(destination_class_));
-
-  static_assert(sizeof(privacy_level_) == sizeof(proto->privacy_level()),
-                "size mismatch");
-  proto->set_privacy_level(
-      static_cast<decltype(proto->privacy_level())>(privacy_level_));
-
-  static_assert(sizeof(skip_dropbox_) == sizeof(proto->skip_dropbox()),
-                "size mismatch");
-  proto->set_skip_dropbox(
-      static_cast<decltype(proto->skip_dropbox())>(skip_dropbox_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/trace_stats.cc b/src/tracing/core/trace_stats.cc
deleted file mode 100644
index b021524..0000000
--- a/src/tracing/core/trace_stats.cc
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/trace_stats.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/ext/tracing/core/trace_stats.h"
-
-#include "protos/perfetto/common/trace_stats.pb.h"
-
-namespace perfetto {
-
-TraceStats::TraceStats() = default;
-TraceStats::~TraceStats() = default;
-TraceStats::TraceStats(const TraceStats&) = default;
-TraceStats& TraceStats::operator=(const TraceStats&) = default;
-TraceStats::TraceStats(TraceStats&&) noexcept = default;
-TraceStats& TraceStats::operator=(TraceStats&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceStats::operator==(const TraceStats& other) const {
-  return (buffer_stats_ == other.buffer_stats_) &&
-         (producers_connected_ == other.producers_connected_) &&
-         (producers_seen_ == other.producers_seen_) &&
-         (data_sources_registered_ == other.data_sources_registered_) &&
-         (data_sources_seen_ == other.data_sources_seen_) &&
-         (tracing_sessions_ == other.tracing_sessions_) &&
-         (total_buffers_ == other.total_buffers_) &&
-         (chunks_discarded_ == other.chunks_discarded_) &&
-         (patches_discarded_ == other.patches_discarded_) &&
-         (invalid_packets_ == other.invalid_packets_);
-}
-#pragma GCC diagnostic pop
-
-void TraceStats::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceStats proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceStats::FromProto(const perfetto::protos::TraceStats& proto) {
-  buffer_stats_.clear();
-  for (const auto& field : proto.buffer_stats()) {
-    buffer_stats_.emplace_back();
-    buffer_stats_.back().FromProto(field);
-  }
-
-  static_assert(
-      sizeof(producers_connected_) == sizeof(proto.producers_connected()),
-      "size mismatch");
-  producers_connected_ =
-      static_cast<decltype(producers_connected_)>(proto.producers_connected());
-
-  static_assert(sizeof(producers_seen_) == sizeof(proto.producers_seen()),
-                "size mismatch");
-  producers_seen_ =
-      static_cast<decltype(producers_seen_)>(proto.producers_seen());
-
-  static_assert(sizeof(data_sources_registered_) ==
-                    sizeof(proto.data_sources_registered()),
-                "size mismatch");
-  data_sources_registered_ = static_cast<decltype(data_sources_registered_)>(
-      proto.data_sources_registered());
-
-  static_assert(sizeof(data_sources_seen_) == sizeof(proto.data_sources_seen()),
-                "size mismatch");
-  data_sources_seen_ =
-      static_cast<decltype(data_sources_seen_)>(proto.data_sources_seen());
-
-  static_assert(sizeof(tracing_sessions_) == sizeof(proto.tracing_sessions()),
-                "size mismatch");
-  tracing_sessions_ =
-      static_cast<decltype(tracing_sessions_)>(proto.tracing_sessions());
-
-  static_assert(sizeof(total_buffers_) == sizeof(proto.total_buffers()),
-                "size mismatch");
-  total_buffers_ = static_cast<decltype(total_buffers_)>(proto.total_buffers());
-
-  static_assert(sizeof(chunks_discarded_) == sizeof(proto.chunks_discarded()),
-                "size mismatch");
-  chunks_discarded_ =
-      static_cast<decltype(chunks_discarded_)>(proto.chunks_discarded());
-
-  static_assert(sizeof(patches_discarded_) == sizeof(proto.patches_discarded()),
-                "size mismatch");
-  patches_discarded_ =
-      static_cast<decltype(patches_discarded_)>(proto.patches_discarded());
-
-  static_assert(sizeof(invalid_packets_) == sizeof(proto.invalid_packets()),
-                "size mismatch");
-  invalid_packets_ =
-      static_cast<decltype(invalid_packets_)>(proto.invalid_packets());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceStats::ToProto(perfetto::protos::TraceStats* proto) const {
-  proto->Clear();
-
-  for (const auto& it : buffer_stats_) {
-    auto* entry = proto->add_buffer_stats();
-    it.ToProto(entry);
-  }
-
-  static_assert(
-      sizeof(producers_connected_) == sizeof(proto->producers_connected()),
-      "size mismatch");
-  proto->set_producers_connected(
-      static_cast<decltype(proto->producers_connected())>(
-          producers_connected_));
-
-  static_assert(sizeof(producers_seen_) == sizeof(proto->producers_seen()),
-                "size mismatch");
-  proto->set_producers_seen(
-      static_cast<decltype(proto->producers_seen())>(producers_seen_));
-
-  static_assert(sizeof(data_sources_registered_) ==
-                    sizeof(proto->data_sources_registered()),
-                "size mismatch");
-  proto->set_data_sources_registered(
-      static_cast<decltype(proto->data_sources_registered())>(
-          data_sources_registered_));
-
-  static_assert(
-      sizeof(data_sources_seen_) == sizeof(proto->data_sources_seen()),
-      "size mismatch");
-  proto->set_data_sources_seen(
-      static_cast<decltype(proto->data_sources_seen())>(data_sources_seen_));
-
-  static_assert(sizeof(tracing_sessions_) == sizeof(proto->tracing_sessions()),
-                "size mismatch");
-  proto->set_tracing_sessions(
-      static_cast<decltype(proto->tracing_sessions())>(tracing_sessions_));
-
-  static_assert(sizeof(total_buffers_) == sizeof(proto->total_buffers()),
-                "size mismatch");
-  proto->set_total_buffers(
-      static_cast<decltype(proto->total_buffers())>(total_buffers_));
-
-  static_assert(sizeof(chunks_discarded_) == sizeof(proto->chunks_discarded()),
-                "size mismatch");
-  proto->set_chunks_discarded(
-      static_cast<decltype(proto->chunks_discarded())>(chunks_discarded_));
-
-  static_assert(
-      sizeof(patches_discarded_) == sizeof(proto->patches_discarded()),
-      "size mismatch");
-  proto->set_patches_discarded(
-      static_cast<decltype(proto->patches_discarded())>(patches_discarded_));
-
-  static_assert(sizeof(invalid_packets_) == sizeof(proto->invalid_packets()),
-                "size mismatch");
-  proto->set_invalid_packets(
-      static_cast<decltype(proto->invalid_packets())>(invalid_packets_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TraceStats::BufferStats::BufferStats() = default;
-TraceStats::BufferStats::~BufferStats() = default;
-TraceStats::BufferStats::BufferStats(const TraceStats::BufferStats&) = default;
-TraceStats::BufferStats& TraceStats::BufferStats::operator=(
-    const TraceStats::BufferStats&) = default;
-TraceStats::BufferStats::BufferStats(TraceStats::BufferStats&&) noexcept =
-    default;
-TraceStats::BufferStats& TraceStats::BufferStats::operator=(
-    TraceStats::BufferStats&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TraceStats::BufferStats::operator==(
-    const TraceStats::BufferStats& other) const {
-  return (buffer_size_ == other.buffer_size_) &&
-         (bytes_written_ == other.bytes_written_) &&
-         (bytes_overwritten_ == other.bytes_overwritten_) &&
-         (bytes_read_ == other.bytes_read_) &&
-         (padding_bytes_written_ == other.padding_bytes_written_) &&
-         (padding_bytes_cleared_ == other.padding_bytes_cleared_) &&
-         (chunks_written_ == other.chunks_written_) &&
-         (chunks_rewritten_ == other.chunks_rewritten_) &&
-         (chunks_overwritten_ == other.chunks_overwritten_) &&
-         (chunks_discarded_ == other.chunks_discarded_) &&
-         (chunks_read_ == other.chunks_read_) &&
-         (chunks_committed_out_of_order_ ==
-          other.chunks_committed_out_of_order_) &&
-         (write_wrap_count_ == other.write_wrap_count_) &&
-         (patches_succeeded_ == other.patches_succeeded_) &&
-         (patches_failed_ == other.patches_failed_) &&
-         (readaheads_succeeded_ == other.readaheads_succeeded_) &&
-         (readaheads_failed_ == other.readaheads_failed_) &&
-         (abi_violations_ == other.abi_violations_) &&
-         (trace_writer_packet_loss_ == other.trace_writer_packet_loss_);
-}
-#pragma GCC diagnostic pop
-
-void TraceStats::BufferStats::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TraceStats_BufferStats proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TraceStats::BufferStats::FromProto(
-    const perfetto::protos::TraceStats_BufferStats& proto) {
-  static_assert(sizeof(buffer_size_) == sizeof(proto.buffer_size()),
-                "size mismatch");
-  buffer_size_ = static_cast<decltype(buffer_size_)>(proto.buffer_size());
-
-  static_assert(sizeof(bytes_written_) == sizeof(proto.bytes_written()),
-                "size mismatch");
-  bytes_written_ = static_cast<decltype(bytes_written_)>(proto.bytes_written());
-
-  static_assert(sizeof(bytes_overwritten_) == sizeof(proto.bytes_overwritten()),
-                "size mismatch");
-  bytes_overwritten_ =
-      static_cast<decltype(bytes_overwritten_)>(proto.bytes_overwritten());
-
-  static_assert(sizeof(bytes_read_) == sizeof(proto.bytes_read()),
-                "size mismatch");
-  bytes_read_ = static_cast<decltype(bytes_read_)>(proto.bytes_read());
-
-  static_assert(
-      sizeof(padding_bytes_written_) == sizeof(proto.padding_bytes_written()),
-      "size mismatch");
-  padding_bytes_written_ = static_cast<decltype(padding_bytes_written_)>(
-      proto.padding_bytes_written());
-
-  static_assert(
-      sizeof(padding_bytes_cleared_) == sizeof(proto.padding_bytes_cleared()),
-      "size mismatch");
-  padding_bytes_cleared_ = static_cast<decltype(padding_bytes_cleared_)>(
-      proto.padding_bytes_cleared());
-
-  static_assert(sizeof(chunks_written_) == sizeof(proto.chunks_written()),
-                "size mismatch");
-  chunks_written_ =
-      static_cast<decltype(chunks_written_)>(proto.chunks_written());
-
-  static_assert(sizeof(chunks_rewritten_) == sizeof(proto.chunks_rewritten()),
-                "size mismatch");
-  chunks_rewritten_ =
-      static_cast<decltype(chunks_rewritten_)>(proto.chunks_rewritten());
-
-  static_assert(
-      sizeof(chunks_overwritten_) == sizeof(proto.chunks_overwritten()),
-      "size mismatch");
-  chunks_overwritten_ =
-      static_cast<decltype(chunks_overwritten_)>(proto.chunks_overwritten());
-
-  static_assert(sizeof(chunks_discarded_) == sizeof(proto.chunks_discarded()),
-                "size mismatch");
-  chunks_discarded_ =
-      static_cast<decltype(chunks_discarded_)>(proto.chunks_discarded());
-
-  static_assert(sizeof(chunks_read_) == sizeof(proto.chunks_read()),
-                "size mismatch");
-  chunks_read_ = static_cast<decltype(chunks_read_)>(proto.chunks_read());
-
-  static_assert(sizeof(chunks_committed_out_of_order_) ==
-                    sizeof(proto.chunks_committed_out_of_order()),
-                "size mismatch");
-  chunks_committed_out_of_order_ =
-      static_cast<decltype(chunks_committed_out_of_order_)>(
-          proto.chunks_committed_out_of_order());
-
-  static_assert(sizeof(write_wrap_count_) == sizeof(proto.write_wrap_count()),
-                "size mismatch");
-  write_wrap_count_ =
-      static_cast<decltype(write_wrap_count_)>(proto.write_wrap_count());
-
-  static_assert(sizeof(patches_succeeded_) == sizeof(proto.patches_succeeded()),
-                "size mismatch");
-  patches_succeeded_ =
-      static_cast<decltype(patches_succeeded_)>(proto.patches_succeeded());
-
-  static_assert(sizeof(patches_failed_) == sizeof(proto.patches_failed()),
-                "size mismatch");
-  patches_failed_ =
-      static_cast<decltype(patches_failed_)>(proto.patches_failed());
-
-  static_assert(
-      sizeof(readaheads_succeeded_) == sizeof(proto.readaheads_succeeded()),
-      "size mismatch");
-  readaheads_succeeded_ = static_cast<decltype(readaheads_succeeded_)>(
-      proto.readaheads_succeeded());
-
-  static_assert(sizeof(readaheads_failed_) == sizeof(proto.readaheads_failed()),
-                "size mismatch");
-  readaheads_failed_ =
-      static_cast<decltype(readaheads_failed_)>(proto.readaheads_failed());
-
-  static_assert(sizeof(abi_violations_) == sizeof(proto.abi_violations()),
-                "size mismatch");
-  abi_violations_ =
-      static_cast<decltype(abi_violations_)>(proto.abi_violations());
-
-  static_assert(sizeof(trace_writer_packet_loss_) ==
-                    sizeof(proto.trace_writer_packet_loss()),
-                "size mismatch");
-  trace_writer_packet_loss_ = static_cast<decltype(trace_writer_packet_loss_)>(
-      proto.trace_writer_packet_loss());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TraceStats::BufferStats::ToProto(
-    perfetto::protos::TraceStats_BufferStats* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(buffer_size_) == sizeof(proto->buffer_size()),
-                "size mismatch");
-  proto->set_buffer_size(
-      static_cast<decltype(proto->buffer_size())>(buffer_size_));
-
-  static_assert(sizeof(bytes_written_) == sizeof(proto->bytes_written()),
-                "size mismatch");
-  proto->set_bytes_written(
-      static_cast<decltype(proto->bytes_written())>(bytes_written_));
-
-  static_assert(
-      sizeof(bytes_overwritten_) == sizeof(proto->bytes_overwritten()),
-      "size mismatch");
-  proto->set_bytes_overwritten(
-      static_cast<decltype(proto->bytes_overwritten())>(bytes_overwritten_));
-
-  static_assert(sizeof(bytes_read_) == sizeof(proto->bytes_read()),
-                "size mismatch");
-  proto->set_bytes_read(
-      static_cast<decltype(proto->bytes_read())>(bytes_read_));
-
-  static_assert(
-      sizeof(padding_bytes_written_) == sizeof(proto->padding_bytes_written()),
-      "size mismatch");
-  proto->set_padding_bytes_written(
-      static_cast<decltype(proto->padding_bytes_written())>(
-          padding_bytes_written_));
-
-  static_assert(
-      sizeof(padding_bytes_cleared_) == sizeof(proto->padding_bytes_cleared()),
-      "size mismatch");
-  proto->set_padding_bytes_cleared(
-      static_cast<decltype(proto->padding_bytes_cleared())>(
-          padding_bytes_cleared_));
-
-  static_assert(sizeof(chunks_written_) == sizeof(proto->chunks_written()),
-                "size mismatch");
-  proto->set_chunks_written(
-      static_cast<decltype(proto->chunks_written())>(chunks_written_));
-
-  static_assert(sizeof(chunks_rewritten_) == sizeof(proto->chunks_rewritten()),
-                "size mismatch");
-  proto->set_chunks_rewritten(
-      static_cast<decltype(proto->chunks_rewritten())>(chunks_rewritten_));
-
-  static_assert(
-      sizeof(chunks_overwritten_) == sizeof(proto->chunks_overwritten()),
-      "size mismatch");
-  proto->set_chunks_overwritten(
-      static_cast<decltype(proto->chunks_overwritten())>(chunks_overwritten_));
-
-  static_assert(sizeof(chunks_discarded_) == sizeof(proto->chunks_discarded()),
-                "size mismatch");
-  proto->set_chunks_discarded(
-      static_cast<decltype(proto->chunks_discarded())>(chunks_discarded_));
-
-  static_assert(sizeof(chunks_read_) == sizeof(proto->chunks_read()),
-                "size mismatch");
-  proto->set_chunks_read(
-      static_cast<decltype(proto->chunks_read())>(chunks_read_));
-
-  static_assert(sizeof(chunks_committed_out_of_order_) ==
-                    sizeof(proto->chunks_committed_out_of_order()),
-                "size mismatch");
-  proto->set_chunks_committed_out_of_order(
-      static_cast<decltype(proto->chunks_committed_out_of_order())>(
-          chunks_committed_out_of_order_));
-
-  static_assert(sizeof(write_wrap_count_) == sizeof(proto->write_wrap_count()),
-                "size mismatch");
-  proto->set_write_wrap_count(
-      static_cast<decltype(proto->write_wrap_count())>(write_wrap_count_));
-
-  static_assert(
-      sizeof(patches_succeeded_) == sizeof(proto->patches_succeeded()),
-      "size mismatch");
-  proto->set_patches_succeeded(
-      static_cast<decltype(proto->patches_succeeded())>(patches_succeeded_));
-
-  static_assert(sizeof(patches_failed_) == sizeof(proto->patches_failed()),
-                "size mismatch");
-  proto->set_patches_failed(
-      static_cast<decltype(proto->patches_failed())>(patches_failed_));
-
-  static_assert(
-      sizeof(readaheads_succeeded_) == sizeof(proto->readaheads_succeeded()),
-      "size mismatch");
-  proto->set_readaheads_succeeded(
-      static_cast<decltype(proto->readaheads_succeeded())>(
-          readaheads_succeeded_));
-
-  static_assert(
-      sizeof(readaheads_failed_) == sizeof(proto->readaheads_failed()),
-      "size mismatch");
-  proto->set_readaheads_failed(
-      static_cast<decltype(proto->readaheads_failed())>(readaheads_failed_));
-
-  static_assert(sizeof(abi_violations_) == sizeof(proto->abi_violations()),
-                "size mismatch");
-  proto->set_abi_violations(
-      static_cast<decltype(proto->abi_violations())>(abi_violations_));
-
-  static_assert(sizeof(trace_writer_packet_loss_) ==
-                    sizeof(proto->trace_writer_packet_loss()),
-                "size mismatch");
-  proto->set_trace_writer_packet_loss(
-      static_cast<decltype(proto->trace_writer_packet_loss())>(
-          trace_writer_packet_loss_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 91d2b44..dfd73db 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -334,9 +334,9 @@
   PERFETTO_DCHECK_THREAD(thread_checker_);
   PERFETTO_DLOG("Enabling tracing for consumer %p",
                 reinterpret_cast<void*>(consumer));
-  if (cfg.lockdown_mode() == TraceConfig::LockdownModeOperation::LOCKDOWN_SET)
+  if (cfg.lockdown_mode() == TraceConfig::LOCKDOWN_SET)
     lockdown_mode_ = true;
-  if (cfg.lockdown_mode() == TraceConfig::LockdownModeOperation::LOCKDOWN_CLEAR)
+  if (cfg.lockdown_mode() == TraceConfig::LOCKDOWN_CLEAR)
     lockdown_mode_ = false;
   TracingSession* tracing_session =
       GetTracingSession(consumer->tracing_session_id_);
@@ -2529,11 +2529,9 @@
   change->set_producer_name(producer.name_);
   change->set_data_source_name(instance.data_source_name);
   if (instance.state == DataSourceInstance::STARTED) {
-    change->set_state(ObservableEvents::DataSourceInstanceStateChange::
-                          DATA_SOURCE_INSTANCE_STATE_STARTED);
+    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
   } else {
-    change->set_state(ObservableEvents::DataSourceInstanceStateChange::
-                          DATA_SOURCE_INSTANCE_STATE_STOPPED);
+    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED);
   }
 }
 
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 3479e1e..b301612 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -1127,8 +1127,7 @@
   trace_config.add_buffers()->set_size_kb(128);
   auto* ds_config = trace_config.add_data_sources()->mutable_config();
   ds_config->set_name("data_source");
-  trace_config.set_lockdown_mode(
-      TraceConfig::LockdownModeOperation::LOCKDOWN_SET);
+  trace_config.set_lockdown_mode(TraceConfig::LOCKDOWN_SET);
   consumer->EnableTracing(trace_config);
 
   producer->WaitForTracingSetup();
@@ -1147,8 +1146,7 @@
   producer->WaitForDataSourceStop("data_source");
   consumer->WaitForTracingDisabled();
 
-  trace_config.set_lockdown_mode(
-      TraceConfig::LockdownModeOperation::LOCKDOWN_CLEAR);
+  trace_config.set_lockdown_mode(TraceConfig::LOCKDOWN_CLEAR);
   consumer->EnableTracing(trace_config);
   producer->WaitForDataSourceSetup("data_source");
   producer->WaitForDataSourceStart("data_source");
@@ -2703,8 +2701,7 @@
     ObservableEvents::DataSourceInstanceStateChange change;
     change.set_producer_name("mock_producer");
     change.set_data_source_name("data_source");
-    change.set_state(ObservableEvents::DataSourceInstanceStateChange::
-                         DATA_SOURCE_INSTANCE_STATE_STARTED);
+    change.set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
     EXPECT_EQ(events.instance_state_changes_size(), 1);
     EXPECT_THAT(events.instance_state_changes(), Contains(Eq(change)));
   }
@@ -2718,8 +2715,7 @@
     ObservableEvents::DataSourceInstanceStateChange change;
     change.set_producer_name("mock_producer");
     change.set_data_source_name("data_source");
-    change.set_state(ObservableEvents::DataSourceInstanceStateChange::
-                         DATA_SOURCE_INSTANCE_STATE_STOPPED);
+    change.set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED);
     EXPECT_EQ(events.instance_state_changes_size(), 1);
     EXPECT_THAT(events.instance_state_changes(), Contains(Eq(change)));
   }
@@ -2739,8 +2735,7 @@
     ObservableEvents::DataSourceInstanceStateChange change;
     change.set_producer_name("mock_producer");
     change.set_data_source_name("data_source");
-    change.set_state(ObservableEvents::DataSourceInstanceStateChange::
-                         DATA_SOURCE_INSTANCE_STATE_STOPPED);
+    change.set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED);
     EXPECT_EQ(events.instance_state_changes_size(), 1);
     EXPECT_THAT(events.instance_state_changes(), Contains(Eq(change)));
   }
@@ -2756,8 +2751,7 @@
     ObservableEvents::DataSourceInstanceStateChange change;
     change.set_producer_name("mock_producer");
     change.set_data_source_name("data_source");
-    change.set_state(ObservableEvents::DataSourceInstanceStateChange::
-                         DATA_SOURCE_INSTANCE_STATE_STARTED);
+    change.set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
     EXPECT_EQ(events.instance_state_changes_size(), 1);
     EXPECT_THAT(events.instance_state_changes(), Contains(Eq(change)));
   }
@@ -2803,8 +2797,7 @@
         event.add_instance_state_changes();
     change->set_producer_name("mock_producer");
     change->set_data_source_name("data_source");
-    change->set_state(ObservableEvents::DataSourceInstanceStateChange::
-                          DATA_SOURCE_INSTANCE_STATE_STARTED);
+    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
     EXPECT_CALL(*consumer, OnObservableEvents(Eq(event)))
         .WillOnce(InvokeWithoutArgs(
             task_runner.CreateCheckpoint("data_source_started")));
@@ -2817,8 +2810,7 @@
         event.add_instance_state_changes();
     change->set_producer_name("mock_producer");
     change->set_data_source_name("data_source");
-    change->set_state(ObservableEvents::DataSourceInstanceStateChange::
-                          DATA_SOURCE_INSTANCE_STATE_STOPPED);
+    change->set_state(ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED);
     EXPECT_CALL(*consumer, OnObservableEvents(Eq(event)))
         .WillOnce(InvokeWithoutArgs(
             task_runner.CreateCheckpoint("data_source_stopped")));
diff --git a/src/tracing/core/tracing_service_state.cc b/src/tracing/core/tracing_service_state.cc
deleted file mode 100644
index 8442445..0000000
--- a/src/tracing/core/tracing_service_state.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * protos/perfetto/common/tracing_service_state.proto
- * by
- * ../../tools/proto_to_cpp/proto_to_cpp.cc.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-#include "perfetto/tracing/core/tracing_service_state.h"
-
-#include "protos/perfetto/common/tracing_service_state.pb.h"
-
-#include "perfetto/tracing/core/data_source_descriptor.h"
-#include "protos/perfetto/common/data_source_descriptor.pb.h"
-
-namespace perfetto {
-
-TracingServiceState::TracingServiceState() = default;
-TracingServiceState::~TracingServiceState() = default;
-TracingServiceState::TracingServiceState(const TracingServiceState&) = default;
-TracingServiceState& TracingServiceState::operator=(
-    const TracingServiceState&) = default;
-TracingServiceState::TracingServiceState(TracingServiceState&&) noexcept =
-    default;
-TracingServiceState& TracingServiceState::operator=(TracingServiceState&&) =
-    default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TracingServiceState::operator==(const TracingServiceState& other) const {
-  return (producers_ == other.producers_) &&
-         (data_sources_ == other.data_sources_) &&
-         (num_sessions_ == other.num_sessions_) &&
-         (num_sessions_started_ == other.num_sessions_started_);
-}
-#pragma GCC diagnostic pop
-
-void TracingServiceState::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TracingServiceState proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TracingServiceState::FromProto(
-    const perfetto::protos::TracingServiceState& proto) {
-  producers_.clear();
-  for (const auto& field : proto.producers()) {
-    producers_.emplace_back();
-    producers_.back().FromProto(field);
-  }
-
-  data_sources_.clear();
-  for (const auto& field : proto.data_sources()) {
-    data_sources_.emplace_back();
-    data_sources_.back().FromProto(field);
-  }
-
-  static_assert(sizeof(num_sessions_) == sizeof(proto.num_sessions()),
-                "size mismatch");
-  num_sessions_ = static_cast<decltype(num_sessions_)>(proto.num_sessions());
-
-  static_assert(
-      sizeof(num_sessions_started_) == sizeof(proto.num_sessions_started()),
-      "size mismatch");
-  num_sessions_started_ = static_cast<decltype(num_sessions_started_)>(
-      proto.num_sessions_started());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TracingServiceState::ToProto(
-    perfetto::protos::TracingServiceState* proto) const {
-  proto->Clear();
-
-  for (const auto& it : producers_) {
-    auto* entry = proto->add_producers();
-    it.ToProto(entry);
-  }
-
-  for (const auto& it : data_sources_) {
-    auto* entry = proto->add_data_sources();
-    it.ToProto(entry);
-  }
-
-  static_assert(sizeof(num_sessions_) == sizeof(proto->num_sessions()),
-                "size mismatch");
-  proto->set_num_sessions(
-      static_cast<decltype(proto->num_sessions())>(num_sessions_));
-
-  static_assert(
-      sizeof(num_sessions_started_) == sizeof(proto->num_sessions_started()),
-      "size mismatch");
-  proto->set_num_sessions_started(
-      static_cast<decltype(proto->num_sessions_started())>(
-          num_sessions_started_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TracingServiceState::Producer::Producer() = default;
-TracingServiceState::Producer::~Producer() = default;
-TracingServiceState::Producer::Producer(const TracingServiceState::Producer&) =
-    default;
-TracingServiceState::Producer& TracingServiceState::Producer::operator=(
-    const TracingServiceState::Producer&) = default;
-TracingServiceState::Producer::Producer(
-    TracingServiceState::Producer&&) noexcept = default;
-TracingServiceState::Producer& TracingServiceState::Producer::operator=(
-    TracingServiceState::Producer&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TracingServiceState::Producer::operator==(
-    const TracingServiceState::Producer& other) const {
-  return (id_ == other.id_) && (name_ == other.name_) && (uid_ == other.uid_);
-}
-#pragma GCC diagnostic pop
-
-void TracingServiceState::Producer::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TracingServiceState_Producer proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TracingServiceState::Producer::FromProto(
-    const perfetto::protos::TracingServiceState_Producer& proto) {
-  static_assert(sizeof(id_) == sizeof(proto.id()), "size mismatch");
-  id_ = static_cast<decltype(id_)>(proto.id());
-
-  static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
-  name_ = static_cast<decltype(name_)>(proto.name());
-
-  static_assert(sizeof(uid_) == sizeof(proto.uid()), "size mismatch");
-  uid_ = static_cast<decltype(uid_)>(proto.uid());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TracingServiceState::Producer::ToProto(
-    perfetto::protos::TracingServiceState_Producer* proto) const {
-  proto->Clear();
-
-  static_assert(sizeof(id_) == sizeof(proto->id()), "size mismatch");
-  proto->set_id(static_cast<decltype(proto->id())>(id_));
-
-  static_assert(sizeof(name_) == sizeof(proto->name()), "size mismatch");
-  proto->set_name(static_cast<decltype(proto->name())>(name_));
-
-  static_assert(sizeof(uid_) == sizeof(proto->uid()), "size mismatch");
-  proto->set_uid(static_cast<decltype(proto->uid())>(uid_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-TracingServiceState::DataSource::DataSource() = default;
-TracingServiceState::DataSource::~DataSource() = default;
-TracingServiceState::DataSource::DataSource(
-    const TracingServiceState::DataSource&) = default;
-TracingServiceState::DataSource& TracingServiceState::DataSource::operator=(
-    const TracingServiceState::DataSource&) = default;
-TracingServiceState::DataSource::DataSource(
-    TracingServiceState::DataSource&&) noexcept = default;
-TracingServiceState::DataSource& TracingServiceState::DataSource::operator=(
-    TracingServiceState::DataSource&&) = default;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-bool TracingServiceState::DataSource::operator==(
-    const TracingServiceState::DataSource& other) const {
-  return (ds_descriptor_ == other.ds_descriptor_) &&
-         (producer_id_ == other.producer_id_);
-}
-#pragma GCC diagnostic pop
-
-void TracingServiceState::DataSource::ParseRawProto(const std::string& raw) {
-  perfetto::protos::TracingServiceState_DataSource proto;
-  proto.ParseFromString(raw);
-  FromProto(proto);
-}
-
-void TracingServiceState::DataSource::FromProto(
-    const perfetto::protos::TracingServiceState_DataSource& proto) {
-  ds_descriptor_->FromProto(proto.ds_descriptor());
-
-  static_assert(sizeof(producer_id_) == sizeof(proto.producer_id()),
-                "size mismatch");
-  producer_id_ = static_cast<decltype(producer_id_)>(proto.producer_id());
-  unknown_fields_ = proto.unknown_fields();
-}
-
-void TracingServiceState::DataSource::ToProto(
-    perfetto::protos::TracingServiceState_DataSource* proto) const {
-  proto->Clear();
-
-  ds_descriptor_->ToProto(proto->mutable_ds_descriptor());
-
-  static_assert(sizeof(producer_id_) == sizeof(proto->producer_id()),
-                "size mismatch");
-  proto->set_producer_id(
-      static_cast<decltype(proto->producer_id())>(producer_id_));
-  *(proto->mutable_unknown_fields()) = unknown_fields_;
-}
-
-}  // namespace perfetto
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index 2c25ab8..5f8dd4f 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -245,8 +245,7 @@
                               state_change.data_source_name()};
       data_source_states_[handle] =
           state_change.state() ==
-          ObservableEvents::DataSourceInstanceStateChange::
-              DATA_SOURCE_INSTANCE_STATE_STARTED;
+          ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED;
     }
     // Data sources are first reported as being stopped before starting, so once
     // all the data sources we know about have started we can declare tracing
diff --git a/test/BUILD.gn b/test/BUILD.gn
index fae46eb..b9e6654 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -26,6 +26,7 @@
     "../gn:gtest_and_gmock",
     "../include/perfetto/ext/traced",
     "../include/perfetto/protozero",
+    "../protos/perfetto/config:cpp",
     "../protos/perfetto/config:zero",
     "../protos/perfetto/config/power:zero",
     "../protos/perfetto/trace:lite",
@@ -111,6 +112,7 @@
     ":task_runner_thread",
     "../gn:default_deps",
     "../include/perfetto/ext/traced",
+    "../protos/perfetto/config:cpp",
     "../src/base:test_support",
     "../src/traced/probes:probes_src",
     "../src/tracing:ipc",
@@ -157,6 +159,7 @@
       "../gn:default_deps",
       "../gn:gtest_and_gmock",
       "../include/perfetto/ext/traced",
+      "../protos/perfetto/config:cpp",
       "../protos/perfetto/trace:lite",
       "../protos/perfetto/trace:zero",
       "../src/base:test_support",
diff --git a/test/cts/Android.bp b/test/cts/Android.bp
index 2ef5a35..69803de 100644
--- a/test/cts/Android.bp
+++ b/test/cts/Android.bp
@@ -6,6 +6,10 @@
     "heapprofd_test_cts.cc",
     "heapprofd_java_test_cts.cc",
     "utils.cc",
+    ":perfetto_protos_perfetto_config_cpp_gen",
+  ],
+  generated_headers: [
+    "perfetto_protos_perfetto_config_cpp_gen_headers",
   ],
   static_libs: [
     "libgmock",
diff --git a/test/cts/end_to_end_integrationtest_cts.cc b/test/cts/end_to_end_integrationtest_cts.cc
index 432e81a..e174bb4 100644
--- a/test/cts/end_to_end_integrationtest_cts.cc
+++ b/test/cts/end_to_end_integrationtest_cts.cc
@@ -21,10 +21,10 @@
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/tracing/core/data_source_config.h"
-#include "perfetto/tracing/core/test_config.h"
 #include "src/base/test/test_task_runner.h"
 #include "test/test_helper.h"
 
+#include "protos/perfetto/config/test_config.gen.h"
 #include "protos/perfetto/trace/test_event.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pb.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/test/cts/heapprofd_java_test_cts.cc b/test/cts/heapprofd_java_test_cts.cc
index 3ad1316..a2f26b7 100644
--- a/test/cts/heapprofd_java_test_cts.cc
+++ b/test/cts/heapprofd_java_test_cts.cc
@@ -73,14 +73,19 @@
   ASSERT_GT(packets.size(), 0);
 
   size_t objects = 0;
-  for (const auto& packet : packets)
+  size_t roots = 0;
+  for (const auto& packet : packets) {
     objects += packet.heap_graph().objects_size();
+    roots += packet.heap_graph().roots_size();
+  }
   ASSERT_GT(objects, 0);
+  ASSERT_GT(roots, 0);
 }
 
 void AssertNoProfileContents(std::vector<protos::TracePacket> packets) {
   // If profile packets are present, they must be empty.
   for (const auto& packet : packets) {
+    ASSERT_EQ(packet.heap_graph().roots_size(), 0);
     ASSERT_EQ(packet.heap_graph().objects_size(), 0);
     ASSERT_EQ(packet.heap_graph().type_names_size(), 0);
     ASSERT_EQ(packet.heap_graph().field_names_size(), 0);
diff --git a/test/end_to_end_benchmark.cc b/test/end_to_end_benchmark.cc
index 48aaab2..5cdedb3 100644
--- a/test/end_to_end_benchmark.cc
+++ b/test/end_to_end_benchmark.cc
@@ -19,7 +19,6 @@
 #include "perfetto/base/time.h"
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
-#include "perfetto/tracing/core/test_config.h"
 #include "perfetto/tracing/core/trace_config.h"
 #include "src/base/test/test_task_runner.h"
 #include "test/gtest_and_gmock.h"
@@ -27,7 +26,7 @@
 #include "test/task_runner_thread_delegates.h"
 #include "test/test_helper.h"
 
-#include "protos/perfetto/trace/trace_packet.pb.h"
+#include "protos/perfetto/config/test_config.gen.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 
 namespace perfetto {
diff --git a/test/end_to_end_integrationtest.cc b/test/end_to_end_integrationtest.cc
index ea28c95..eab9338 100644
--- a/test/end_to_end_integrationtest.cc
+++ b/test/end_to_end_integrationtest.cc
@@ -31,9 +31,9 @@
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/ext/tracing/ipc/default_socket.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
-#include "perfetto/tracing/core/test_config.h"
-#include "perfetto/tracing/core/trace_config.h"
 #include "protos/perfetto/config/power/android_power_config.pbzero.h"
+#include "protos/perfetto/config/test_config.gen.h"
+#include "protos/perfetto/config/trace_config.gen.h"
 #include "protos/perfetto/trace/trace.pb.h"
 #include "protos/perfetto/trace/trace_packet.pb.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
diff --git a/test/fake_producer.cc b/test/fake_producer.cc
index 175e8e6..17f80f0 100644
--- a/test/fake_producer.cc
+++ b/test/fake_producer.cc
@@ -26,7 +26,8 @@
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/ext/tracing/core/trace_writer.h"
 #include "perfetto/tracing/core/data_source_config.h"
-#include "perfetto/tracing/core/test_config.h"
+
+#include "protos/perfetto/config/test_config.gen.h"
 #include "protos/perfetto/trace/test_event.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 
diff --git a/test/metrics/heap_profile.textproto b/test/metrics/heap_profile.textproto
index e64cb5c..831b002 100644
--- a/test/metrics/heap_profile.textproto
+++ b/test/metrics/heap_profile.textproto
@@ -14,6 +14,8 @@
 }
 packet {
   trusted_packet_sequence_id: 999
+  previous_packet_dropped: true
+  incremental_state_cleared: true
   timestamp: 10
   profile_packet {
     strings {
diff --git a/test/trace_processor/heap_graph.textproto b/test/trace_processor/heap_graph.textproto
index 64cca48..eb32c54 100644
--- a/test/trace_processor/heap_graph.textproto
+++ b/test/trace_processor/heap_graph.textproto
@@ -16,6 +16,10 @@
   trusted_packet_sequence_id: 999
   timestamp: 10
   heap_graph {
+    roots {
+      root_type: ROOT_JAVA_FRAME
+      object_ids: 0x01
+    }
     objects {
       id: 0x01
       type_id: 1
@@ -31,6 +35,8 @@
     continued: true
     index: 1
   }
+}
+packet {
   heap_graph {
     type_names {
       iid: 1
diff --git a/test/trace_processor/heap_graph_object.out b/test/trace_processor/heap_graph_object.out
index fc3b7a4..3f43952 100644
--- a/test/trace_processor/heap_graph_object.out
+++ b/test/trace_processor/heap_graph_object.out
@@ -1,3 +1,3 @@
-"id","type","upid","graph_sample_ts","object_id","self_size","reference_set_id","type_name"
-0,"heap_graph_object",0,10,1,64,0,"FactoryProducerDelegateImplActor"
-1,"heap_graph_object",0,10,2,32,1,"Foo"
+"id","type","upid","graph_sample_ts","object_id","self_size","reference_set_id","type_name","root_type"
+0,"heap_graph_object",0,10,1,64,0,"FactoryProducerDelegateImplActor","ROOT_JAVA_FRAME"
+1,"heap_graph_object",0,10,2,32,1,"Foo","[NULL]"
diff --git a/tools/BUILD.gn b/tools/BUILD.gn
index 19313b5..8ee64e9 100644
--- a/tools/BUILD.gn
+++ b/tools/BUILD.gn
@@ -25,7 +25,6 @@
     ":idle_alloc",
     "compact_reencode",
     "ftrace_proto_gen",
-    "proto_to_cpp",
     "protoprofile",
     "trace_to_text",
     "trace_to_text:trace_to_text_lite",
diff --git a/tools/gen_all b/tools/gen_all
index 094bd88..92d545c 100755
--- a/tools/gen_all
+++ b/tools/gen_all
@@ -56,11 +56,6 @@
     call('ninja', '-C', out, 'protoc')
     call('gen_binary_descriptors', '--protoc', protoc_path(out), *check_only)
 
-    # TODO(primiano): gen_tracing_cpp_headers_from_protos is going away soon
-    # and there is no point adding --check-only support to that.
-    if not check_only:
-      call('gen_tracing_cpp_headers_from_protos', out)
-
   except AssertionError as e:
     if not str(e):
       raise
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 86aa750..5610db4 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -66,6 +66,9 @@
 ipc_plugin = '//src/ipc/protoc_plugin:ipc_plugin(%s)' % gn_utils.HOST_TOOLCHAIN
 protozero_plugin = '//src/protozero/protoc_plugin:protozero_plugin(%s)' % (
     gn_utils.HOST_TOOLCHAIN)
+cppgen_plugin = '//src/protozero/protoc_plugin:cppgen_plugin(%s)' % (
+    gn_utils.HOST_TOOLCHAIN)
+
 default_targets += [
     '//src/trace_processor:trace_processor_shell(%s)' % gn_utils.HOST_TOOLCHAIN,
     '//tools/trace_to_text:trace_to_text(%s)' % gn_utils.HOST_TOOLCHAIN,
@@ -481,6 +484,12 @@
     tools.add(plugin.name)
     cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
     cmd += ['--plugin_out=wrapper_namespace=pbzero:' + cpp_out_dir]
+  elif target.proto_plugin == 'cppgen':
+    suffixes = ['gen']
+    plugin = create_modules_from_target(blueprint, gn, cppgen_plugin)
+    tools.add(plugin.name)
+    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
+    cmd += ['--plugin_out=:' + cpp_out_dir]
   elif target.proto_plugin == 'ipc':
     suffixes.append('ipc')
     plugin = create_modules_from_target(blueprint, gn, ipc_plugin)
diff --git a/tools/gen_bazel b/tools/gen_bazel
index dba8d8d..af4584b 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -66,6 +66,7 @@
     '//src/ipc/protoc_plugin:ipc_plugin',
     '//src/protozero:libprotozero',
     '//src/protozero/protoc_plugin:protozero_plugin',
+    '//src/protozero/protoc_plugin:cppgen_plugin',
 ] + public_targets
 
 # Root proto targets (to force discovery of intermediate proto targets).
@@ -142,9 +143,8 @@
   def __lt__(self, other):
     if isinstance(other, self.__class__):
       return self.name < other.name
-    raise TypeError(
-        '\'<\' not supported between instances of \'%s\' and \'%s\'' %
-        (type(self).__name__, type(other).__name__))
+    raise TypeError('\'<\' not supported between instances of \'%s\' and \'%s\''
+                    % (type(self).__name__, type(other).__name__))
 
   def __str__(self):
     """Converts the object into a Bazel Starlark label."""
@@ -225,6 +225,8 @@
     plugin_label_type = 'perfetto_cc_proto_library'
   elif target.proto_plugin == 'protozero':
     plugin_label_type = 'perfetto_cc_protozero_library'
+  elif target.proto_plugin == 'cppgen':
+    plugin_label_type = 'perfetto_cc_protocpp_library'
   elif target.proto_plugin == 'ipc':
     plugin_label_type = 'perfetto_cc_ipc_library'
   else:
@@ -234,6 +236,17 @@
   plugin_label.comment = target.name
   plugin_label.deps += [':' + sources_label_name]
 
+  # When using the cppgen plugin we need to pass down also the transitive deps.
+  # For instance consider foo.proto including common.proto. The generated
+  # foo.cc will #include "common.gen.h". Hence the generated cc_protocpp_library
+  # rule need to pass down the dependency on the target that generates
+  # common.gen.{cc,h}. This is not needed for protozero because protozero
+  # headers are fully hermetic deps-wise and use only on forward declarations.
+  if target.proto_deps and target.proto_plugin == 'cppgen':
+    plugin_label.deps += [
+        ':' + get_bazel_label_name(x) for x in target.proto_deps
+    ]
+
   # Generates 2.
   sources_label = BazelLabel(sources_label_name, 'perfetto_proto_library')
   sources_label.comment = target.name
@@ -338,6 +351,7 @@
     "perfetto_cc_ipc_library",
     "perfetto_cc_library",
     "perfetto_cc_proto_library",
+    "perfetto_cc_protocpp_library",
     "perfetto_cc_protozero_library",
     "perfetto_java_proto_library",
     "perfetto_proto_library",
diff --git a/tools/gen_tracing_cpp_headers_from_protos b/tools/gen_tracing_cpp_headers_from_protos
deleted file mode 100755
index c214698..0000000
--- a/tools/gen_tracing_cpp_headers_from_protos
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import subprocess
-import sys
-
-ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-PUB_CORE_H = 'include/perfetto/tracing/core'
-CORE_H = 'include/perfetto/ext/tracing/core'
-CORE_CPP = 'src/tracing/core'
-
-PROTOS = (
-    # Classes that are exposed as part of the public API surface.
-    ('protos/perfetto/common/data_source_descriptor.proto', PUB_CORE_H, CORE_CPP
-    ),
-    ('protos/perfetto/common/tracing_service_state.proto', PUB_CORE_H,
-     CORE_CPP),
-    ('protos/perfetto/config/chrome/chrome_config.proto', PUB_CORE_H, CORE_CPP),
-    ('protos/perfetto/config/data_source_config.proto', PUB_CORE_H, CORE_CPP),
-    ('protos/perfetto/config/test_config.proto', PUB_CORE_H, CORE_CPP),
-    ('protos/perfetto/config/trace_config.proto', PUB_CORE_H, CORE_CPP),
-
-    # Classes that are exposes only in the /ext/ (unstable) API surface.
-    ('protos/perfetto/common/commit_data_request.proto', CORE_H, CORE_CPP),
-    ('protos/perfetto/common/observable_events.proto', CORE_H, CORE_CPP),
-    ('protos/perfetto/common/trace_stats.proto', CORE_H, CORE_CPP),
-
-    # Generate ftrace cpp/h files into the src/traced/probes/ directory.
-    ('protos/perfetto/config/ftrace/ftrace_config.proto',
-     'src/traced/probes/ftrace', 'src/traced/probes/ftrace'),
-
-    # Generate profiling cpp/h files into the src/profiling/memory/ directory.
-    ('protos/perfetto/config/profiling/heapprofd_config.proto',
-     'src/profiling/memory', 'src/profiling/memory'),
-    ('protos/perfetto/config/profiling/java_hprof_config.proto',
-     'src/profiling/memory', 'src/profiling/memory'),
-)
-
-
-def run(cmd):
-  print('\nRunning ' + ' '.join(cmd))
-  subprocess.check_call(cmd)
-
-
-def main():
-  if not os.path.exists('.gn'):
-    print('This script must be executed from the perfetto root directory')
-    return 1
-  if len(sys.argv) < 2:
-    print('Usage: %s out/xxx' % sys.argv[0])
-    return 1
-  out_dir = sys.argv[1]
-  arch = 'mac' if sys.platform == 'darwin' else 'linux64'
-  clang_format_path = os.path.join(ROOT_DIR, 'buildtools', arch, 'clang-format')
-  clang_format = [clang_format_path, '-i', '--sort-includes']
-  ninja = os.path.join(ROOT_DIR, 'tools', 'ninja')
-  run([ninja, '-C', out_dir, 'proto_to_cpp'])
-  tool = os.path.join(out_dir, 'proto_to_cpp')
-  assert (os.path.exists(tool))
-  for args in PROTOS:
-    proto, header_dir, cpp_dir = args
-    include_dir = header_dir.replace('include/', '')
-    run([tool, proto] + [header_dir, cpp_dir, include_dir])
-    fname = os.path.basename(proto).replace('.proto', '')
-    run(clang_format + [os.path.join(header_dir, fname + '.h')])
-    run(clang_format + [os.path.join(cpp_dir, fname + '.cc')])
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/tools/proto_to_cpp/BUILD.gn b/tools/proto_to_cpp/BUILD.gn
deleted file mode 100644
index aaa7c7e..0000000
--- a/tools/proto_to_cpp/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import("../../gn/perfetto_host_executable.gni")
-
-perfetto_host_executable("proto_to_cpp") {
-  testonly = true
-  deps = [
-    "../../gn:default_deps",
-    "../../gn:protobuf_full",
-    "../../src/base",
-  ]
-  sources = [
-    "proto_to_cpp.cc",
-  ]
-}
diff --git a/tools/proto_to_cpp/proto_to_cpp.cc b/tools/proto_to_cpp/proto_to_cpp.cc
deleted file mode 100644
index 5e995f2..0000000
--- a/tools/proto_to_cpp/proto_to_cpp.cc
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/util/field_comparator.h>
-#include <google/protobuf/util/message_differencer.h>
-
-#include <stdio.h>
-
-#include <fstream>
-#include <iostream>
-
-#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/string_utils.h"
-
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
-using namespace google::protobuf::io;
-using perfetto::base::SplitString;
-using perfetto::base::StripChars;
-using perfetto::base::StripSuffix;
-using perfetto::base::ToUpper;
-
-static constexpr auto TYPE_MESSAGE = FieldDescriptor::TYPE_MESSAGE;
-
-namespace {
-
-static const char kHeader[] = R"(/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*******************************************************************************
- * AUTOGENERATED - DO NOT EDIT
- *******************************************************************************
- * This file has been generated from the protobuf message
- * $p$
- * by
- * $f$.
- * If you need to make changes here, change the .proto file and then run
- * ./tools/gen_tracing_cpp_headers_from_protos
- */
-
-)";
-
-class ErrorPrinter : public MultiFileErrorCollector {
-  virtual void AddError(const string& filename,
-                        int line,
-                        int col,
-                        const string& msg) {
-    PERFETTO_ELOG("%s %d:%d: %s", filename.c_str(), line, col, msg.c_str());
-  }
-  virtual void AddWarning(const string& filename,
-                          int line,
-                          int col,
-                          const string& msg) {
-    PERFETTO_ILOG("%s %d:%d: %s", filename.c_str(), line, col, msg.c_str());
-  }
-};
-
-std::string GetProtoHeader(const FileDescriptor* proto_file) {
-  return StripSuffix(proto_file->name(), ".proto") + ".pb.h";
-}
-
-std::string GetFwdDeclType(const Descriptor* msg, bool with_namespace = false) {
-  std::string full_type;
-  full_type.append(msg->name());
-  for (const Descriptor* par = msg->containing_type(); par;
-       par = par->containing_type()) {
-    full_type.insert(0, par->name() + "_");
-  }
-  if (with_namespace) {
-    std::vector<std::string> namespaces =
-        SplitString(msg->file()->package(), ".");
-    for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) {
-      full_type.insert(0, *it + "::");
-    }
-  }
-  return full_type;
-}
-
-void GenFwdDecl(const Descriptor* msg, Printer* p, bool root_cpp_only = false) {
-  if (!root_cpp_only) {
-    p->Print("class $n$;", "n", GetFwdDeclType(msg));
-  } else if (msg->full_name() == msg->file()->package() + "." + msg->name()) {
-    p->Print("class $n$;", "n", msg->name());
-  }
-
-  // Recurse into subtypes
-  for (int i = 0; i < msg->field_count(); i++) {
-    const FieldDescriptor* field = msg->field(i);
-    if (field->type() == TYPE_MESSAGE && !field->options().lazy()) {
-      GenFwdDecl(field->message_type(), p, root_cpp_only);
-    }
-  }
-}
-
-}  // namespace
-
-class ProtoToCpp {
- public:
-  ProtoToCpp(const std::string& header_dir,
-             const std::string& cpp_dir,
-             const std::string& include_path);
-
-  static std::string GetCppType(const FieldDescriptor* field, bool constref);
-
-  void Convert(const std::string& src_proto);
-  std::string GetHeaderPath(const FileDescriptor*);
-  std::string GetCppPath(const FileDescriptor*);
-  std::string GetIncludePath(const FileDescriptor*);
-  void GenHeader(const Descriptor*, Printer*);
-  void GenCpp(const Descriptor*, Printer*, std::string prefix);
-
- private:
-  std::string header_dir_;
-  std::string cpp_dir_;
-  std::string include_path_;
-  DiskSourceTree dst_;
-  ErrorPrinter error_printer_;
-  Importer importer_;
-};
-
-ProtoToCpp::ProtoToCpp(const std::string& header_dir,
-                       const std::string& cpp_dir,
-                       const std::string& include_path)
-    : header_dir_(header_dir),
-      cpp_dir_(cpp_dir),
-      include_path_(include_path),
-      importer_(&dst_, &error_printer_) {
-  dst_.MapPath("", "");  // Yes, this tautology is needed :/.
-}
-
-std::string ProtoToCpp::GetHeaderPath(const FileDescriptor* proto_file) {
-  std::string basename = SplitString(proto_file->name(), "/").back();
-  return header_dir_ + "/" + StripSuffix(basename, ".proto") + ".h";
-}
-
-std::string ProtoToCpp::GetCppPath(const FileDescriptor* proto_file) {
-  std::string basename = SplitString(proto_file->name(), "/").back();
-  return cpp_dir_ + "/" + StripSuffix(basename, ".proto") + ".cc";
-}
-
-std::string ProtoToCpp::GetIncludePath(const FileDescriptor* proto_file) {
-  std::string basename = SplitString(proto_file->name(), "/").back();
-  return include_path_ + "/" + StripSuffix(basename, ".proto") + ".h";
-}
-
-std::string ProtoToCpp::GetCppType(const FieldDescriptor* field,
-                                   bool constref) {
-  switch (field->type()) {
-    case FieldDescriptor::TYPE_DOUBLE:
-      return "double";
-    case FieldDescriptor::TYPE_FLOAT:
-      return "float";
-    case FieldDescriptor::TYPE_FIXED32:
-    case FieldDescriptor::TYPE_UINT32:
-      return "uint32_t";
-    case FieldDescriptor::TYPE_SFIXED32:
-    case FieldDescriptor::TYPE_INT32:
-    case FieldDescriptor::TYPE_SINT32:
-      return "int32_t";
-    case FieldDescriptor::TYPE_FIXED64:
-    case FieldDescriptor::TYPE_UINT64:
-      return "uint64_t";
-    case FieldDescriptor::TYPE_SFIXED64:
-    case FieldDescriptor::TYPE_SINT64:
-    case FieldDescriptor::TYPE_INT64:
-      return "int64_t";
-    case FieldDescriptor::TYPE_BOOL:
-      return "bool";
-    case FieldDescriptor::TYPE_STRING:
-    case FieldDescriptor::TYPE_BYTES:
-      return constref ? "const std::string&" : "std::string";
-    case FieldDescriptor::TYPE_MESSAGE:
-      PERFETTO_CHECK(!field->options().lazy());
-      return constref ? "const " + field->message_type()->name() + "&"
-                      : field->message_type()->name();
-    case FieldDescriptor::TYPE_ENUM:
-      return field->enum_type()->name();
-    case FieldDescriptor::TYPE_GROUP:
-      PERFETTO_FATAL("No cpp type for a group field.");
-  }
-  PERFETTO_FATAL("Not reached");  // for gcc
-}
-
-void ProtoToCpp::Convert(const std::string& src_proto) {
-  const FileDescriptor* proto_file = importer_.Import(src_proto);
-  if (!proto_file) {
-    PERFETTO_ELOG("Failed to load %s", src_proto.c_str());
-    exit(1);
-  }
-
-  std::string dst_header = GetHeaderPath(proto_file);
-  std::string dst_cpp = GetCppPath(proto_file);
-
-  std::ofstream header_ostr;
-  header_ostr.open(dst_header);
-  PERFETTO_CHECK(header_ostr.is_open());
-  OstreamOutputStream header_proto_ostr(&header_ostr);
-  Printer header_printer(&header_proto_ostr, '$');
-
-  std::ofstream cpp_ostr;
-  cpp_ostr.open(dst_cpp);
-  PERFETTO_CHECK(cpp_ostr.is_open());
-  OstreamOutputStream cpp_proto_ostr(&cpp_ostr);
-  Printer cpp_printer(&cpp_proto_ostr, '$');
-
-  std::string include_guard = dst_header + "_";
-  include_guard = ToUpper(include_guard);
-  include_guard = StripChars(include_guard, ".-/\\", '_');
-  header_printer.Print(kHeader, "f", __FILE__, "p", src_proto);
-  header_printer.Print("#ifndef $g$\n#define $g$\n\n", "g", include_guard);
-  header_printer.Print("#include <stdint.h>\n");
-  header_printer.Print("#include <vector>\n");
-  header_printer.Print("#include <string>\n");
-  header_printer.Print("#include <type_traits>\n\n");
-  header_printer.Print("#include \"perfetto/base/copyable_ptr.h\"\n");
-  header_printer.Print("#include \"perfetto/base/export.h\"\n\n");
-
-  cpp_printer.Print(kHeader, "f", __FILE__, "p", src_proto);
-  if (dst_header.find("include/") == 0) {
-    cpp_printer.Print("#include \"$f$\"\n", "f",
-                      dst_header.substr(strlen("include/")));
-  } else {
-    cpp_printer.Print("#include \"$f$\"\n", "f", dst_header);
-  }
-
-  // Generate includes for translated types of dependencies.
-
-  // Figure out the subset of imports that are used only for lazy fields. We
-  // won't emit a C++ #include for them. This code is overly aggressive at
-  // removing imports: it rules them out as soon as it sees one lazy field
-  // whose type is defined in that import. A 100% correct solution would require
-  // to check that *all* dependent types for a given import are lazy before
-  // excluding that. In practice we don't need that because we don't use imports
-  // for both lazy and non-lazy fields.
-  std::set<std::string> lazy_imports;
-  for (int m = 0; m < proto_file->message_type_count(); m++) {
-    const Descriptor* msg = proto_file->message_type(m);
-    for (int i = 0; i < msg->field_count(); i++) {
-      const FieldDescriptor* field = msg->field(i);
-      if (field->options().lazy()) {
-        lazy_imports.insert(field->message_type()->file()->name());
-      }
-    }
-  }
-
-  cpp_printer.Print("\n#include \"$f$\"\n", "f", GetProtoHeader(proto_file));
-  for (int i = 0; i < proto_file->dependency_count(); i++) {
-    const FileDescriptor* dep = proto_file->dependency(i);
-    if (lazy_imports.count(dep->name()))
-      continue;
-    cpp_printer.Print("\n#include \"$f$\"\n", "f", GetIncludePath(dep));
-    cpp_printer.Print("#include \"$f$\"\n", "f", GetProtoHeader(dep));
-  }
-
-  // Generate forward declarations in the header for proto types.
-  header_printer.Print("// Forward declarations for protobuf types.\n");
-  std::vector<std::string> namespaces = SplitString(proto_file->package(), ".");
-  for (size_t i = 0; i < namespaces.size(); i++)
-    header_printer.Print("namespace $n$ {\n", "n", namespaces[i]);
-  for (int i = 0; i < proto_file->message_type_count(); i++)
-    GenFwdDecl(proto_file->message_type(i), &header_printer);
-  for (size_t i = 0; i < namespaces.size(); i++)
-    header_printer.Print("}\n");
-
-  header_printer.Print("\nnamespace perfetto {\n");
-  cpp_printer.Print("\nnamespace perfetto {\n");
-
-  // Generate fwd declarations for top-level classes.
-  for (int i = 0; i < proto_file->message_type_count(); i++)
-    GenFwdDecl(proto_file->message_type(i), &header_printer, true);
-  header_printer.Print("\n");
-
-  for (int i = 0; i < proto_file->message_type_count(); i++) {
-    const Descriptor* msg = proto_file->message_type(i);
-    GenHeader(msg, &header_printer);
-    GenCpp(msg, &cpp_printer, "");
-  }
-
-  cpp_printer.Print("}  // namespace perfetto\n");
-  header_printer.Print("}  // namespace perfetto\n");
-  header_printer.Print("\n#endif  // $g$\n", "g", include_guard);
-}
-
-void ProtoToCpp::GenHeader(const Descriptor* msg, Printer* p) {
-  PERFETTO_ILOG("GEN %s %s", msg->name().c_str(), msg->file()->name().c_str());
-  p->Print("\nclass PERFETTO_EXPORT $n$ {\n", "n", msg->name());
-  p->Print(" public:\n");
-  p->Indent();
-  // Do a first pass to generate nested types.
-  for (int i = 0; i < msg->field_count(); i++) {
-    const FieldDescriptor* field = msg->field(i);
-    if (field->has_default_value()) {
-      PERFETTO_FATAL(
-          "Error on field %s: Explicitly declared default values are not "
-          "supported",
-          field->name().c_str());
-    }
-
-    if (field->type() == FieldDescriptor::TYPE_ENUM) {
-      const EnumDescriptor* enum_desc = field->enum_type();
-      p->Print("enum $n$ {\n", "n", enum_desc->name());
-      for (int e = 0; e < enum_desc->value_count(); e++) {
-        const EnumValueDescriptor* value = enum_desc->value(e);
-        p->Print("  $n$ = $v$,\n", "n", value->name(), "v",
-                 std::to_string(value->number()));
-      }
-      p->Print("};\n");
-    } else if (field->type() == TYPE_MESSAGE &&
-               field->message_type()->file() == msg->file()) {
-      GenHeader(field->message_type(), p);
-    }
-  }
-
-  p->Print("$n$();\n", "n", msg->name());
-  p->Print("~$n$();\n", "n", msg->name());
-  p->Print("$n$($n$&&) noexcept;\n", "n", msg->name());
-  p->Print("$n$& operator=($n$&&);\n", "n", msg->name());
-  p->Print("$n$(const $n$&);\n", "n", msg->name());
-  p->Print("$n$& operator=(const $n$&);\n", "n", msg->name());
-  p->Print("bool operator==(const $n$&) const;\n", "n", msg->name());
-  p->Print(
-      "bool operator!=(const $n$& other) const { return !(*this == other); }\n",
-      "n", msg->name());
-  p->Print("\n");
-
-  std::string proto_type = GetFwdDeclType(msg, true);
-  p->Print("// Raw proto decoding.\n");
-  p->Print("void ParseRawProto(const std::string&);\n");
-  p->Print("// Conversion methods from/to the corresponding protobuf types.\n");
-  p->Print("void FromProto(const $p$&);\n", "p", proto_type);
-  p->Print("void ToProto($p$*) const;\n", "p", proto_type);
-
-  // Generate accessors.
-  for (int i = 0; i < msg->field_count(); i++) {
-    const FieldDescriptor* field = msg->field(i);
-    p->Print("\n");
-    if (field->options().lazy()) {
-      if (field->is_repeated() || field->type() != TYPE_MESSAGE) {
-        PERFETTO_FATAL(
-            "[lazy=true] is supported only on non-repeated submessage fields");
-      }
-      p->Print("const std::string& $n$_raw() const { return $n$_; }\n", "n",
-               field->lowercase_name());
-      p->Print("void set_$n$_raw(const std::string& raw) { $n$_ = raw; }\n",
-               "n", field->lowercase_name());
-    } else if (!field->is_repeated()) {
-      if (field->type() == TYPE_MESSAGE) {
-        p->Print("$t$ $n$() const { return *$n$_; }\n", "t",
-                 GetCppType(field, true), "n", field->lowercase_name());
-        p->Print("$t$* mutable_$n$() { return $n$_.get(); }\n", "t",
-                 GetCppType(field, false), "n", field->lowercase_name());
-      } else {
-        p->Print("$t$ $n$() const { return $n$_; }\n", "t",
-                 GetCppType(field, true), "n", field->lowercase_name());
-        p->Print("void set_$n$($t$ value) { $n$_ = value; }\n", "t",
-                 GetCppType(field, true), "n", field->lowercase_name());
-        if (field->type() == FieldDescriptor::TYPE_BYTES) {
-          p->Print(
-              "void set_$n$(const void* p, size_t s) { "
-              "$n$_.assign(reinterpret_cast<const char*>(p), s); }\n",
-              "n", field->lowercase_name());
-        }
-      }
-    } else {  // is_repeated()
-      p->Print(
-          "int $n$_size() const { return static_cast<int>($n$_.size()); }\n",
-          "t", GetCppType(field, false), "n", field->lowercase_name());
-      p->Print("const std::vector<$t$>& $n$() const { return $n$_; }\n", "t",
-               GetCppType(field, false), "n", field->lowercase_name());
-      p->Print("std::vector<$t$>* mutable_$n$() { return &$n$_; }\n", "t",
-               GetCppType(field, false), "n", field->lowercase_name());
-      p->Print("void clear_$n$() { $n$_.clear(); }\n", "n",
-               field->lowercase_name());
-
-      if (field->type() == TYPE_MESSAGE && !field->options().lazy()) {
-        p->Print(
-            "$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); "
-            "}\n",
-            "t", GetCppType(field, false), "n", field->lowercase_name());
-      } else {
-        p->Print(
-            "$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); }\n",
-            "t", GetCppType(field, false), "n", field->lowercase_name());
-      }
-    }
-  }
-  p->Outdent();
-  p->Print("\n private:\n");
-  p->Indent();
-
-  // Generate fields.
-  for (int i = 0; i < msg->field_count(); i++) {
-    const FieldDescriptor* field = msg->field(i);
-    if (field->options().lazy()) {
-      p->Print("std::string $n$_;  // [lazy=true]\n", "n",
-               field->lowercase_name());
-    } else if (!field->is_repeated()) {
-      std::string type = GetCppType(field, false);
-      if (field->type() == TYPE_MESSAGE) {
-        type = "::perfetto::base::CopyablePtr<" + type + ">";
-        p->Print("$t$ $n$_;\n", "t", type, "n", field->lowercase_name());
-      } else {
-        p->Print("$t$ $n$_{};\n", "t", type, "n", field->lowercase_name());
-      }
-    } else {  // is_repeated()
-      p->Print("std::vector<$t$> $n$_;\n", "t", GetCppType(field, false), "n",
-               field->lowercase_name());
-    }
-  }
-  p->Print("\n");
-  p->Print("// Allows to preserve unknown protobuf fields for compatibility\n");
-  p->Print("// with future versions of .proto files.\n");
-  p->Print("std::string unknown_fields_;\n");
-  p->Outdent();
-  p->Print("};\n\n");
-}
-
-void ProtoToCpp::GenCpp(const Descriptor* msg, Printer* p, std::string prefix) {
-  p->Print("\n");
-  std::string full_name = prefix + msg->name();
-
-  p->Print("$f$::$n$() = default;\n", "f", full_name, "n", msg->name());
-  p->Print("$f$::~$n$() = default;\n", "f", full_name, "n", msg->name());
-  p->Print("$f$::$n$(const $f$&) = default;\n", "f", full_name, "n",
-           msg->name());
-  p->Print("$f$& $f$::operator=(const $f$&) = default;\n", "f", full_name, "n",
-           msg->name());
-  p->Print("$f$::$n$($f$&&) noexcept = default;\n", "f", full_name, "n",
-           msg->name());
-  p->Print("$f$& $f$::operator=($f$&&) = default;\n", "f", full_name, "n",
-           msg->name());
-
-  p->Print("\n");
-
-  // Comparison operator
-  p->Print("#pragma GCC diagnostic push\n");
-  p->Print("#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n");
-  p->Print("bool $f$::operator==(const $f$& other) const {\n", "f", full_name,
-           "n", msg->name());
-  p->Indent();
-
-  p->Print("return ");
-  for (int i = 0; i < msg->field_count(); i++) {
-    if (i > 0)
-      p->Print("\n && ");
-    const FieldDescriptor* field = msg->field(i);
-    p->Print("($n$_ == other.$n$_)", "n", field->name());
-  }
-  p->Print(";");
-  p->Outdent();
-  p->Print("}\n");
-  p->Print("#pragma GCC diagnostic pop\n\n");
-
-  std::string proto_type = GetFwdDeclType(msg, true);
-
-  // Genrate the ParseRawProto() method definition.
-  p->Print("void $f$::ParseRawProto(const std::string& raw) {\n", "f",
-           full_name);
-  p->Indent();
-  p->Print("$p$ proto;\n", "p", proto_type);
-  p->Print("proto.ParseFromString(raw);\n");
-  p->Print("FromProto(proto);\n");
-  p->Outdent();
-  p->Print("}\n\n");
-
-  // Genrate the FromProto() method definition.
-  p->Print("void $f$::FromProto(const $p$& proto) {\n", "f", full_name, "p",
-           proto_type);
-  p->Indent();
-  for (int i = 0; i < msg->field_count(); i++) {
-    p->Print("\n");
-    const FieldDescriptor* field = msg->field(i);
-    if (field->options().lazy()) {
-      p->Print("$n$_ = proto.$n$().SerializeAsString();\n", "n", field->name());
-    } else if (!field->is_repeated()) {
-      if (field->type() == TYPE_MESSAGE) {
-        p->Print("$n$_->FromProto(proto.$n$());\n", "n", field->name());
-      } else {
-        p->Print(
-            "static_assert(sizeof($n$_) == sizeof(proto.$n$()), \"size "
-            "mismatch\");\n",
-            "n", field->name());
-        p->Print("$n$_ = static_cast<decltype($n$_)>(proto.$n$());\n", "n",
-                 field->name());
-      }
-    } else {  // is_repeated()
-      p->Print("$n$_.clear();\n", "n", field->name());
-      p->Print("for (const auto& field : proto.$n$()) {\n", "n", field->name());
-      p->Print("  $n$_.emplace_back();\n", "n", field->name());
-      if (field->type() == TYPE_MESSAGE) {
-        p->Print("  $n$_.back().FromProto(field);\n", "n", field->name());
-      } else {
-        p->Print(
-            "static_assert(sizeof($n$_.back()) == sizeof(proto.$n$(0)), \"size "
-            "mismatch\");\n",
-            "n", field->name());
-        p->Print(
-            "  $n$_.back() = static_cast<decltype($n$_)::value_type>(field);\n",
-            "n", field->name());
-      }
-      p->Print("}\n");
-    }
-  }
-  p->Print("unknown_fields_ = proto.unknown_fields();\n");
-  p->Outdent();
-  p->Print("}\n\n");
-
-  // Genrate the ToProto() method definition.
-  p->Print("void $f$::ToProto($p$* proto) const {\n", "f", full_name, "p",
-           proto_type);
-  p->Indent();
-  p->Print("proto->Clear();\n");
-  for (int i = 0; i < msg->field_count(); i++) {
-    p->Print("\n");
-    const FieldDescriptor* field = msg->field(i);
-    if (field->options().lazy()) {
-      p->Print("proto->mutable_$n$()->ParseFromString($n$_);\n", "n",
-               field->name());
-    } else if (!field->is_repeated()) {
-      if (field->type() == TYPE_MESSAGE) {
-        p->Print("$n$_->ToProto(proto->mutable_$n$());\n", "n", field->name());
-      } else {
-        p->Print(
-            "static_assert(sizeof($n$_) == sizeof(proto->$n$()), \"size "
-            "mismatch\");\n",
-            "n", field->name());
-        p->Print("proto->set_$n$(static_cast<decltype(proto->$n$())>($n$_));\n",
-                 "n", field->name());
-      }
-    } else {  // is_repeated()
-      p->Print("for (const auto& it : $n$_) {\n", "n", field->name());
-      if (field->type() == TYPE_MESSAGE) {
-        p->Print("  auto* entry = proto->add_$n$();\n", "n", field->name());
-        p->Print("  it.ToProto(entry);\n");
-      } else {
-        p->Print(
-            "  proto->add_$n$(static_cast<decltype(proto->$n$(0))>(it));\n",
-            "n", field->name());
-        p->Print(
-            "static_assert(sizeof(it) == sizeof(proto->$n$(0)), \"size "
-            "mismatch\");\n",
-            "n", field->name());
-      }
-      p->Print("}\n");
-    }
-  }
-  p->Print("*(proto->mutable_unknown_fields()) = unknown_fields_;\n");
-  p->Outdent();
-  p->Print("}\n\n");
-
-  // Recurse into nested types.
-  for (int i = 0; i < msg->field_count(); i++) {
-    const FieldDescriptor* field = msg->field(i);
-    // [lazy=true] field are not recursesd and exposed as raw-strings
-    // containing proto-encoded bytes.
-    if (field->options().lazy())
-      continue;
-
-    if (field->type() == TYPE_MESSAGE &&
-        field->message_type()->file() == msg->file()) {
-      std::string child_prefix = prefix + msg->name() + "::";
-      GenCpp(field->message_type(), p, child_prefix);
-    }
-  }
-}
-
-int main(int argc, char** argv) {
-  if (argc <= 4) {
-    PERFETTO_ELOG(
-        "Usage: %s source.proto dir/for/header dir/for/cc include/path",
-        argv[0]);
-    return 1;
-  }
-  ProtoToCpp proto_to_cpp(argv[2], argv[3], argv[4]);
-  proto_to_cpp.Convert(argv[1]);
-  return 0;
-}
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index eae9fce..c42fcf0 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -394,10 +394,20 @@
         };
       },
 
-  selectHeapDump(
+  selectHeapProfile(
       state: StateDraft, args: {id: number, upid: number, ts: number}): void {
     state.currentSelection =
-        {kind: 'HEAP_DUMP', id: args.id, upid: args.upid, ts: args.ts};
+        {kind: 'HEAP_PROFILE', id: args.id, upid: args.upid, ts: args.ts};
+  },
+
+  showHeapProfileFlamegraph(
+      state: StateDraft, args: {id: number, upid: number, ts: number}): void {
+    state.currentHeapProfileFlamegraph = {
+      kind: 'HEAP_PROFILE_FLAMEGRAPH',
+      id: args.id,
+      upid: args.upid,
+      ts: args.ts
+    };
   },
 
   selectChromeSlice(state: StateDraft, args: {id: number}): void {
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 3d8f50b..5f31d28 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -112,8 +112,15 @@
   id: number;
 }
 
-export interface HeapDumpSelection {
-  kind: 'HEAP_DUMP';
+export interface HeapProfileSelection {
+  kind: 'HEAP_PROFILE';
+  id: number;
+  upid: number;
+  ts: number;
+}
+
+export interface HeapProfileFlamegraph {
+  kind: 'HEAP_PROFILE_FLAMEGRAPH';
   id: number;
   upid: number;
   ts: number;
@@ -134,7 +141,7 @@
 }
 
 type Selection = NoteSelection|SliceSelection|CounterSelection|
-    HeapDumpSelection|ChromeSliceSelection|ThreadStateSelection;
+    HeapProfileSelection|ChromeSliceSelection|ThreadStateSelection;
 
 export interface LogsPagination {
   offset: number;
@@ -174,6 +181,7 @@
   notes: ObjectById<Note>;
   status: Status;
   currentSelection: Selection|null;
+  currentHeapProfileFlamegraph: HeapProfileFlamegraph|null;
 
   logsPagination: LogsPagination;
 
@@ -378,6 +386,7 @@
 
     status: {msg: '', timestamp: 0},
     currentSelection: null,
+    currentHeapProfileFlamegraph: null,
 
     video: null,
     videoEnabled: false,
diff --git a/ui/src/controller/selection_controller.ts b/ui/src/controller/selection_controller.ts
index 96376c9..2257307 100644
--- a/ui/src/controller/selection_controller.ts
+++ b/ui/src/controller/selection_controller.ts
@@ -15,9 +15,8 @@
 import {Engine} from '../common/engine';
 import {fromNs, toNs} from '../common/time';
 import {
-  CallsiteInfo,
   CounterDetails,
-  HeapDumpDetails,
+  HeapProfileDetails,
   SliceDetails
 } from '../frontend/globals';
 
@@ -52,7 +51,7 @@
       return;
     }
 
-    const selectWithId = ['SLICE', 'COUNTER', 'CHROME_SLICE', 'HEAP_DUMP'];
+    const selectWithId = ['SLICE', 'COUNTER', 'CHROME_SLICE', 'HEAP_PROFILE'];
     if (!selectWithId.includes(selection.kind) ||
         (selectWithId.includes(selection.kind) &&
          selection.id === this.lastSelectedId &&
@@ -66,8 +65,8 @@
 
     if (selectedId === undefined) return;
 
-    if (selection.kind === 'HEAP_DUMP') {
-      const selected: HeapDumpDetails = {};
+    if (selection.kind === 'HEAP_PROFILE') {
+      const selected: HeapProfileDetails = {};
       const ts = selection.ts;
       const upid = selection.upid;
       this.heapDumpDetails(ts, upid).then(results => {
@@ -117,7 +116,7 @@
   }
 
   async sliceDetails(id: number) {
-    const sqlQuery = `SELECT ts, dur, priority, end_state, utid FROM sched
+    const sqlQuery = `SELECT ts, dur, priority, end_state, utid, cpu FROM sched
     WHERE row_id = ${id}`;
     this.args.engine.query(sqlQuery).then(result => {
       // Check selection is still the same on completion of query.
@@ -129,8 +128,9 @@
         const priority = result.columns[2].longValues![0] as number;
         const endState = result.columns[3].stringValues![0];
         const utid = result.columns[4].longValues![0] as number;
+        const cpu = result.columns[5].longValues![0] as number;
         const selected: SliceDetails =
-            {ts: timeFromStart, dur, priority, endState, id, utid};
+            {ts: timeFromStart, dur, priority, endState, cpu, id, utid};
         this.schedulingDetails(ts, utid).then(wakeResult => {
           Object.assign(selected, wakeResult);
           globals.publish('SliceDetails', selected);
@@ -154,94 +154,12 @@
             ts} and upid = ${upid}`);
     const allocatedNotFreed = allocatedNotFreedMemory.columns[0].longValues![0];
     const startTime = fromNs(ts) - globals.state.traceTime.startSec;
-
-    // Collecting data for drawing flagraph for selected heap profile.
-    // Data needs to be in following format:
-    // id, name, parent_id, depth, total_size
-
-    // Joining the callsite table with frame table then with alloc table to get
-    // the size and name for each callsite.
-    await this.args.engine.query(
-        // TODO(tneda|lalitm): get names from symbols to exactly replicate
-        // pprof.
-        `create view callsite_with_name_and_size as
-      select cs.id, parent_id, depth, name, SUM(IFNULL(size, 0)) as size
-      from stack_profile_callsite cs
-      join stack_profile_frame on cs.frame_id = stack_profile_frame.id
-      left join heap_profile_allocation alloc on alloc.callsite_id = cs.id and
-      alloc.ts <= ${ts} and alloc.upid = ${upid} group by cs.id
-    `);
-
-    // Recursive query to compute the hash for each callsite based on names
-    // rather than ids.
-    // We get all the children of the row in question and emit a row with hash
-    // equal hash(name, parent.hash). Roots without the parent will have -1 as
-    // hash.  Slices will be merged into a big slice.
-    await this.args.engine.query(`create view callsite_hash_name_size as
-      with recursive callsite_table_names(
-        id, hash, name, size, parent_hash, depth) AS (
-      select id, hash(name) as hash, name, size, -1, depth
-      from callsite_with_name_and_size
-      where depth = 0
-      UNION ALL
-      SELECT cs.id, hash(cs.name, ctn.hash) as hash, cs.name, cs.size, ctn.hash,
-       cs.depth
-      FROM callsite_table_names ctn
-      INNER JOIN callsite_with_name_and_size cs ON ctn.id = cs.parent_id
-      )
-      SELECT hash, name, parent_hash, depth, SUM(size) as size
-      FROM callsite_table_names
-      group by hash`);
-
-    // Recursive query to compute the cumulative size of each callsite.
-    // Base case: We get all the callsites where the size is non-zero.
-    // Recursive case: We get the callsite which is the parent of the current
-    //  callsite(in terms of hashes) and emit a row with the size of the current
-    //  callsite plus all the info of the parent.
-    // Grouping: For each callsite, our recursive table has n rows where n is
-    //  the number of descendents with a non-zero self size. We need to group on
-    //  the hash and sum all the sizes to get the cumulative size for each
-    //  callsite hash.
-    const callsites = await this.args.engine.query(
-        `with recursive callsite_children(hash, name, parent_hash, depth, size)
-         AS (
-        select *
-        from callsite_hash_name_size
-        where size > 0
-        union all
-        select chns.hash, chns.name, chns.parent_hash, chns.depth, cc.size
-        from callsite_hash_name_size chns
-        inner join callsite_children cc on chns.hash = cc.parent_hash
-        )
-        SELECT hash, name, parent_hash, depth, SUM(size) as size
-        from callsite_children
-        group by hash
-        order by depth, parent_hash, size desc, name
-        `);
-
-    const flamegraphData: CallsiteInfo[] = new Array();
-    for (let i = 0; i < callsites.numRecords; i++) {
-      const hash = callsites.columns[0].longValues![i];
-      const name = callsites.columns[1].stringValues![i];
-      const parentHash = callsites.columns[2].longValues![i];
-      const depth = callsites.columns[3].longValues![i];
-      const totalSize = callsites.columns[4].longValues![i];
-      flamegraphData.push({
-        hash: +hash,
-        totalSize: +totalSize,
-        depth: +depth,
-        parentHash: +parentHash,
-        name
-      });
-    }
-
     return {
       ts: startTime,
       allocated,
       allocatedNotFreed,
       tsNs: ts,
       pid,
-      flamegraphData
     };
   }
 
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index b7ee307..5cf35ab 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -35,6 +35,9 @@
 import {GPU_FREQ_TRACK_KIND} from '../tracks/gpu_freq/common';
 import {HEAP_PROFILE_TRACK_KIND} from '../tracks/heap_profile/common';
 import {
+  HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND
+} from '../tracks/heap_profile_flamegraph/common';
+import {
   PROCESS_SCHEDULING_TRACK_KIND
 } from '../tracks/process_scheduling/common';
 import {PROCESS_SUMMARY_TRACK} from '../tracks/process_summary/common';
@@ -315,7 +318,7 @@
 
     const upidToProcessTracks = new Map();
     const rawProcessTracks = await engine.query(`
-      select id, upid, name, max(depth) as maxDepth
+      select id, upid, process_track.name, max(depth) as maxDepth
       from process_track
       inner join slice on slice.track_id = process_track.id
       group by track_id
@@ -492,7 +495,8 @@
           utid === null ? undefined : utidToThreadTrack.get(utid);
       if (threadTrack === undefined &&
           (upid === null || counterUpids[upid] === undefined) &&
-          counterUtids[utid] === undefined && !threadHasSched) {
+          counterUtids[utid] === undefined && !threadHasSched &&
+          (upid === null || upid !== null && !heapUpids.has(upid))) {
         continue;
       }
 
@@ -520,11 +524,16 @@
           config: {pidForColor, upid, utid},
         });
 
+        const name = upid === null ?
+            `${threadName} ${tid}` :
+            `${
+                processName === null && heapUpids.has(upid) ?
+                    'Heap Profile for' :
+                    processName} ${pid}`;
         addTrackGroupActions.push(Actions.addTrackGroup({
           engineId: this.engineId,
           summaryTrackId,
-          name: upid === null ? `${threadName} ${tid}` :
-                                `${processName} ${pid}`,
+          name,
           id: pUuid,
           collapsed: true,
         }));
@@ -554,6 +563,14 @@
               trackGroup: pUuid,
               config: {upid}
             });
+
+            tracksToAdd.push({
+              engineId: this.engineId,
+              kind: HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND,
+              name: `Heap Profile Flamegraph`,
+              trackGroup: pUuid,
+              config: {upid}
+            });
           }
 
           if (upidToProcessTracks.has(upid)) {
diff --git a/ui/src/frontend/details_panel.ts b/ui/src/frontend/details_panel.ts
new file mode 100644
index 0000000..1bed6ea
--- /dev/null
+++ b/ui/src/frontend/details_panel.ts
@@ -0,0 +1,181 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import * as m from 'mithril';
+
+import {LogExists, LogExistsKey} from '../common/logs';
+
+import {ChromeSliceDetailsPanel} from './chrome_slice_panel';
+import {CounterDetailsPanel} from './counter_panel';
+import {DragGestureHandler} from './drag_gesture_handler';
+import {globals} from './globals';
+import {HeapProfileDetailsPanel} from './heap_profile_panel';
+import {LogPanel} from './logs_panel';
+import {NotesEditorPanel} from './notes_panel';
+import {AnyAttrsVnode, PanelContainer} from './panel_container';
+import {SliceDetailsPanel} from './slice_panel';
+import {ThreadStatePanel} from './thread_state_panel';
+
+const UP_ICON = 'keyboard_arrow_up';
+const DOWN_ICON = 'keyboard_arrow_down';
+const DRAG_HANDLE_HEIGHT_PX = 28;
+const DEFAULT_DETAILS_HEIGHT_PX = 230 + DRAG_HANDLE_HEIGHT_PX;
+
+function hasLogs(): boolean {
+  const data = globals.trackDataStore.get(LogExistsKey) as LogExists;
+  return data && data.exists;
+}
+
+interface DragHandleAttrs {
+  height: number;
+  resize: (height: number) => void;
+}
+
+class DragHandle implements m.ClassComponent<DragHandleAttrs> {
+  private dragStartHeight = 0;
+  private height = 0;
+  private resize: (height: number) => void = () => {};
+  private isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
+
+  oncreate({dom, attrs}: m.CVnodeDOM<DragHandleAttrs>) {
+    this.resize = attrs.resize;
+    this.height = attrs.height;
+    this.isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
+    const elem = dom as HTMLElement;
+    new DragGestureHandler(
+        elem,
+        this.onDrag.bind(this),
+        this.onDragStart.bind(this),
+        this.onDragEnd.bind(this));
+  }
+
+  onupdate({attrs}: m.CVnodeDOM<DragHandleAttrs>) {
+    this.resize = attrs.resize;
+    this.height = attrs.height;
+    this.isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
+  }
+
+  onDrag(_x: number, y: number) {
+    const newHeight = this.dragStartHeight + (DRAG_HANDLE_HEIGHT_PX / 2) - y;
+    this.isClosed = Math.floor(newHeight) <= DRAG_HANDLE_HEIGHT_PX;
+    this.resize(Math.floor(newHeight));
+    globals.rafScheduler.scheduleFullRedraw();
+  }
+
+  onDragStart(_x: number, _y: number) {
+    this.dragStartHeight = this.height;
+  }
+
+  onDragEnd() {}
+
+  view() {
+    const icon = this.isClosed ? UP_ICON : DOWN_ICON;
+    const title = this.isClosed ? 'Show panel' : 'Hide panel';
+    return m(
+        '.handle',
+        m('.handle-title', 'Current Selection'),
+        m('i.material-icons',
+          {
+            onclick: () => {
+              if (this.height === DRAG_HANDLE_HEIGHT_PX) {
+                this.isClosed = false;
+                this.resize(DEFAULT_DETAILS_HEIGHT_PX);
+              } else {
+                this.isClosed = true;
+                this.resize(DRAG_HANDLE_HEIGHT_PX);
+              }
+              globals.rafScheduler.scheduleFullRedraw();
+            },
+            title
+          },
+          icon));
+  }
+}
+
+export class DetailsPanel implements m.ClassComponent {
+  private detailsHeight = DRAG_HANDLE_HEIGHT_PX;
+  // Used to set details panel to default height on selection.
+  private showDetailsPanel = true;
+
+  view() {
+    const detailsPanels: AnyAttrsVnode[] = [];
+    const curSelection = globals.state.currentSelection;
+    if (curSelection) {
+      switch (curSelection.kind) {
+        case 'NOTE':
+          detailsPanels.push(m(NotesEditorPanel, {
+            key: 'notes',
+            id: curSelection.id,
+          }));
+          break;
+        case 'SLICE':
+          detailsPanels.push(m(SliceDetailsPanel, {
+            key: 'slice',
+          }));
+          break;
+        case 'COUNTER':
+          detailsPanels.push(m(CounterDetailsPanel, {
+            key: 'counter',
+          }));
+          break;
+        case 'HEAP_PROFILE':
+          detailsPanels.push(m(HeapProfileDetailsPanel, {key: 'heap_profile'}));
+          break;
+        case 'CHROME_SLICE':
+          detailsPanels.push(m(ChromeSliceDetailsPanel));
+          break;
+        case 'THREAD_STATE':
+          detailsPanels.push(m(ThreadStatePanel, {
+            key: 'thread_state',
+            ts: curSelection.ts,
+            dur: curSelection.dur,
+            utid: curSelection.utid,
+            state: curSelection.state,
+            cpu: curSelection.cpu
+          }));
+          break;
+        default:
+          break;
+      }
+    } else if (hasLogs()) {
+      detailsPanels.push(m(LogPanel, {}));
+    }
+
+    const wasShowing = this.showDetailsPanel;
+    this.showDetailsPanel = detailsPanels.length > 0;
+    // Pop up details panel on first selection.
+    if (!wasShowing && this.showDetailsPanel &&
+        this.detailsHeight === DRAG_HANDLE_HEIGHT_PX) {
+      this.detailsHeight = DEFAULT_DETAILS_HEIGHT_PX;
+    }
+
+    return m(
+        '.details-content',
+        {
+          style: {
+            height: `${this.detailsHeight}px`,
+            display: this.showDetailsPanel ? null : 'none'
+          }
+        },
+        m(DragHandle, {
+          resize: (height: number) => {
+            this.detailsHeight = Math.max(height, DRAG_HANDLE_HEIGHT_PX);
+          },
+          height: this.detailsHeight,
+        }),
+        m('.details-panel-container',
+          m(PanelContainer,
+            {doesScroll: true, panels: detailsPanels, kind: 'DETAILS'})));
+  }
+}
diff --git a/ui/src/frontend/flamegraph.ts b/ui/src/frontend/flamegraph.ts
index 64ae4d0..f8d38a4 100644
--- a/ui/src/frontend/flamegraph.ts
+++ b/ui/src/frontend/flamegraph.ts
@@ -29,14 +29,17 @@
   width: number;
 }
 
-const NODE_HEIGHT_MIN = 12;
+const NODE_HEIGHT_MIN = 10;
 const NODE_HEIGHT_MAX = 25;
+const NODE_HEIGHT_DEFAULT = 15;
 
 export class Flamegraph {
-  private nodeHeight = NODE_HEIGHT_MIN;
+  private nodeHeight = NODE_HEIGHT_DEFAULT;
+  // If selected, node height will be calculated based on space that is provided
+  // in draw method
   private flamegraphData: CallsiteInfo[];
   private maxDepth = -1;
-  private calculateNodeHeight = true;
+  private totalSize = -1;
   private textSize = 12;
   // Key for the map is depth followed by x coordinate - `depth;x`
   private graphData: Map<string, CallsiteInfoWidth> = new Map();
@@ -56,15 +59,25 @@
   constructor(flamegraphData: CallsiteInfo[]) {
     this.flamegraphData = flamegraphData;
     this.findMaxDepth();
-    this.calculateNodeHeight = true;
   }
 
   private findMaxDepth() {
+    this.maxDepth = -1;
     this.flamegraphData.forEach((value: CallsiteInfo) => {
       this.maxDepth = this.maxDepth < value.depth ? value.depth : this.maxDepth;
     });
   }
 
+  private findTotalSize() {
+    let totalSize = 0;
+    this.flamegraphData.forEach((value: CallsiteInfo) => {
+      if (value.parentHash === -1) {
+        totalSize += value.totalSize;
+      }
+    });
+    return totalSize;
+  }
+
   hash(s: string): number {
     let hash = 0x811c9dc5 & 0xfffffff;
     for (let i = 0; i < s.length; i++) {
@@ -87,39 +100,40 @@
    * Caller will have to call draw method ater updating data to have updated
    * graph.
    */
-  updateData(flamegraphData: CallsiteInfo[]) {
+  updateDataIfChanged(flamegraphData: CallsiteInfo[]) {
+    if (this.flamegraphData === flamegraphData) {
+      return;
+    }
     this.flamegraphData = flamegraphData;
+    this.clickedCallsite = undefined;
     this.findMaxDepth();
-    this.calculateNodeHeight = true;
+    // Finding total size of roots.
+    this.totalSize = this.findTotalSize();
   }
 
   draw(
       ctx: CanvasRenderingContext2D, width: number, height: number, x = 0,
-      y = 0, unit = 'B') {
-    if (this.calculateNodeHeight) {
+      y = 0, unit = 'B', fillHeight = false) {
+    // TODO(tneda): Instead of pesimistic approach improve displaying text.
+    const name = '____MMMMMMQQwwZZZZZZzzzzzznnnnnnwwwwwwWWWWWqq$$mmmmmm__';
+    const charWidth = ctx.measureText(name).width / name.length;
+    if (fillHeight) {
       const calcHeight = Math.round((height - 10) / (this.maxDepth + 2));
-      this.calculateNodeHeight = false;
       this.nodeHeight = calcHeight < NODE_HEIGHT_MIN ?
           NODE_HEIGHT_MIN :
           calcHeight > NODE_HEIGHT_MAX ? NODE_HEIGHT_MAX : calcHeight;
       this.textSize = this.nodeHeight - 3 > 15 ? 15 : this.nodeHeight - 3;
+    } else {
+      this.nodeHeight = NODE_HEIGHT_DEFAULT;
     }
 
     if (this.flamegraphData !== undefined) {
-      // Finding total size of roots.
-      let totalSize = 0;
-      this.flamegraphData.forEach((value: CallsiteInfo) => {
-        if (value.parentHash === -1) {
-          totalSize += value.totalSize;
-        }
-      });
-
       // For each node, we use this map to get information about it's parent
       // (total size of it, width and where it starts in graph) so we can
       // calculate it's own position in graph.
       const nodesMap = new Map<number, Node>();
       let currentY = y;
-      nodesMap.set(-1, {width, nextXForChildren: x, size: totalSize, x});
+      nodesMap.set(-1, {width, nextXForChildren: x, size: this.totalSize, x});
 
       // Initialize data needed for click/hover behaivior.
       this.graphData = new Map();
@@ -164,7 +178,7 @@
           continue;
         }
         const parent = value.parentHash;
-        const parentSize = parent === -1 ? totalSize : parentNode.size;
+        const parentSize = parent === -1 ? this.totalSize : parentNode.size;
         // Calculate node's width based on its proportion in parent.
         const width =
             (isFullWidth ? 1 : value.totalSize / parentSize) * parentNode.width;
@@ -180,8 +194,7 @@
         // Draw name.
         const name = this.getCallsiteName(value);
         ctx.font = `${this.textSize}px Google Sans`;
-        const charWidth = ctx.measureText(name).width / name.length;
-        const text = cropText(name, charWidth, width);
+        const text = cropText(name, charWidth, width - 2);
         ctx.fillStyle = 'black';
         ctx.fillText(text, currentX + 5, currentY + this.nodeHeight - 4);
 
@@ -233,7 +246,8 @@
       if (this.hoveredX > -1 && this.hoveredY > -1 && this.hoveredCallsite) {
         // Draw the tooltip.
         const line1 = this.getCallsiteName(this.hoveredCallsite);
-        const percentage = this.hoveredCallsite.totalSize / totalSize * 100;
+        const percentage =
+            this.hoveredCallsite.totalSize / this.totalSize * 100;
         const line2 = `total: ${this.hoveredCallsite.totalSize}${unit} (${
             percentage.toFixed(2)}%)`;
         ctx.font = '12px Google Sans';
@@ -297,4 +311,10 @@
     const [left, ] = searchSegment(haystack, needle);
     return left === -1 ? -1 : haystack[left];
   }
+
+  getHeight(): number {
+    return this.flamegraphData.length === 0 ?
+        0 :
+        (this.maxDepth + 2) * this.nodeHeight;
+  }
 }
diff --git a/ui/src/frontend/frontend_local_state.ts b/ui/src/frontend/frontend_local_state.ts
index 25f7991..85d1eff 100644
--- a/ui/src/frontend/frontend_local_state.ts
+++ b/ui/src/frontend/frontend_local_state.ts
@@ -95,6 +95,7 @@
   visibleTracks = new Set<string>();
   prevVisibleTracks = new Set<string>();
   searchIndex = -1;
+  scrollToTrackId: undefined|string|number = undefined;
   private scrollBarWidth: undefined|number = undefined;
 
   private _omniboxState: OmniboxState = {
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index 3313625..032cdb5 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -28,6 +28,7 @@
   dur?: number;
   priority?: number;
   endState?: string;
+  cpu?: number;
   id?: number;
   utid?: number;
   wakeupTs?: number;
@@ -52,13 +53,12 @@
   totalSize: number;
 }
 
-export interface HeapDumpDetails {
+export interface HeapProfileDetails {
   ts?: number;
   tsNs?: number;
   allocated?: number;
   allocatedNotFreed?: number;
   pid?: number;
-  flamegraphData?: CallsiteInfo[];
 }
 
 export interface QuantizedLoad {
@@ -94,7 +94,7 @@
   private _threadMap?: ThreadMap = undefined;
   private _sliceDetails?: SliceDetails = undefined;
   private _counterDetails?: CounterDetails = undefined;
-  private _heapDumpDetails?: HeapDumpDetails = undefined;
+  private _heapDumpDetails?: HeapProfileDetails = undefined;
   private _isLoading = false;
   private _bufferUsage?: number = undefined;
   private _recordingLog?: string = undefined;
@@ -186,7 +186,7 @@
     return assertExists(this._heapDumpDetails);
   }
 
-  set heapDumpDetails(click: HeapDumpDetails) {
+  set heapDumpDetails(click: HeapProfileDetails) {
     this._heapDumpDetails = assertExists(click);
   }
 
diff --git a/ui/src/frontend/heap_dump_panel.ts b/ui/src/frontend/heap_profile_panel.ts
similarity index 88%
rename from ui/src/frontend/heap_dump_panel.ts
rename to ui/src/frontend/heap_profile_panel.ts
index 7c31636..f9ab242 100644
--- a/ui/src/frontend/heap_dump_panel.ts
+++ b/ui/src/frontend/heap_profile_panel.ts
@@ -20,17 +20,19 @@
 import {globals} from './globals';
 import {Panel} from './panel';
 
-interface HeapDumpDetailsPanelAttrs {}
+interface HeapProfileDetailsPanelAttrs {}
 
-export class HeapDumpDetailsPanel extends Panel<HeapDumpDetailsPanelAttrs> {
+export class HeapProfileDetailsPanel extends
+    Panel<HeapProfileDetailsPanelAttrs> {
   private ts = 0;
   private pid = 0;
 
   view() {
     const heapDumpInfo = globals.heapDumpDetails;
-    if (heapDumpInfo && heapDumpInfo.ts && heapDumpInfo.allocated &&
-        heapDumpInfo.allocatedNotFreed && heapDumpInfo.tsNs &&
-        heapDumpInfo.pid) {
+    if (heapDumpInfo && heapDumpInfo.ts !== undefined &&
+        heapDumpInfo.allocated !== undefined &&
+        heapDumpInfo.allocatedNotFreed !== undefined &&
+        heapDumpInfo.tsNs !== undefined && heapDumpInfo.pid !== undefined) {
       this.ts = heapDumpInfo.tsNs;
       this.pid = heapDumpInfo.pid;
       return m(
diff --git a/ui/src/frontend/index.ts b/ui/src/frontend/index.ts
index 2b1effe..5682502 100644
--- a/ui/src/frontend/index.ts
+++ b/ui/src/frontend/index.ts
@@ -28,11 +28,14 @@
   LogExistsKey
 } from '../common/logs';
 import {CurrentSearchResults, SearchSummary} from '../common/search_data';
+import {
+  HeapProfileFlamegraphKey
+} from '../tracks/heap_profile_flamegraph/common';
 
 import {
   CounterDetails,
   globals,
-  HeapDumpDetails,
+  HeapProfileDetails,
   QuantizedLoad,
   SliceDetails,
   ThreadDesc
@@ -95,6 +98,8 @@
     if ([LogExistsKey, LogBoundsKey, LogEntriesKey].includes(args.id)) {
       const data = globals.trackDataStore.get(LogExistsKey) as LogExists;
       if (data && data.exists) globals.rafScheduler.scheduleFullRedraw();
+    } else if (HeapProfileFlamegraphKey === args.id) {
+      globals.rafScheduler.scheduleFullRedraw();
     } else {
       globals.rafScheduler.scheduleRedraw();
     }
@@ -123,7 +128,7 @@
     this.redraw();
   }
 
-  publishHeapDumpDetails(click: HeapDumpDetails) {
+  publishHeapDumpDetails(click: HeapProfileDetails) {
     globals.heapDumpDetails = click;
     this.redraw();
   }
diff --git a/ui/src/frontend/slice_panel.ts b/ui/src/frontend/slice_panel.ts
index 80f5c7b..99191fe 100644
--- a/ui/src/frontend/slice_panel.ts
+++ b/ui/src/frontend/slice_panel.ts
@@ -14,6 +14,7 @@
 
 import * as m from 'mithril';
 
+import {Actions} from '../common/actions';
 import {drawDoubleHeadedArrow} from '../common/canvas_utils';
 import {translateState} from '../common/thread_state';
 import {timeToCode} from '../common/time';
@@ -21,37 +22,46 @@
 import {globals} from './globals';
 import {Panel, PanelSize} from './panel';
 
-
 export class SliceDetailsPanel extends Panel {
   view() {
     const sliceInfo = globals.sliceDetails;
-    if (!sliceInfo.utid) return;
+    if (sliceInfo.utid === undefined) return;
     const threadInfo = globals.threads.get(sliceInfo.utid);
 
-    if (threadInfo && sliceInfo.ts && sliceInfo.dur) {
+    if (threadInfo && sliceInfo.ts !== undefined &&
+        sliceInfo.dur !== undefined) {
       return m(
           '.details-panel',
           m('.details-panel-heading', `Slice Details:`),
-          m('.details-table', [m('table', [
-              m('tr', m('th', `PID`), m('td', `${threadInfo.pid}`)),
-              m('tr',
-                m('th', `Process name`),
-                m('td', `${threadInfo.procName}`)),
-              m('tr', m('th', `TID`), m('td', `${threadInfo.tid}`)),
-              m('tr',
-                m('th', `Thread name`),
-                m('td', `${threadInfo.threadName}`)),
-              m('tr',
-                m('th', `Start time`),
-                m('td', `${timeToCode(sliceInfo.ts)}`)),
-              m('tr',
-                m('th', `Duration`),
-                m('td', `${timeToCode(sliceInfo.dur)}`)),
-              m('tr', m('th', `Prio`), m('td', `${sliceInfo.priority}`)),
-              m('tr',
-                m('th', `End State`),
-                m('td', `${translateState(sliceInfo.endState)}`))
-            ])], ));
+          m(
+              '.details-table',
+              [m('table',
+                 [
+                   m('tr',
+                     m('th', `Process`),
+                     m('td', `${threadInfo.procName} [${threadInfo.pid}]`)),
+                   m('tr',
+                     m('th', `Thread`),
+                     m('td',
+                       `${threadInfo.threadName} [${threadInfo.tid}]`,
+                       m('i.material-icons',
+                         {
+                           onclick: () => this.goToThread(),
+                           title: 'Go to thread'
+                         },
+                         'call_made'))),
+                   m('tr',
+                     m('th', `Start time`),
+                     m('td', `${timeToCode(sliceInfo.ts)}`)),
+                   m('tr',
+                     m('th', `Duration`),
+                     m('td', `${timeToCode(sliceInfo.dur)}`)),
+                   m('tr', m('th', `Prio`), m('td', `${sliceInfo.priority}`)),
+                   m('tr',
+                     m('th', `End State`),
+                     m('td', `${translateState(sliceInfo.endState)}`))
+                 ])],
+              ));
     } else {
       return m(
           '.details-panel',
@@ -62,6 +72,41 @@
     }
   }
 
+  goToThread() {
+    const sliceInfo = globals.sliceDetails;
+    if (sliceInfo.utid === undefined) return;
+    const threadInfo = globals.threads.get(sliceInfo.utid);
+
+    if (sliceInfo.id === undefined || sliceInfo.ts === undefined ||
+        sliceInfo.dur === undefined || sliceInfo.cpu === undefined ||
+        threadInfo === undefined) {
+      return;
+    }
+    globals.makeSelection(Actions.selectThreadState({
+      utid: threadInfo.utid,
+      ts: sliceInfo.ts + globals.state.traceTime.startSec,
+      dur: sliceInfo.dur,
+      state: 'Running',
+      cpu: sliceInfo.cpu,
+    }));
+    let trackId: string|number|undefined;
+    let trackGroupId;
+    for (const track of Object.values(globals.state.tracks)) {
+      if (track.kind === 'ThreadStateTrack' &&
+          (track.config as {utid: number}).utid === threadInfo.utid) {
+        trackGroupId = track.trackGroup;
+        trackId = track.id;
+      }
+    }
+    // After the track exists in the dom, it will be scrolled to.
+    globals.frontendLocalState.scrollToTrackId = trackId;
+
+    if (trackGroupId && globals.state.trackGroups[trackGroupId].collapsed) {
+      globals.dispatch(Actions.toggleTrackGroupCollapsed({trackGroupId}));
+    }
+  }
+
+
   renderCanvas(ctx: CanvasRenderingContext2D, size: PanelSize) {
     const details = globals.sliceDetails;
     // Show expanded details on the scheduling of the currently selected slice.
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index d60f4b4..1af0ef0 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -20,6 +20,7 @@
 import {globals} from './globals';
 import {drawGridLines} from './gridline_helper';
 import {Panel, PanelSize} from './panel';
+import {verticalScrollToTrack} from './scroll_helper';
 import {Track} from './track';
 import {TRACK_SHELL_WIDTH} from './track_constants';
 import {trackRegistry} from './track_registry';
@@ -187,6 +188,13 @@
           m(TrackContent, {track: attrs.track})
         ]);
   }
+
+  onupdate({attrs}: m.CVnode<TrackComponentAttrs>) {
+    if (globals.frontendLocalState.scrollToTrackId === attrs.trackState.id) {
+      verticalScrollToTrack(attrs.trackState.id);
+      globals.frontendLocalState.scrollToTrackId = undefined;
+    }
+  }
 }
 
 export interface TrackButtonAttrs {
diff --git a/ui/src/frontend/viewer_page.ts b/ui/src/frontend/viewer_page.ts
index 9bea625..37c0279 100644
--- a/ui/src/frontend/viewer_page.ts
+++ b/ui/src/frontend/viewer_page.ts
@@ -15,25 +15,18 @@
 import * as m from 'mithril';
 
 import {Actions} from '../common/actions';
-import {LogExists, LogExistsKey} from '../common/logs';
 import {QueryResponse} from '../common/queries';
 import {TimeSpan} from '../common/time';
 
-import {ChromeSliceDetailsPanel} from './chrome_slice_panel';
 import {copyToClipboard} from './clipboard';
-import {CounterDetailsPanel} from './counter_panel';
-import {DragGestureHandler} from './drag_gesture_handler';
+import {DetailsPanel} from './details_panel';
 import {globals} from './globals';
-import {HeapDumpDetailsPanel} from './heap_dump_panel';
-import {LogPanel} from './logs_panel';
-import {NotesEditorPanel, NotesPanel} from './notes_panel';
+import {NotesPanel} from './notes_panel';
 import {OverviewTimelinePanel} from './overview_timeline_panel';
 import {createPage} from './pages';
 import {PanAndZoomHandler} from './pan_and_zoom_handler';
 import {Panel} from './panel';
 import {AnyAttrsVnode, PanelContainer} from './panel_container';
-import {SliceDetailsPanel} from './slice_panel';
-import {ThreadStatePanel} from './thread_state_panel';
 import {TickmarkPanel} from './tickmark_panel';
 import {TimeAxisPanel} from './time_axis_panel';
 import {computeZoom} from './time_scale';
@@ -43,17 +36,8 @@
 import {TrackPanel} from './track_panel';
 import {VideoPanel} from './video_panel';
 
-const DRAG_HANDLE_HEIGHT_PX = 28;
-const DEFAULT_DETAILS_HEIGHT_PX = 230 + DRAG_HANDLE_HEIGHT_PX;
-const UP_ICON = 'keyboard_arrow_up';
-const DOWN_ICON = 'keyboard_arrow_down';
 const SIDEBAR_WIDTH = 256;
 
-function hasLogs(): boolean {
-  const data = globals.trackDataStore.get(LogExistsKey) as LogExists;
-  return data && data.exists;
-}
-
 class QueryTable extends Panel {
   view() {
     const resp = globals.queryResults.get('command') as QueryResponse;
@@ -113,71 +97,6 @@
   renderCanvas() {}
 }
 
-interface DragHandleAttrs {
-  height: number;
-  resize: (height: number) => void;
-}
-
-class DragHandle implements m.ClassComponent<DragHandleAttrs> {
-  private dragStartHeight = 0;
-  private height = 0;
-  private resize: (height: number) => void = () => {};
-  private isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
-
-  oncreate({dom, attrs}: m.CVnodeDOM<DragHandleAttrs>) {
-    this.resize = attrs.resize;
-    this.height = attrs.height;
-    this.isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
-    const elem = dom as HTMLElement;
-    new DragGestureHandler(
-        elem,
-        this.onDrag.bind(this),
-        this.onDragStart.bind(this),
-        this.onDragEnd.bind(this));
-  }
-
-  onupdate({attrs}: m.CVnodeDOM<DragHandleAttrs>) {
-    this.resize = attrs.resize;
-    this.height = attrs.height;
-    this.isClosed = this.height <= DRAG_HANDLE_HEIGHT_PX;
-  }
-
-  onDrag(_x: number, y: number) {
-    const newHeight = this.dragStartHeight + (DRAG_HANDLE_HEIGHT_PX / 2) - y;
-    this.isClosed = Math.floor(newHeight) <= DRAG_HANDLE_HEIGHT_PX;
-    this.resize(Math.floor(newHeight));
-    globals.rafScheduler.scheduleFullRedraw();
-  }
-
-  onDragStart(_x: number, _y: number) {
-    this.dragStartHeight = this.height;
-  }
-
-  onDragEnd() {}
-
-  view() {
-    const icon = this.isClosed ? UP_ICON : DOWN_ICON;
-    const title = this.isClosed ? 'Show panel' : 'Hide panel';
-    return m(
-        '.handle',
-        m('.handle-title', 'Current Selection'),
-        m('i.material-icons',
-          {
-            onclick: () => {
-              if (this.height === DRAG_HANDLE_HEIGHT_PX) {
-                this.isClosed = false;
-                this.resize(DEFAULT_DETAILS_HEIGHT_PX);
-              } else {
-                this.isClosed = true;
-                this.resize(DRAG_HANDLE_HEIGHT_PX);
-              }
-              globals.rafScheduler.scheduleFullRedraw();
-            },
-            title
-          },
-          icon));
-  }
-}
 
 // Checks if the mousePos is within 3px of the start or end of the
 // current selected time range.
@@ -206,9 +125,6 @@
 class TraceViewer implements m.ClassComponent {
   private onResize: () => void = () => {};
   private zoomContent?: PanAndZoomHandler;
-  private detailsHeight = DRAG_HANDLE_HEIGHT_PX;
-  // Used to set details panel to default height on selection.
-  private showDetailsPanel = true;
   // Used to prevent global deselection if a pan/drag select occurred.
   private keepCurrentSelection = false;
 
@@ -327,57 +243,6 @@
     }
     scrollingPanels.unshift(m(QueryTable, {key: 'query'}));
 
-    const detailsPanels: AnyAttrsVnode[] = [];
-    const curSelection = globals.state.currentSelection;
-    if (curSelection) {
-      switch (curSelection.kind) {
-        case 'NOTE':
-          detailsPanels.push(m(NotesEditorPanel, {
-            key: 'notes',
-            id: curSelection.id,
-          }));
-          break;
-        case 'SLICE':
-          detailsPanels.push(m(SliceDetailsPanel, {
-            key: 'slice',
-          }));
-          break;
-        case 'COUNTER':
-          detailsPanels.push(m(CounterDetailsPanel, {
-            key: 'counter',
-          }));
-          break;
-        case 'HEAP_DUMP':
-          detailsPanels.push(m(HeapDumpDetailsPanel, {key: 'heap_dump'}));
-          break;
-        case 'CHROME_SLICE':
-          detailsPanels.push(m(ChromeSliceDetailsPanel));
-          break;
-        case 'THREAD_STATE':
-          detailsPanels.push(m(ThreadStatePanel, {
-            key: 'thread_state',
-            ts: curSelection.ts,
-            dur: curSelection.dur,
-            utid: curSelection.utid,
-            state: curSelection.state,
-            cpu: curSelection.cpu
-          }));
-          break;
-        default:
-          break;
-      }
-    } else if (hasLogs()) {
-      detailsPanels.push(m(LogPanel, {}));
-    }
-
-    const wasShowing = this.showDetailsPanel;
-    this.showDetailsPanel = detailsPanels.length > 0;
-    // Pop up details panel on first selection.
-    if (!wasShowing && this.showDetailsPanel &&
-        this.detailsHeight === DRAG_HANDLE_HEIGHT_PX) {
-      this.detailsHeight = DEFAULT_DETAILS_HEIGHT_PX;
-    }
-
     return m(
         '.page',
         m('.split-panel',
@@ -414,22 +279,7 @@
             (globals.state.videoEnabled && globals.state.video != null) ?
                 m(VideoPanel) :
                 null)),
-        m('.details-content',
-          {
-            style: {
-              height: `${this.detailsHeight}px`,
-              display: this.showDetailsPanel ? null : 'none'
-            }
-          },
-          m(DragHandle, {
-            resize: (height: number) => {
-              this.detailsHeight = Math.max(height, DRAG_HANDLE_HEIGHT_PX);
-            },
-            height: this.detailsHeight,
-          }),
-          m('.details-panel-container',
-            m(PanelContainer,
-              {doesScroll: true, panels: detailsPanels, kind: 'DETAILS'}))));
+        m(DetailsPanel));
   }
 }
 
diff --git a/ui/src/tracks/all_controller.ts b/ui/src/tracks/all_controller.ts
index ca4f7c8..912f34f 100644
--- a/ui/src/tracks/all_controller.ts
+++ b/ui/src/tracks/all_controller.ts
@@ -18,6 +18,7 @@
 import './chrome_slices/controller';
 import './counter/controller';
 import './heap_profile/controller';
+import './heap_profile_flamegraph/controller';
 import './cpu_freq/controller';
 import './gpu_freq/controller';
 import './cpu_slices/controller';
diff --git a/ui/src/tracks/all_frontend.ts b/ui/src/tracks/all_frontend.ts
index 3ce3de0..2957edf 100644
--- a/ui/src/tracks/all_frontend.ts
+++ b/ui/src/tracks/all_frontend.ts
@@ -18,6 +18,7 @@
 import './chrome_slices/frontend';
 import './counter/frontend';
 import './heap_profile/frontend';
+import './heap_profile_flamegraph/frontend';
 import './cpu_freq/frontend';
 import './gpu_freq/frontend';
 import './cpu_slices/frontend';
diff --git a/ui/src/tracks/heap_profile/frontend.ts b/ui/src/tracks/heap_profile/frontend.ts
index 9acc6f6..b4a8bde 100644
--- a/ui/src/tracks/heap_profile/frontend.ts
+++ b/ui/src/tracks/heap_profile/frontend.ts
@@ -20,7 +20,6 @@
 import {TimeScale} from '../../frontend/time_scale';
 import {Track} from '../../frontend/track';
 import {trackRegistry} from '../../frontend/track_registry';
-
 import {Config, Data, HEAP_PROFILE_TRACK_KIND} from './common';
 
 // 0.5 Makes the horizontal lines sharp.
@@ -57,8 +56,8 @@
       const centerX = data.tsStarts[i];
       const selection = globals.state.currentSelection;
       const isHovered = this.hoveredTs === centerX;
-      const isSelected = selection !== null && selection.kind === 'HEAP_DUMP' &&
-          selection.ts === centerX;
+      const isSelected = selection !== null &&
+          selection.kind === 'HEAP_PROFILE' && selection.ts === centerX;
       const lightness = isHovered ? '65' : '85';
       const strokeWidth = isSelected ? 3 : 0;
       this.drawMarker(
@@ -115,8 +114,10 @@
 
     if (index !== -1) {
       const ts = data.tsStarts[index];
+      globals.dispatch(Actions.showHeapProfileFlamegraph(
+          {id: index, upid: this.config.upid, ts}));
       globals.makeSelection(
-          Actions.selectHeapDump({id: index, upid: this.config.upid, ts}));
+          Actions.selectHeapProfile({id: index, upid: this.config.upid, ts}));
       return true;
     }
     return false;
diff --git a/ui/src/tracks/heap_profile_flamegraph/common.ts b/ui/src/tracks/heap_profile_flamegraph/common.ts
new file mode 100644
index 0000000..fa71b0d
--- /dev/null
+++ b/ui/src/tracks/heap_profile_flamegraph/common.ts
@@ -0,0 +1,27 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+import {CallsiteInfo} from 'src/frontend/globals';
+
+import {TrackData} from '../../common/track_data';
+
+export const HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND = 'HeapProfileFlamegraphTrack';
+export const HeapProfileFlamegraphKey = 'heap-profile-flamegraph';
+
+export interface Data extends TrackData {
+  flamegraph: CallsiteInfo[];
+}
+
+export interface Config {
+  upid: number;
+}
diff --git a/ui/src/tracks/heap_profile_flamegraph/controller.ts b/ui/src/tracks/heap_profile_flamegraph/controller.ts
new file mode 100644
index 0000000..226c0df
--- /dev/null
+++ b/ui/src/tracks/heap_profile_flamegraph/controller.ts
@@ -0,0 +1,187 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {globals} from '../../controller/globals';
+import {
+  TrackController,
+  trackControllerRegistry
+} from '../../controller/track_controller';
+import {CallsiteInfo} from '../../frontend/globals';
+
+import {
+  Config,
+  Data,
+  HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND,
+  HeapProfileFlamegraphKey,
+} from './common';
+
+class HeapProfileFlameraphTrackController extends
+    TrackController<Config, Data> {
+  static readonly kind = HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND;
+  private start = 0;
+  private end = 0;
+  private resolution = 0;
+  private length = 0;
+  private lastSelectedTs?: number;
+  private lastSelectedId?: number;
+
+  async onBoundsChange(start: number, end: number, resolution: number):
+      Promise<Data> {
+    this.start = start;
+    this.end = end;
+    this.resolution = resolution;
+
+    return this.generateEmptyData();
+  }
+
+  private generateEmptyData() {
+    const data: Data = {
+      start: -1,
+      end: -1,
+      resolution: this.resolution,
+      length: 0,
+      flamegraph: new Array()
+    };
+    return data;
+  }
+
+  run() {
+    super.run();
+    const selection = globals.state.currentHeapProfileFlamegraph;
+    if (selection && selection.kind === 'HEAP_PROFILE_FLAMEGRAPH') {
+      if (this.lastSelectedId === selection.id &&
+          this.lastSelectedTs === selection.ts) {
+        return;
+      }
+      const selectedId = selection.id;
+      const selectedKind = selection.kind;
+      const selectedTs = selection.ts;
+      this.lastSelectedId = selection.id;
+      this.lastSelectedTs = selection.ts;
+
+      // Sending empty data to show tha Loading state before we get an actual
+      // data.
+      globals.publish(
+          'TrackData',
+          {id: HeapProfileFlamegraphKey, data: this.generateEmptyData()});
+
+      this.getFlamegraphData(selection.ts, selection.upid).then(flamegraph => {
+        if (flamegraph !== undefined && selection &&
+            selection.kind === selectedKind && selection.id === selectedId &&
+            selection.ts === selectedTs) {
+          globals.publish('TrackData', {
+            id: HeapProfileFlamegraphKey,
+            data: {
+              start: this.start,
+              end: this.end,
+              resolution: this.resolution,
+              length: this.length,
+              flamegraph
+            }
+          });
+        }
+      });
+    }
+  }
+
+  async getFlamegraphData(ts: number, upid: number) {
+    // Collecting data for drawing flagraph for selected heap profile.
+    // Data needs to be in following format:
+    // id, name, parent_id, depth, total_size
+
+    // Creating unique names for views so we can reuse and not delete them
+    // for each marker.
+    const tableNameCallsiteNameSize =
+        this.tableName(`callsite_with_name_and_size_${ts}`);
+    const tableNameCallsiteHashNameSize =
+        this.tableName(`callsite_hash_name_size_${ts}`);
+    // Joining the callsite table with frame table then with alloc table to get
+    // the size and name for each callsite.
+    await this.query(
+        // TODO(tneda|lalitm): get names from symbols to exactly replicate
+        // pprof.
+        `create view if not exists ${tableNameCallsiteNameSize} as
+      select cs.id, parent_id, depth, name, SUM(IFNULL(size, 0)) as size
+      from stack_profile_callsite cs
+      join stack_profile_frame on cs.frame_id = stack_profile_frame.id
+      left join heap_profile_allocation alloc on alloc.callsite_id = cs.id and
+      alloc.ts <= ${ts} and alloc.upid = ${upid} group by cs.id`);
+
+    // Recursive query to compute the hash for each callsite based on names
+    // rather than ids.
+    // We get all the children of the row in question and emit a row with hash
+    // equal hash(name, parent.hash). Roots without the parent will have -1 as
+    // hash.  Slices will be merged into a big slice.
+    await this.query(
+        `create view if not exists ${tableNameCallsiteHashNameSize} as
+      with recursive callsite_table_names(
+        id, hash, name, size, parent_hash, depth) AS (
+      select id, hash(name) as hash, name, size, -1, depth
+      from ${tableNameCallsiteNameSize}
+      where depth = 0
+      UNION ALL
+      SELECT cs.id, hash(cs.name, ctn.hash) as hash, cs.name, cs.size, ctn.hash,
+      cs.depth
+      FROM callsite_table_names ctn
+      INNER JOIN ${tableNameCallsiteNameSize} cs ON ctn.id = cs.parent_id
+      )
+      SELECT hash, name, parent_hash, depth, SUM(size) as size
+      FROM callsite_table_names
+      group by hash`);
+
+    // Recursive query to compute the cumulative size of each callsite.
+    // Base case: We get all the callsites where the size is non-zero.
+    // Recursive case: We get the callsite which is the parent of the current
+    //  callsite(in terms of hashes) and emit a row with the size of the current
+    //  callsite plus all the info of the parent.
+    // Grouping: For each callsite, our recursive table has n rows where n is
+    //  the number of descendents with a non-zero self size. We need to group on
+    //  the hash and sum all the sizes to get the cumulative size for each
+    //  callsite hash.
+    const callsites = await this.query(
+        `with recursive callsite_children(hash, name, parent_hash, depth, size)
+        AS (
+        select *
+        from ${tableNameCallsiteHashNameSize}
+        where size > 0
+        union all
+        select chns.hash, chns.name, chns.parent_hash, chns.depth, cc.size
+        from ${tableNameCallsiteHashNameSize} chns
+        inner join callsite_children cc on chns.hash = cc.parent_hash
+        )
+        SELECT hash, name, parent_hash, depth, SUM(size) as size
+        from callsite_children
+        group by hash
+        order by depth, parent_hash, size desc, name`);
+
+    const flamegraphData: CallsiteInfo[] = new Array();
+    for (let i = 0; i < callsites.numRecords; i++) {
+      const hash = callsites.columns[0].longValues![i];
+      const name = callsites.columns[1].stringValues![i];
+      const parentHash = callsites.columns[2].longValues![i];
+      const depth = callsites.columns[3].longValues![i];
+      const totalSize = callsites.columns[4].longValues![i];
+      flamegraphData.push({
+        hash: +hash,
+        totalSize: +totalSize,
+        depth: +depth,
+        parentHash: +parentHash,
+        name
+      });
+    }
+    return flamegraphData;
+  }
+}
+
+trackControllerRegistry.register(HeapProfileFlameraphTrackController);
diff --git a/ui/src/tracks/heap_profile_flamegraph/frontend.ts b/ui/src/tracks/heap_profile_flamegraph/frontend.ts
new file mode 100644
index 0000000..7acc29c
--- /dev/null
+++ b/ui/src/tracks/heap_profile_flamegraph/frontend.ts
@@ -0,0 +1,106 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {TrackState} from '../../common/state';
+import {checkerboardExcept} from '../../frontend/checkerboard';
+import {Flamegraph} from '../../frontend/flamegraph';
+import {globals} from '../../frontend/globals';
+import {Track} from '../../frontend/track';
+import {trackRegistry} from '../../frontend/track_registry';
+
+import {
+  Config,
+  Data,
+  HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND,
+  HeapProfileFlamegraphKey
+} from './common';
+
+const MARGIN = 10;
+
+export class HeapProfileFlamegraphTrack extends Track<Config, Data> {
+  static readonly kind = HEAP_PROFILE_FLAMEGRAPH_TRACK_KIND;
+  private flamegraph: Flamegraph;
+
+  static create(trackState: TrackState): HeapProfileFlamegraphTrack {
+    return new HeapProfileFlamegraphTrack(trackState);
+  }
+
+  constructor(trackState: TrackState) {
+    super(trackState);
+    this.flamegraph = new Flamegraph(new Array());
+  }
+
+  data() {
+    return globals.trackDataStore.get(HeapProfileFlamegraphKey) as Data;
+  }
+
+  private changeFlamegraphData() {
+    const data = this.data();
+    if (data === undefined) {
+      this.flamegraph.updateDataIfChanged(new Array());
+    } else {
+      this.flamegraph.updateDataIfChanged(data.flamegraph);
+    }
+  }
+
+  getHeight(): number {
+    const data = this.data();
+    if (data === undefined) {
+      return 0;
+    }
+    this.changeFlamegraphData();
+    const height = this.flamegraph.getHeight();
+    return Math.max(height + MARGIN, super.getHeight());
+  }
+
+  getWidth(): number {
+    const {visibleWindowTime, timeScale} = globals.frontendLocalState;
+    const startPx = Math.floor(timeScale.timeToPx(visibleWindowTime.start));
+    const endPx = Math.ceil(timeScale.timeToPx(visibleWindowTime.end));
+    return endPx - startPx;
+  }
+
+  renderCanvas(ctx: CanvasRenderingContext2D) {
+    const data = this.data();
+    if (data !== undefined && data.start === -1) {
+      const {visibleWindowTime, timeScale} = globals.frontendLocalState;
+      checkerboardExcept(
+          ctx,
+          this.getHeight(),
+          timeScale.timeToPx(visibleWindowTime.start),
+          timeScale.timeToPx(visibleWindowTime.end),
+          timeScale.timeToPx(data.start),
+          timeScale.timeToPx(data.end));
+      return;
+    }
+    this.changeFlamegraphData();
+    this.flamegraph.draw(ctx, this.getWidth(), this.getHeight());
+  }
+
+  onMouseClick({x, y}: {x: number, y: number}): boolean {
+    this.flamegraph.onMouseClick({x, y});
+    return true;
+  }
+
+  onMouseMove({x, y}: {x: number, y: number}): boolean {
+    this.flamegraph.onMouseMove({x, y});
+    return true;
+  }
+
+  onMouseOut() {
+    this.flamegraph.onMouseOut();
+  }
+}
+
+trackRegistry.register(HeapProfileFlamegraphTrack);
diff --git a/ui/src/tracks/process_summary/controller.ts b/ui/src/tracks/process_summary/controller.ts
index a7a73aa..65835c1 100644
--- a/ui/src/tracks/process_summary/controller.ts
+++ b/ui/src/tracks/process_summary/controller.ts
@@ -64,7 +64,8 @@
     }
 
     // |resolution| is in s/px we want # ns for 10px window:
-    const bucketSizeNs = Math.round(resolution * 10 * 1e9);
+    // Max value with 1 so we don't end up with resolution 0.
+    const bucketSizeNs = Math.max(1, Math.round(resolution * 10 * 1e9));
     const windowStartNs = Math.floor(startNs / bucketSizeNs) * bucketSizeNs;
     const windowDurNs = Math.max(1, endNs - windowStartNs);