Merge "Revert "Add statsd logging to perfetto_cmd""
diff --git a/Android.bp b/Android.bp
index 514776e..c1be406 100644
--- a/Android.bp
+++ b/Android.bp
@@ -27,7 +27,6 @@
     "src/trace_processor/metrics/android/android_mem_unagg.sql",
     "src/trace_processor/metrics/android/android_package_list.sql",
     "src/trace_processor/metrics/android/android_powrails.sql",
-    "src/trace_processor/metrics/android/android_process_growth.sql",
     "src/trace_processor/metrics/android/android_startup.sql",
     "src/trace_processor/metrics/android/android_startup_cpu.sql",
     "src/trace_processor/metrics/android/android_startup_launches.sql",
@@ -36,6 +35,7 @@
     "src/trace_processor/metrics/android/java_heap_stats.sql",
     "src/trace_processor/metrics/android/mem_stats_priority_breakdown.sql",
     "src/trace_processor/metrics/android/process_mem.sql",
+    "src/trace_processor/metrics/android/process_metadata.sql",
     "src/trace_processor/metrics/android/process_unagg_mem_view.sql",
     "src/trace_processor/metrics/android/span_view_stats.sql",
     "src/trace_processor/metrics/android/unsymbolized_frames.sql",
@@ -95,14 +95,14 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_zero_gen",
     ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
     ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
     ":perfetto_protos_perfetto_trace_gpu_zero_gen",
     ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
-    ":perfetto_protos_perfetto_trace_minimal_lite_gen",
     ":perfetto_protos_perfetto_trace_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
@@ -111,7 +111,6 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
     ":perfetto_src_ipc_ipc",
@@ -168,14 +167,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -184,7 +183,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   defaults: [
     "perfetto_defaults",
@@ -304,14 +302,14 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_zero_gen",
     ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
     ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
     ":perfetto_protos_perfetto_trace_gpu_zero_gen",
     ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
-    ":perfetto_protos_perfetto_trace_minimal_lite_gen",
     ":perfetto_protos_perfetto_trace_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
@@ -320,7 +318,6 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
     ":perfetto_src_base_base",
@@ -386,14 +383,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -402,7 +399,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   defaults: [
     "perfetto_defaults",
@@ -492,14 +488,14 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_zero_gen",
     ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
     ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
     ":perfetto_protos_perfetto_trace_gpu_zero_gen",
     ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
-    ":perfetto_protos_perfetto_trace_minimal_lite_gen",
     ":perfetto_protos_perfetto_trace_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
@@ -508,7 +504,6 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
     ":perfetto_src_ipc_ipc",
@@ -558,14 +553,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -574,7 +569,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   export_generated_headers: [
     "perfetto_protos_perfetto_common_cpp_gen_headers",
@@ -608,14 +602,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -624,7 +618,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   defaults: [
     "perfetto_defaults",
@@ -679,14 +672,14 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_zero_gen",
     ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
     ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
     ":perfetto_protos_perfetto_trace_gpu_zero_gen",
     ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
-    ":perfetto_protos_perfetto_trace_minimal_lite_gen",
     ":perfetto_protos_perfetto_trace_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
@@ -695,7 +688,6 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
     ":perfetto_src_base_base",
@@ -747,14 +739,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -763,7 +755,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
   defaults: [
@@ -932,7 +923,8 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_lite_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_lite_gen",
@@ -961,7 +953,6 @@
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_lite_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
     ":perfetto_src_base_base",
@@ -1044,7 +1035,8 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_lite_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_lite_gen_headers",
@@ -1073,7 +1065,6 @@
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_lite_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
   ],
   defaults: [
     "perfetto_defaults",
@@ -2356,33 +2347,71 @@
   ],
 }
 
-// GN: //protos/perfetto/ipc:wire_protocol
+// GN: //protos/perfetto/ipc:wire_protocol_cpp
 genrule {
-  name: "perfetto_protos_perfetto_ipc_wire_protocol_gen",
+  name: "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
   srcs: [
     "protos/perfetto/ipc/wire_protocol.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 $(in)",
+  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/ipc/wire_protocol.pb.cc",
+    "external/perfetto/protos/perfetto/ipc/wire_protocol.gen.cc",
   ],
 }
 
-// GN: //protos/perfetto/ipc:wire_protocol
+// GN: //protos/perfetto/ipc:wire_protocol_cpp
 genrule {
-  name: "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+  name: "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
   srcs: [
     "protos/perfetto/ipc/wire_protocol.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 $(in)",
+  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/ipc/wire_protocol.pb.h",
+    "external/perfetto/protos/perfetto/ipc/wire_protocol.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
+// GN: //protos/perfetto/ipc:wire_protocol_zero
+genrule {
+  name: "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
+  srcs: [
+    "protos/perfetto/ipc/wire_protocol.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "protozero_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/ipc/wire_protocol.pbzero.cc",
+  ],
+}
+
+// GN: //protos/perfetto/ipc:wire_protocol_zero
+genrule {
+  name: "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
+  srcs: [
+    "protos/perfetto/ipc/wire_protocol.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "protozero_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/ipc/wire_protocol.pbzero.h",
   ],
   export_include_dirs: [
     ".",
@@ -2404,7 +2433,7 @@
     "protos/perfetto/metrics/android/mem_unagg_metric.proto",
     "protos/perfetto/metrics/android/package_list.proto",
     "protos/perfetto/metrics/android/powrails_metric.proto",
-    "protos/perfetto/metrics/android/process_growth.proto",
+    "protos/perfetto/metrics/android/process_metadata.proto",
     "protos/perfetto/metrics/android/startup_metric.proto",
     "protos/perfetto/metrics/android/unsymbolized_frames.proto",
   ],
@@ -2424,7 +2453,7 @@
     "external/perfetto/protos/perfetto/metrics/android/mem_unagg_metric.pbzero.cc",
     "external/perfetto/protos/perfetto/metrics/android/package_list.pbzero.cc",
     "external/perfetto/protos/perfetto/metrics/android/powrails_metric.pbzero.cc",
-    "external/perfetto/protos/perfetto/metrics/android/process_growth.pbzero.cc",
+    "external/perfetto/protos/perfetto/metrics/android/process_metadata.pbzero.cc",
     "external/perfetto/protos/perfetto/metrics/android/startup_metric.pbzero.cc",
     "external/perfetto/protos/perfetto/metrics/android/unsymbolized_frames.pbzero.cc",
   ],
@@ -2444,7 +2473,7 @@
     "protos/perfetto/metrics/android/mem_unagg_metric.proto",
     "protos/perfetto/metrics/android/package_list.proto",
     "protos/perfetto/metrics/android/powrails_metric.proto",
-    "protos/perfetto/metrics/android/process_growth.proto",
+    "protos/perfetto/metrics/android/process_metadata.proto",
     "protos/perfetto/metrics/android/startup_metric.proto",
     "protos/perfetto/metrics/android/unsymbolized_frames.proto",
   ],
@@ -2464,7 +2493,7 @@
     "external/perfetto/protos/perfetto/metrics/android/mem_unagg_metric.pbzero.h",
     "external/perfetto/protos/perfetto/metrics/android/package_list.pbzero.h",
     "external/perfetto/protos/perfetto/metrics/android/powrails_metric.pbzero.h",
-    "external/perfetto/protos/perfetto/metrics/android/process_growth.pbzero.h",
+    "external/perfetto/protos/perfetto/metrics/android/process_metadata.pbzero.h",
     "external/perfetto/protos/perfetto/metrics/android/startup_metric.pbzero.h",
     "external/perfetto/protos/perfetto/metrics/android/unsymbolized_frames.pbzero.h",
   ],
@@ -3966,40 +3995,6 @@
   ],
 }
 
-// GN: //protos/perfetto/trace:trusted_lite
-genrule {
-  name: "perfetto_protos_perfetto_trace_trusted_lite_gen",
-  srcs: [
-    "protos/perfetto/trace/trusted_packet.proto",
-  ],
-  tools: [
-    "aprotoc",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/trace/trusted_packet.pb.cc",
-  ],
-}
-
-// GN: //protos/perfetto/trace:trusted_lite
-genrule {
-  name: "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
-  srcs: [
-    "protos/perfetto/trace/trusted_packet.proto",
-  ],
-  tools: [
-    "aprotoc",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/ --proto_path=external/perfetto $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/trace/trusted_packet.pb.h",
-  ],
-  export_include_dirs: [
-    ".",
-    "protos",
-  ],
-}
-
 // GN: //protos/third_party/pprof:lite
 genrule {
   name: "perfetto_protos_third_party_pprof_lite_gen",
@@ -4398,6 +4393,7 @@
 filegroup {
   name: "perfetto_src_protozero_protozero",
   srcs: [
+    "src/protozero/field.cc",
     "src/protozero/message.cc",
     "src/protozero/message_handle.cc",
     "src/protozero/packed_repeated_fields.cc",
@@ -4405,6 +4401,55 @@
     "src/protozero/scattered_heap_buffer.cc",
     "src/protozero/scattered_stream_null_delegate.cc",
     "src/protozero/scattered_stream_writer.cc",
+    "src/protozero/static_buffer.cc",
+  ],
+}
+
+// GN: //src/protozero:testing_messages_cpp
+genrule {
+  name: "perfetto_src_protozero_testing_messages_cpp_gen",
+  srcs: [
+    "src/protozero/test/example_proto/library.proto",
+    "src/protozero/test/example_proto/library_internals/galaxies.proto",
+    "src/protozero/test/example_proto/test_messages.proto",
+    "src/protozero/test/example_proto/upper_import.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/src/protozero/test/example_proto/library.gen.cc",
+    "external/perfetto/src/protozero/test/example_proto/library_internals/galaxies.gen.cc",
+    "external/perfetto/src/protozero/test/example_proto/test_messages.gen.cc",
+    "external/perfetto/src/protozero/test/example_proto/upper_import.gen.cc",
+  ],
+}
+
+// GN: //src/protozero:testing_messages_cpp
+genrule {
+  name: "perfetto_src_protozero_testing_messages_cpp_gen_headers",
+  srcs: [
+    "src/protozero/test/example_proto/library.proto",
+    "src/protozero/test/example_proto/library_internals/galaxies.proto",
+    "src/protozero/test/example_proto/test_messages.proto",
+    "src/protozero/test/example_proto/upper_import.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/src/protozero/test/example_proto/library.gen.h",
+    "external/perfetto/src/protozero/test/example_proto/library_internals/galaxies.gen.h",
+    "external/perfetto/src/protozero/test/example_proto/test_messages.gen.h",
+    "external/perfetto/src/protozero/test/example_proto/upper_import.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
   ],
 }
 
@@ -4512,6 +4557,7 @@
     "src/protozero/proto_decoder_unittest.cc",
     "src/protozero/proto_utils_unittest.cc",
     "src/protozero/scattered_stream_writer_unittest.cc",
+    "src/protozero/test/cppgen_conformance_unittest.cc",
     "src/protozero/test/fake_scattered_buffer.cc",
     "src/protozero/test/protozero_conformance_unittest.cc",
   ],
@@ -4682,6 +4728,7 @@
   name: "perfetto_src_trace_processor_unittests",
   srcs: [
     "src/trace_processor/args_table_unittest.cc",
+    "src/trace_processor/basic_types_unittest.cc",
     "src/trace_processor/clock_tracker_unittest.cc",
     "src/trace_processor/event_tracker_unittest.cc",
     "src/trace_processor/filtered_row_index_unittest.cc",
@@ -5366,7 +5413,8 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_metrics_android_zero_gen",
     ":perfetto_protos_perfetto_metrics_zero_gen",
     ":perfetto_protos_perfetto_trace_android_lite_gen",
@@ -5398,7 +5446,6 @@
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_lite_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
     ":perfetto_src_base_base",
@@ -5421,6 +5468,7 @@
     ":perfetto_src_profiling_memory_unittests",
     ":perfetto_src_profiling_memory_wire_protocol",
     ":perfetto_src_protozero_protozero",
+    ":perfetto_src_protozero_testing_messages_cpp_gen",
     ":perfetto_src_protozero_testing_messages_lite_gen",
     ":perfetto_src_protozero_testing_messages_zero_gen",
     ":perfetto_src_protozero_unittests",
@@ -5511,7 +5559,8 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_metrics_android_zero_gen_headers",
     "perfetto_protos_perfetto_metrics_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_lite_gen_headers",
@@ -5543,9 +5592,9 @@
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_lite_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
     "perfetto_src_ipc_test_messages_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
+    "perfetto_src_protozero_testing_messages_cpp_gen_headers",
     "perfetto_src_protozero_testing_messages_lite_gen_headers",
     "perfetto_src_protozero_testing_messages_zero_gen_headers",
     "perfetto_src_traced_probes_ftrace_test_messages_lite_gen_headers",
@@ -5933,14 +5982,14 @@
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
     ":perfetto_protos_perfetto_ipc_ipc_gen",
-    ":perfetto_protos_perfetto_ipc_wire_protocol_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+    ":perfetto_protos_perfetto_ipc_wire_protocol_zero_gen",
     ":perfetto_protos_perfetto_trace_android_zero_gen",
     ":perfetto_protos_perfetto_trace_chrome_zero_gen",
     ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
     ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
     ":perfetto_protos_perfetto_trace_gpu_zero_gen",
     ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
-    ":perfetto_protos_perfetto_trace_minimal_lite_gen",
     ":perfetto_protos_perfetto_trace_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
     ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
@@ -5949,7 +5998,6 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
-    ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
     ":perfetto_src_ipc_ipc",
@@ -5998,14 +6046,14 @@
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
     "perfetto_protos_perfetto_ipc_ipc_gen_headers",
-    "perfetto_protos_perfetto_ipc_wire_protocol_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+    "perfetto_protos_perfetto_ipc_wire_protocol_zero_gen_headers",
     "perfetto_protos_perfetto_trace_android_zero_gen_headers",
     "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
     "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
     "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
     "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_minimal_lite_gen_headers",
     "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
     "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
@@ -6014,7 +6062,6 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
-    "perfetto_protos_perfetto_trace_trusted_lite_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
   defaults: [
diff --git a/BUILD b/BUILD
index 57831e6..9764754 100644
--- a/BUILD
+++ b/BUILD
@@ -66,7 +66,8 @@
         ":include_perfetto_ext_ipc_ipc",
     ],
     deps = [
-        ":protos_perfetto_ipc_wire_protocol",
+        ":protos_perfetto_ipc_wire_protocol_cpp",
+        ":protos_perfetto_ipc_wire_protocol_zero",
     ] + PERFETTO_CONFIG.deps.protobuf_lite,
 )
 
@@ -182,14 +183,14 @@
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_zero",
         ":protos_perfetto_ipc_ipc",
-        ":protos_perfetto_ipc_wire_protocol",
+        ":protos_perfetto_ipc_wire_protocol_cpp",
+        ":protos_perfetto_ipc_wire_protocol_zero",
         ":protos_perfetto_trace_android_zero",
         ":protos_perfetto_trace_chrome_zero",
         ":protos_perfetto_trace_filesystem_zero",
         ":protos_perfetto_trace_ftrace_zero",
         ":protos_perfetto_trace_gpu_zero",
         ":protos_perfetto_trace_interned_data_zero",
-        ":protos_perfetto_trace_minimal_lite",
         ":protos_perfetto_trace_minimal_zero",
         ":protos_perfetto_trace_non_minimal_zero",
         ":protos_perfetto_trace_perfetto_zero",
@@ -198,7 +199,6 @@
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
         ":protos_perfetto_trace_track_event_zero",
-        ":protos_perfetto_trace_trusted_lite",
     ] + PERFETTO_CONFIG.deps.protobuf_lite,
 )
 
@@ -354,6 +354,7 @@
         "include/perfetto/protozero/scattered_heap_buffer.h",
         "include/perfetto/protozero/scattered_stream_null_delegate.h",
         "include/perfetto/protozero/scattered_stream_writer.h",
+        "include/perfetto/protozero/static_buffer.h",
     ],
 )
 
@@ -528,6 +529,7 @@
 filegroup(
     name = "src_protozero_protozero",
     srcs = [
+        "src/protozero/field.cc",
         "src/protozero/message.cc",
         "src/protozero/message_handle.cc",
         "src/protozero/packed_repeated_fields.cc",
@@ -535,6 +537,7 @@
         "src/protozero/scattered_heap_buffer.cc",
         "src/protozero/scattered_stream_null_delegate.cc",
         "src/protozero/scattered_stream_writer.cc",
+        "src/protozero/static_buffer.cc",
     ],
 )
 
@@ -569,7 +572,6 @@
         "src/trace_processor/metrics/android/android_mem_unagg.sql",
         "src/trace_processor/metrics/android/android_package_list.sql",
         "src/trace_processor/metrics/android/android_powrails.sql",
-        "src/trace_processor/metrics/android/android_process_growth.sql",
         "src/trace_processor/metrics/android/android_startup.sql",
         "src/trace_processor/metrics/android/android_startup_cpu.sql",
         "src/trace_processor/metrics/android/android_startup_launches.sql",
@@ -578,6 +580,7 @@
         "src/trace_processor/metrics/android/java_heap_stats.sql",
         "src/trace_processor/metrics/android/mem_stats_priority_breakdown.sql",
         "src/trace_processor/metrics/android/process_mem.sql",
+        "src/trace_processor/metrics/android/process_metadata.sql",
         "src/trace_processor/metrics/android/process_unagg_mem_view.sql",
         "src/trace_processor/metrics/android/span_view_stats.sql",
         "src/trace_processor/metrics/android/unsymbolized_frames.sql",
@@ -1156,7 +1159,7 @@
     name = "protos_perfetto_common_cpp",
     deps = [
         ":protos_perfetto_common_protos",
-        ":protos_perfetto_common_lite",
+        ":protos_perfetto_common_zero",
     ],
 )
 
@@ -1198,8 +1201,8 @@
     name = "protos_perfetto_config_android_cpp",
     deps = [
         ":protos_perfetto_config_android_protos",
-        ":protos_perfetto_common_lite",
-        ":protos_perfetto_config_android_lite",
+        ":protos_perfetto_config_android_zero",
+        ":protos_perfetto_common_zero",
         ":protos_perfetto_common_cpp",
     ],
 )
@@ -1237,23 +1240,23 @@
     name = "protos_perfetto_config_cpp",
     deps = [
         ":protos_perfetto_config_protos",
-        ":protos_perfetto_config_inode_file_cpp",
+        ":protos_perfetto_config_gpu_zero",
+        ":protos_perfetto_config_profiling_zero",
         ":protos_perfetto_config_android_cpp",
-        ":protos_perfetto_config_lite",
-        ":protos_perfetto_config_android_lite",
+        ":protos_perfetto_config_sys_stats_zero",
         ":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_zero",
+        ":protos_perfetto_config_ftrace_zero",
         ":protos_perfetto_config_power_cpp",
-        ":protos_perfetto_config_process_stats_lite",
-        ":protos_perfetto_config_power_lite",
+        ":protos_perfetto_config_inode_file_cpp",
+        ":protos_perfetto_config_zero",
         ":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_inode_file_zero",
+        ":protos_perfetto_config_android_zero",
+        ":protos_perfetto_config_process_stats_zero",
+        ":protos_perfetto_common_zero",
         ":protos_perfetto_config_ftrace_cpp",
         ":protos_perfetto_config_sys_stats_cpp",
     ],
@@ -1264,7 +1267,7 @@
     name = "protos_perfetto_config_ftrace_cpp",
     deps = [
         ":protos_perfetto_config_ftrace_protos",
-        ":protos_perfetto_config_ftrace_lite",
+        ":protos_perfetto_config_ftrace_zero",
     ],
 )
 
@@ -1297,7 +1300,7 @@
     name = "protos_perfetto_config_gpu_cpp",
     deps = [
         ":protos_perfetto_config_gpu_protos",
-        ":protos_perfetto_config_gpu_lite",
+        ":protos_perfetto_config_gpu_zero",
     ],
 )
 
@@ -1330,7 +1333,7 @@
     name = "protos_perfetto_config_inode_file_cpp",
     deps = [
         ":protos_perfetto_config_inode_file_protos",
-        ":protos_perfetto_config_inode_file_lite",
+        ":protos_perfetto_config_inode_file_zero",
     ],
 )
 
@@ -1390,7 +1393,7 @@
     name = "protos_perfetto_config_power_cpp",
     deps = [
         ":protos_perfetto_config_power_protos",
-        ":protos_perfetto_config_power_lite",
+        ":protos_perfetto_config_power_zero",
     ],
 )
 
@@ -1423,7 +1426,7 @@
     name = "protos_perfetto_config_process_stats_cpp",
     deps = [
         ":protos_perfetto_config_process_stats_protos",
-        ":protos_perfetto_config_process_stats_lite",
+        ":protos_perfetto_config_process_stats_zero",
     ],
 )
 
@@ -1456,7 +1459,7 @@
     name = "protos_perfetto_config_profiling_cpp",
     deps = [
         ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_profiling_lite",
+        ":protos_perfetto_config_profiling_zero",
     ],
 )
 
@@ -1512,8 +1515,8 @@
     name = "protos_perfetto_config_sys_stats_cpp",
     deps = [
         ":protos_perfetto_config_sys_stats_protos",
-        ":protos_perfetto_common_lite",
-        ":protos_perfetto_config_sys_stats_lite",
+        ":protos_perfetto_config_sys_stats_zero",
+        ":protos_perfetto_common_zero",
         ":protos_perfetto_common_cpp",
     ],
 )
@@ -1580,18 +1583,20 @@
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_protos",
         ":protos_perfetto_ipc_wire_protocol_protos",
-    ],
-)
-
-# GN target: //protos/perfetto/ipc:wire_protocol
-perfetto_cc_proto_library(
-    name = "protos_perfetto_ipc_wire_protocol",
-    deps = [
         ":protos_perfetto_ipc_wire_protocol_protos",
     ],
 )
 
-# GN target: //protos/perfetto/ipc:wire_protocol
+# GN target: //protos/perfetto/ipc:wire_protocol_cpp
+perfetto_cc_protocpp_library(
+    name = "protos_perfetto_ipc_wire_protocol_cpp",
+    deps = [
+        ":protos_perfetto_ipc_wire_protocol_protos",
+        ":protos_perfetto_ipc_wire_protocol_zero",
+    ],
+)
+
+# GN target: //protos/perfetto/ipc:wire_protocol_zero
 perfetto_proto_library(
     name = "protos_perfetto_ipc_wire_protocol_protos",
     srcs = [
@@ -1599,6 +1604,14 @@
     ],
 )
 
+# GN target: //protos/perfetto/ipc:wire_protocol_zero
+perfetto_cc_protozero_library(
+    name = "protos_perfetto_ipc_wire_protocol_zero",
+    deps = [
+        ":protos_perfetto_ipc_wire_protocol_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/metrics/android:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_metrics_android_lite",
@@ -1621,7 +1634,7 @@
         "protos/perfetto/metrics/android/mem_unagg_metric.proto",
         "protos/perfetto/metrics/android/package_list.proto",
         "protos/perfetto/metrics/android/powrails_metric.proto",
-        "protos/perfetto/metrics/android/process_growth.proto",
+        "protos/perfetto/metrics/android/process_metadata.proto",
         "protos/perfetto/metrics/android/startup_metric.proto",
         "protos/perfetto/metrics/android/unsymbolized_frames.proto",
     ],
@@ -2154,35 +2167,6 @@
     ],
 )
 
-# GN target: //protos/perfetto/trace:trusted_lite
-perfetto_cc_proto_library(
-    name = "protos_perfetto_trace_trusted_lite",
-    deps = [
-        ":protos_perfetto_trace_trusted_protos",
-    ],
-)
-
-# GN target: //protos/perfetto/trace:trusted_lite
-perfetto_proto_library(
-    name = "protos_perfetto_trace_trusted_protos",
-    srcs = [
-        "protos/perfetto/trace/trusted_packet.proto",
-    ],
-    deps = [
-        ":protos_perfetto_common_protos",
-        ":protos_perfetto_config_android_protos",
-        ":protos_perfetto_config_ftrace_protos",
-        ":protos_perfetto_config_gpu_protos",
-        ":protos_perfetto_config_inode_file_protos",
-        ":protos_perfetto_config_power_protos",
-        ":protos_perfetto_config_process_stats_protos",
-        ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_protos",
-        ":protos_perfetto_config_sys_stats_protos",
-        ":protos_perfetto_trace_minimal_protos",
-    ],
-)
-
 # GN target: //protos/third_party/pprof:lite
 perfetto_cc_proto_library(
     name = "protos_third_party_pprof_lite",
@@ -2279,14 +2263,14 @@
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_zero",
         ":protos_perfetto_ipc_ipc",
-        ":protos_perfetto_ipc_wire_protocol",
+        ":protos_perfetto_ipc_wire_protocol_cpp",
+        ":protos_perfetto_ipc_wire_protocol_zero",
         ":protos_perfetto_trace_android_zero",
         ":protos_perfetto_trace_chrome_zero",
         ":protos_perfetto_trace_filesystem_zero",
         ":protos_perfetto_trace_ftrace_zero",
         ":protos_perfetto_trace_gpu_zero",
         ":protos_perfetto_trace_interned_data_zero",
-        ":protos_perfetto_trace_minimal_lite",
         ":protos_perfetto_trace_minimal_zero",
         ":protos_perfetto_trace_non_minimal_zero",
         ":protos_perfetto_trace_perfetto_zero",
@@ -2295,7 +2279,6 @@
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
         ":protos_perfetto_trace_track_event_zero",
-        ":protos_perfetto_trace_trusted_lite",
     ] + PERFETTO_CONFIG.deps.protobuf_lite,
 )
 
@@ -2360,14 +2343,14 @@
                ":protos_perfetto_config_sys_stats_zero",
                ":protos_perfetto_config_zero",
                ":protos_perfetto_ipc_ipc",
-               ":protos_perfetto_ipc_wire_protocol",
+               ":protos_perfetto_ipc_wire_protocol_cpp",
+               ":protos_perfetto_ipc_wire_protocol_zero",
                ":protos_perfetto_trace_android_zero",
                ":protos_perfetto_trace_chrome_zero",
                ":protos_perfetto_trace_filesystem_zero",
                ":protos_perfetto_trace_ftrace_zero",
                ":protos_perfetto_trace_gpu_zero",
                ":protos_perfetto_trace_interned_data_zero",
-               ":protos_perfetto_trace_minimal_lite",
                ":protos_perfetto_trace_minimal_zero",
                ":protos_perfetto_trace_non_minimal_zero",
                ":protos_perfetto_trace_perfetto_zero",
@@ -2376,7 +2359,6 @@
                ":protos_perfetto_trace_ps_zero",
                ":protos_perfetto_trace_sys_stats_zero",
                ":protos_perfetto_trace_track_event_zero",
-               ":protos_perfetto_trace_trusted_lite",
                ":src_perfetto_cmd_protos",
            ] + PERFETTO_CONFIG.deps.protobuf_lite +
            PERFETTO_CONFIG.deps.zlib,
diff --git a/docs/security-model.md b/docs/security-model.md
index bff44a9..369e6cc 100644
--- a/docs/security-model.md
+++ b/docs/security-model.md
@@ -51,10 +51,9 @@
 untrusted-and-unprivileged and trusted-and-more-privileged entities).
 
 **Attestation of trace contents**  
-The tracing service guarantees that the `TracePacket` fields defined also in
-[trusted_packet.proto](/protos/perfetto/trace/trusted_packet.proto) cannot be
-spoofed by the Producer(s). Packets that try to define those fields are rejected
-(modulo the clock snapshots).  
+The tracing service guarantees that the `TracePacket` fields written by the
+Service cannot be spoofed by the Producer(s).  
+Packets that try to define those fields are rejected, modulo clock snapshots.  
 See [PacketStreamValidator](/src/tracing/core/packet_stream_validator.cc) and
 [its unit test](/src/tracing/core/packet_stream_validator_unittest.cc) for more
 details.  
diff --git a/docs/trace-format.md b/docs/trace-format.md
index ca5db49..ec6c3eb 100644
--- a/docs/trace-format.md
+++ b/docs/trace-format.md
@@ -9,9 +9,9 @@
 (see [trace_packet.proto](/protos/perfetto/trace/trace_packet.proto)).
 
 As a key part of the Perfetto design, the tracing service is agnostic of the
-content of TracePacket, modulo the few fields defined in
-[trusted_packet.proto](/protos/perfetto/trace/trusted_packet.proto) that are
-produced by the service itself.
+content of TracePacket, modulo few fields (e.g., `trusted_packed_*`,
+clock snapshots, copy of the original config) that are produced by the service
+itself.
 
 Each data source can extend the trace with their app-specific protobuf schema.
 *** aside
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index c7af114..3e96c4d 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -182,11 +182,11 @@
         forward_variables_from(invoker, vars_to_forward)
       }
     } else if (gen_type == "cpp") {
-      lite_target_name_ = string_replace(target_name, expansion_token, "lite")
+      zero_target_name_ = string_replace(target_name, expansion_token, "zero")
       protozero_cpp_library(target_name_) {
         proto_in_dir = proto_path
         proto_out_dir = proto_path
-        deps = deps_ + [ ":$lite_target_name_" ]
+        deps = deps_ + [ ":$zero_target_name_" ]
         forward_variables_from(invoker, vars_to_forward)
       }
     } else if (gen_type == "lite") {
diff --git a/gn/standalone/toolchain/BUILD.gn b/gn/standalone/toolchain/BUILD.gn
index 7394802..4f38ceb 100644
--- a/gn/standalone/toolchain/BUILD.gn
+++ b/gn/standalone/toolchain/BUILD.gn
@@ -179,7 +179,7 @@
         command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile"
       } else {
         rspfile_content = "{{inputs}}"
-        command = "$ar rcsD {{output}} @$rspfile"
+        command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile"
       }
       outputs = [
         "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index 0b2efbf..0f08b42 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -38,25 +38,6 @@
 #define PERFETTO_NO_INLINE
 #endif
 
-// TODO(lalitm): is_trivially_constructible is currently not available
-// in some environments we build in. Reenable when that environment supports
-// this.
-#if defined(__GLIBCXX__)
-#define PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(T) true
-#else
-#define PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(T) \
-  std::is_trivially_constructible<T>::value
-#endif
-
-// TODO(lalitm): is_trivially_copyable is currently not available
-// in some environments we build in. Reenable when that environment supports
-// this.
-#if defined(__GLIBCXX__)
-#define PERFETTO_IS_TRIVIALLY_COPYABLE(T) true
-#else
-#define PERFETTO_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
-#endif
-
 #if defined(__GNUC__) || defined(__clang__)
 #define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
diff --git a/include/perfetto/protozero/BUILD.gn b/include/perfetto/protozero/BUILD.gn
index 994ff60..7afe1b9 100644
--- a/include/perfetto/protozero/BUILD.gn
+++ b/include/perfetto/protozero/BUILD.gn
@@ -28,5 +28,6 @@
     "scattered_heap_buffer.h",
     "scattered_stream_null_delegate.h",
     "scattered_stream_writer.h",
+    "static_buffer.h",
   ]
 }
diff --git a/include/perfetto/protozero/field.h b/include/perfetto/protozero/field.h
index f76fe84..69b2a15 100644
--- a/include/perfetto/protozero/field.h
+++ b/include/perfetto/protozero/field.h
@@ -182,6 +182,10 @@
     *val = static_cast<T>(as_int32());
   }
 
+  // Serializes the field back into a proto-encoded byte stream and appends it
+  // to |dst|. |dst| is resized accordingly.
+  void SerializeAndAppendTo(std::string* dst);
+
  private:
   // Fields are deliberately not initialized to keep the class trivially
   // constructible. It makes a large perf difference for ProtoDecoder.
diff --git a/include/perfetto/protozero/message.h b/include/perfetto/protozero/message.h
index 213a436..c3fdfd6 100644
--- a/include/perfetto/protozero/message.h
+++ b/include/perfetto/protozero/message.h
@@ -171,6 +171,16 @@
 
   ScatteredStreamWriter* stream_writer_for_testing() { return stream_writer_; }
 
+  // Appends some raw bytes to the message. The use-case for this is preserving
+  // unknown fields in the decode -> re-encode path of xxx.gen.cc classes
+  // generated by the cppgen_plugin.cc.
+  // The caller needs to guarantee that the appended data is properly
+  // proto-encoded and each field has a proto preamble.
+  void AppendRawProtoBytes(const void* data, size_t size) {
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(data);
+    WriteToStream(src, src + size);
+  }
+
  private:
   Message(const Message&) = delete;
   Message& operator=(const Message&) = delete;
diff --git a/include/perfetto/protozero/proto_decoder.h b/include/perfetto/protozero/proto_decoder.h
index 5794cc9..b58e64e 100644
--- a/include/perfetto/protozero/proto_decoder.h
+++ b/include/perfetto/protozero/proto_decoder.h
@@ -332,7 +332,7 @@
     // implicit initializers on all the ~1000 entries. We need it to initialize
     // only on the first |max_field_id| fields, the remaining capacity doesn't
     // require initialization.
-    static_assert(PERFETTO_IS_TRIVIALLY_CONSTRUCTIBLE(Field) &&
+    static_assert(std::is_trivially_constructible<Field>::value &&
                       std::is_trivially_destructible<Field>::value &&
                       std::is_trivial<Field>::value,
                   "Field must be a trivial aggregate type");
diff --git a/include/perfetto/protozero/proto_utils.h b/include/perfetto/protozero/proto_utils.h
index 8a93951..d8f0592 100644
--- a/include/perfetto/protozero/proto_utils.h
+++ b/include/perfetto/protozero/proto_utils.h
@@ -225,20 +225,22 @@
 // buffer.
 inline const uint8_t* ParseVarInt(const uint8_t* start,
                                   const uint8_t* end,
-                                  uint64_t* value) {
+                                  uint64_t* out_value) {
   const uint8_t* pos = start;
-  uint64_t shift = 0;
-  *value = 0;
-  do {
-    if (PERFETTO_UNLIKELY(pos >= end)) {
-      *value = 0;
-      return start;
+  uint64_t value = 0;
+  for (uint32_t shift = 0; pos < end && shift < 64u; shift += 7) {
+    // Cache *pos into |cur_byte| to prevent that the compiler dereferences the
+    // pointer twice (here and in the if() below) due to char* aliasing rules.
+    uint8_t cur_byte = *pos++;
+    value |= static_cast<uint64_t>(cur_byte & 0x7f) << shift;
+    if ((cur_byte & 0x80) == 0) {
+      // In valid cases we get here.
+      *out_value = value;
+      return pos;
     }
-    PERFETTO_DCHECK(shift < 64ull);
-    *value |= static_cast<uint64_t>(*pos & 0x7f) << shift;
-    shift += 7;
-  } while (*pos++ & 0x80);
-  return pos;
+  }
+  *out_value = 0;
+  return start;
 }
 
 }  // namespace proto_utils
diff --git a/include/perfetto/protozero/static_buffer.h b/include/perfetto/protozero/static_buffer.h
new file mode 100644
index 0000000..6f5924f
--- /dev/null
+++ b/include/perfetto/protozero/static_buffer.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_
+#define INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "perfetto/base/export.h"
+#include "perfetto/protozero/scattered_stream_writer.h"
+
+namespace protozero {
+
+class Message;
+
+// A simple implementation of ScatteredStreamWriter::Delegate backed by a
+// fixed-size buffer. It doesn't support expansion. The caller needs to ensure
+// to never write more than the size of the buffer. Will CHECK() otherwise.
+class PERFETTO_EXPORT StaticBufferDelegate
+    : public ScatteredStreamWriter::Delegate {
+ public:
+  StaticBufferDelegate(uint8_t* buf, size_t len) : range_{buf, buf + len} {}
+  ~StaticBufferDelegate() override;
+
+  // ScatteredStreamWriter::Delegate implementation.
+  ContiguousMemoryRange GetNewBuffer() override;
+
+  ContiguousMemoryRange const range_;
+  bool get_new_buffer_called_once_ = false;
+};
+
+// Helper function to create protozero messages backed by a fixed-size buffer
+// in one line. You can write:
+//   protozero::Static<protozero::MyMessage> msg(buf.data(), buf.size());
+//   msg->set_stuff(...);
+//   size_t bytes_encoded = msg.Finalize();
+template <typename T /* protozero::Message */>
+class StaticBuffered {
+ public:
+  StaticBuffered(void* buf, size_t len)
+      : delegate_(reinterpret_cast<uint8_t*>(buf), len), writer_(&delegate_) {
+    msg_.Reset(&writer_);
+  }
+
+  // This can't be neither copied nor moved because Message hands out pointers
+  // to itself when creating submessages.
+  StaticBuffered(const StaticBuffered&) = delete;
+  StaticBuffered& operator=(const StaticBuffered&) = delete;
+  StaticBuffered(StaticBuffered&&) = delete;
+  StaticBuffered& operator=(StaticBuffered&&) = delete;
+
+  T* get() { return &msg_; }
+  T* operator->() { return &msg_; }
+
+  // The lack of a size() method is deliberate. It's to prevent that one
+  // accidentally calls size() before Finalize().
+
+  // Returns the number of encoded bytes (<= the size passed in the ctor).
+  size_t Finalize() {
+    msg_.Finalize();
+    return static_cast<size_t>(writer_.write_ptr() - delegate_.range_.begin);
+  }
+
+ private:
+  StaticBufferDelegate delegate_;
+  ScatteredStreamWriter writer_;
+  T msg_;
+};
+
+// Helper function to create stack-based protozero messages in one line.
+// You can write:
+//   protozero::StackBuffered<protozero::MyMessage, 16> msg;
+//   msg->set_stuff(...);
+//   size_t bytes_encoded = msg.Finalize();
+template <typename T /* protozero::Message */, size_t N>
+class StackBuffered : public StaticBuffered<T> {
+ public:
+  StackBuffered() : StaticBuffered<T>(&buf_[0], N) {}
+
+ private:
+  uint8_t buf_[N];  // Deliberately not initialized.
+};
+
+}  // namespace protozero
+
+#endif  // INCLUDE_PERFETTO_PROTOZERO_STATIC_BUFFER_H_
diff --git a/include/perfetto/trace_processor/basic_types.h b/include/perfetto/trace_processor/basic_types.h
index efac31c..ca540d2 100644
--- a/include/perfetto/trace_processor/basic_types.h
+++ b/include/perfetto/trace_processor/basic_types.h
@@ -57,6 +57,13 @@
     return value;
   }
 
+  static SqlValue Double(double v) {
+    SqlValue value;
+    value.double_value = v;
+    value.type = Type::kDouble;
+    return value;
+  }
+
   static SqlValue String(const char* v) {
     SqlValue value;
     value.string_value = v;
@@ -69,7 +76,7 @@
     return double_value;
   }
 
-  int Compare(const SqlValue& value) const {
+  int64_t Compare(const SqlValue& value) const {
     // TODO(lalitm): this is almost the same as what SQLite does with the
     // exception of comparisions between long and double - we choose (for
     // performance reasons) to omit comparisions between them.
@@ -80,10 +87,11 @@
       case Type::kNull:
         return 0;
       case Type::kLong:
-        return static_cast<int>(long_value - value.long_value);
+        return long_value - value.long_value;
       case Type::kDouble: {
-        double diff = double_value - value.double_value;
-        return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
+        return double_value < value.double_value
+                   ? -1
+                   : (double_value > value.double_value ? 1 : 0);
       }
       case Type::kString:
         return strcmp(string_value, value.string_value);
@@ -92,7 +100,7 @@
         int ret = memcmp(bytes_value, value.bytes_value, bytes);
         if (ret != 0)
           return ret;
-        return static_cast<int>(bytes_count - value.bytes_count);
+        return static_cast<int64_t>(bytes_count - value.bytes_count);
       }
     }
     PERFETTO_FATAL("For GCC");
diff --git a/protos/perfetto/ipc/BUILD.gn b/protos/perfetto/ipc/BUILD.gn
index 48f54a1..c65b9f4 100644
--- a/protos/perfetto/ipc/BUILD.gn
+++ b/protos/perfetto/ipc/BUILD.gn
@@ -30,8 +30,11 @@
   ]
 }
 
-perfetto_proto_library("wire_protocol") {
-  proto_generators = [ "lite" ]
+perfetto_proto_library("wire_protocol_@TYPE@") {
+  proto_generators = [
+    "zero",
+    "cpp",
+  ]
   sources = [
     "wire_protocol.proto",
   ]
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 41353b0..3f8571c 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -26,7 +26,7 @@
     "mem_unagg_metric.proto",
     "package_list.proto",
     "powrails_metric.proto",
-    "process_growth.proto",
+    "process_metadata.proto",
     "startup_metric.proto",
     "unsymbolized_frames.proto",
   ]
diff --git a/protos/perfetto/metrics/android/heap_profile_callsites.proto b/protos/perfetto/metrics/android/heap_profile_callsites.proto
index d19bba3..df1a516 100644
--- a/protos/perfetto/metrics/android/heap_profile_callsites.proto
+++ b/protos/perfetto/metrics/android/heap_profile_callsites.proto
@@ -18,6 +18,8 @@
 
 package perfetto.protos;
 
+import "protos/perfetto/metrics/android/process_metadata.proto";
+
 message HeapProfileCallsites {
   message Frame {
     optional string name = 1;
@@ -51,10 +53,12 @@
   }
 
   // Callsites per process instance.
-  // Next id: 6
+  // Next id: 7
   message InstanceStats {
     optional uint32 pid = 1;
+    // TODO(ilkos): Remove process_name in favour of the metadata.
     optional string process_name = 2;
+    optional AndroidProcessMetadata process = 6;
     repeated Callsite callsites = 3;
 
     // Bytes allocated via malloc but not freed.
diff --git a/protos/perfetto/metrics/android/java_heap_stats.proto b/protos/perfetto/metrics/android/java_heap_stats.proto
index a5e1513..e07190b 100644
--- a/protos/perfetto/metrics/android/java_heap_stats.proto
+++ b/protos/perfetto/metrics/android/java_heap_stats.proto
@@ -18,6 +18,8 @@
 
 package perfetto.protos;
 
+import "protos/perfetto/metrics/android/process_metadata.proto";
+
 message JavaHeapStats {
   message Sample {
     optional int64 ts = 1;
@@ -29,7 +31,7 @@
   // dump is enabled).
   message InstanceStats {
     optional uint32 upid = 1;
-    optional string process_name = 2;
+    optional AndroidProcessMetadata process = 2;
     repeated Sample samples = 3;
   }
 
diff --git a/protos/perfetto/metrics/android/process_growth.proto b/protos/perfetto/metrics/android/process_growth.proto
deleted file mode 100644
index 50fcec5..0000000
--- a/protos/perfetto/metrics/android/process_growth.proto
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-package perfetto.protos;
-
-message AndroidProcessGrowth {
-  // Next id: 7
-  message InstanceMetrics {
-    optional uint32 pid = 1;
-    optional string process_name = 2;
-
-    optional int64 anon_and_swap_start_value = 5;
-    optional int64 anon_and_swap_change_bytes = 3;
-
-    // Bytes allocated via malloc but not freed.
-    // Only applicable with a heap profile.
-    optional int64 malloc_memory_change_bytes = 4;
-    // Total bytes allocated via malloc. Only applicable with a heap profile.
-    optional int64 malloc_memory_total_allocated_bytes = 6;
-  }
-
-  // Process memory per process instance.
-  repeated InstanceMetrics instance_metrics = 1;
-}
diff --git a/protos/perfetto/metrics/android/process_metadata.proto b/protos/perfetto/metrics/android/process_metadata.proto
new file mode 100644
index 0000000..9c35812
--- /dev/null
+++ b/protos/perfetto/metrics/android/process_metadata.proto
@@ -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.
+ */
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+message AndroidProcessMetadata {
+  optional string name = 1;
+  optional int64 uid = 2;
+  optional string package_name = 3;
+  optional int64 apk_version_code = 4;
+  optional bool debuggable = 5;
+}
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index 508e830..6225559 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -23,7 +23,6 @@
 import "protos/perfetto/metrics/android/cpu_metric.proto";
 import "protos/perfetto/metrics/android/mem_metric.proto";
 import "protos/perfetto/metrics/android/mem_unagg_metric.proto";
-import "protos/perfetto/metrics/android/process_growth.proto";
 import "protos/perfetto/metrics/android/ion_metric.proto";
 import "protos/perfetto/metrics/android/lmk_metric.proto";
 import "protos/perfetto/metrics/android/powrails_metric.proto";
@@ -51,7 +50,7 @@
 //
 // Next id: 18
 message TraceMetrics {
-  reserved 4, 13, 14;
+  reserved 4, 10, 13, 14;
 
   // Battery counters metric on Android.
   optional AndroidBatteryMetric android_batt = 5;
@@ -71,9 +70,6 @@
   // Package list.
   optional AndroidPackageList android_package_list = 12;
 
-  // Per-process memory growth metrics.
-  optional AndroidProcessGrowth android_process_growth = 10;
-
   // ion buffer memory metrics.
   optional AndroidIonMetric android_ion = 9;
 
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index ca76396..bc312e0 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -39,9 +39,6 @@
   "system_info.proto",
 ]
 
-# Used only for packet_stream_validator.cc (in the service).
-proto_sources_trusted = [ "trusted_packet.proto" ]
-
 # Most targets should either depend on :zero (writers) / :lite (readers)
 # or ":minimal_zero" / :minimal_lite (mostly for chrome).
 
@@ -95,17 +92,6 @@
   sources = proto_sources_minimal
 }
 
-# Used by the traced service for packet sanitization.
-perfetto_proto_library("trusted_@TYPE@") {
-  proto_generators = [ "lite" ]
-  deps = [
-    ":minimal_@TYPE@",
-    "../common:@TYPE@",
-    "../config:@TYPE@",
-  ]
-  sources = proto_sources_trusted
-}
-
 # This target is not used in the tree and is built only to guarantee that the
 # autogenerated merged proto has a valid syntax.
 perfetto_proto_library("merged_trace") {
diff --git a/protos/perfetto/trace/clock_snapshot.proto b/protos/perfetto/trace/clock_snapshot.proto
index 12ce1b6..e3dff0f 100644
--- a/protos/perfetto/trace/clock_snapshot.proto
+++ b/protos/perfetto/trace/clock_snapshot.proto
@@ -45,22 +45,23 @@
     //             IDs and setting this ID to hash(full_clock_name) & ~127.
     optional uint32 clock_id = 1;
 
-    // Unit is ns unless specified otherwise by the resolution_* fields below.
+    // Absolute timestamp. Unit is ns unless specified otherwise by the
+    // unit_multiplier_ns field below.
     optional uint64 timestamp = 2;
 
-    // TODO(eseckler): the fields below and sequence-scoped clock IDs are not
-    // supported yet by the trace processor.
+    // When true each TracePacket's timestamp should be interpreted as a delta
+    // from the last TracePacket's timestamp (referencing this clock) emitted by
+    // the same packet_sequence_id. Should only be used for user-defined
+    // sequence-local clocks. The first packet timestamp after each
+    // ClockSnapshot that contains this clock is relative to the |timestamp| in
+    // the ClockSnapshot.
+    optional bool is_incremental = 3;
 
-    // When true the timestamp should be interpreted as a delta from the last
-    // TracePacket's timestamp emitted by the same packet_sequence_id.
-    // The first packet timestamp after a ClockSnapshot is relative to the last
-    // ClockSnapshot seen on the packet sequence.
-    // optional bool is_incremental = 3;
-
-    // Allows to specify a custom unit different than the default (ns)
-    // for this clock domain. A multiplier of 1000 means that a timestamp = 3
-    // should be interpreted as 3000 ns = 3 us.
-    // optional uint64 unit_multiplier_ns = 4;
+    // Allows to specify a custom unit different than the default (ns) for this
+    // clock domain. A multiplier of 1000 means that a timestamp = 3 should be
+    // interpreted as 3000 ns = 3 us. All snapshots for the same clock within a
+    // trace need to use the same unit.
+    optional uint64 unit_multiplier_ns = 4;
   }
   repeated Clock clocks = 1;
 }
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index d126980..abfe920 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -758,22 +758,23 @@
     //             IDs and setting this ID to hash(full_clock_name) & ~127.
     optional uint32 clock_id = 1;
 
-    // Unit is ns unless specified otherwise by the resolution_* fields below.
+    // Absolute timestamp. Unit is ns unless specified otherwise by the
+    // unit_multiplier_ns field below.
     optional uint64 timestamp = 2;
 
-    // TODO(eseckler): the fields below and sequence-scoped clock IDs are not
-    // supported yet by the trace processor.
+    // When true each TracePacket's timestamp should be interpreted as a delta
+    // from the last TracePacket's timestamp (referencing this clock) emitted by
+    // the same packet_sequence_id. Should only be used for user-defined
+    // sequence-local clocks. The first packet timestamp after each
+    // ClockSnapshot that contains this clock is relative to the |timestamp| in
+    // the ClockSnapshot.
+    optional bool is_incremental = 3;
 
-    // When true the timestamp should be interpreted as a delta from the last
-    // TracePacket's timestamp emitted by the same packet_sequence_id.
-    // The first packet timestamp after a ClockSnapshot is relative to the last
-    // ClockSnapshot seen on the packet sequence.
-    // optional bool is_incremental = 3;
-
-    // Allows to specify a custom unit different than the default (ns)
-    // for this clock domain. A multiplier of 1000 means that a timestamp = 3
-    // should be interpreted as 3000 ns = 3 us.
-    // optional uint64 unit_multiplier_ns = 4;
+    // Allows to specify a custom unit different than the default (ns) for this
+    // clock domain. A multiplier of 1000 means that a timestamp = 3 should be
+    // interpreted as 3000 ns = 3 us. All snapshots for the same clock within a
+    // trace need to use the same unit.
+    optional uint64 unit_multiplier_ns = 4;
   }
   repeated Clock clocks = 1;
 }
@@ -3030,6 +3031,23 @@
 
 // Begin of protos/perfetto/trace/profiling/heap_graph.proto
 
+message ObfuscatedMember {
+  optional string obfuscated_name = 1;
+  optional string deobfuscated_name = 2;
+}
+
+message ObfuscatedClass {
+  optional string obfuscated_name = 1;
+  optional string deobfuscated_name = 2;
+  repeated ObfuscatedMember obfuscated_members = 3;
+}
+
+message DeobfuscationMapping {
+  optional string package_name = 1;
+  optional int64 version_code = 2;
+  repeated ObfuscatedClass obfusucated_classes = 3;
+}
+
 message HeapGraphRoot {
   enum Type {
     ROOT_UNKNOWN = 0;
@@ -3049,7 +3067,7 @@
     ROOT_JNI_MONITOR = 14;
   };
   // Objects retained by this root.
-  repeated uint64 object_ids = 1;
+  repeated uint64 object_ids = 1 [packed = true];
 
   optional Type root_type = 2;
 }
@@ -3065,10 +3083,10 @@
 
   // Indices for InternedData.field_names for the name of the field referring
   // to the object.
-  repeated uint64 reference_field_id = 4;
+  repeated uint64 reference_field_id = 4 [packed = true];
 
   // Ids of the Object that is referred to.
-  repeated uint64 reference_object_id = 5;
+  repeated uint64 reference_object_id = 5 [packed = true];
 }
 
 message HeapGraph {
diff --git a/protos/perfetto/trace/profiling/heap_graph.proto b/protos/perfetto/trace/profiling/heap_graph.proto
index d29c292..5601b9b 100644
--- a/protos/perfetto/trace/profiling/heap_graph.proto
+++ b/protos/perfetto/trace/profiling/heap_graph.proto
@@ -24,6 +24,23 @@
 
 package perfetto.protos;
 
+message ObfuscatedMember {
+  optional string obfuscated_name = 1;
+  optional string deobfuscated_name = 2;
+}
+
+message ObfuscatedClass {
+  optional string obfuscated_name = 1;
+  optional string deobfuscated_name = 2;
+  repeated ObfuscatedMember obfuscated_members = 3;
+}
+
+message DeobfuscationMapping {
+  optional string package_name = 1;
+  optional int64 version_code = 2;
+  repeated ObfuscatedClass obfusucated_classes = 3;
+}
+
 message HeapGraphRoot {
   enum Type {
     ROOT_UNKNOWN = 0;
@@ -43,7 +60,7 @@
     ROOT_JNI_MONITOR = 14;
   };
   // Objects retained by this root.
-  repeated uint64 object_ids = 1;
+  repeated uint64 object_ids = 1 [packed = true];
 
   optional Type root_type = 2;
 }
@@ -59,10 +76,10 @@
 
   // Indices for InternedData.field_names for the name of the field referring
   // to the object.
-  repeated uint64 reference_field_id = 4;
+  repeated uint64 reference_field_id = 4 [packed = true];
 
   // Ids of the Object that is referred to.
-  repeated uint64 reference_object_id = 5;
+  repeated uint64 reference_object_id = 5 [packed = true];
 }
 
 message HeapGraph {
diff --git a/protos/perfetto/trace/trusted_packet.proto b/protos/perfetto/trace/trusted_packet.proto
deleted file mode 100644
index 8316994..0000000
--- a/protos/perfetto/trace/trusted_packet.proto
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.
- */
-
-// Use proto3 syntax as an optimization. The difference is that proto2 stores
-// unknown fields seen while decoding in an internal buffer (std::string) while
-// proto3 completely drops them. Since during validation we only need to check
-// for the presence of the trusted fields below, we can use proto3 as a way to
-// speed up this process.
-//
-// See https://developers.google.com/protocol-buffers/docs/proto3#unknowns and
-// https://android-review.googlesource.com/c/platform/external/perfetto/+/
-// 591673#17 for details.
-syntax = "proto3";
-option optimize_for = LITE_RUNTIME;
-
-import "protos/perfetto/common/trace_stats.proto";
-import "protos/perfetto/config/trace_config.proto";
-import "protos/perfetto/trace/clock_snapshot.proto";
-import "protos/perfetto/trace/system_info.proto";
-import "protos/perfetto/trace/trigger.proto";
-
-package perfetto.protos;
-
-// This proto contains trusted fields of TracePacket which may only be generated
-// by the service (as opposed to the untrusted producers). Note that the field
-// ids here must be kept in sync with TracePacket.
-// This protobuf serves two purposes:
-// 1. Security validation of packets (see packet_stream_validator.cc)
-// 2. Avoid bloating the service binary with symbols for all possible trace
-//    protos. The service doesn't really care about all the protos in the trace,
-//    is just passes them through.
-message TrustedPacket {
-  // User id of the producer which generated this packet.
-  // The oneof boilerplate here is required to tell the difference between
-  // uid == 0 and uid not set (the writer uses proto2).
-  oneof optional_trusted_uid { int32 trusted_uid = 3; };
-
-  oneof optional_trusted_packet_sequence_id {
-    uint32 trusted_packet_sequence_id = 10;
-  }
-
-  ClockSnapshot clock_snapshot = 6;
-  uint64 timestamp = 8;
-  TraceConfig trace_config = 33;
-  TraceStats trace_stats = 35;
-  bytes synchronization_marker = 36;
-  bool previous_packet_dropped = 42;
-  SystemInfo system_info = 45;
-  Trigger trigger = 46;
-}
diff --git a/src/ipc/BUILD.gn b/src/ipc/BUILD.gn
index ed0ecd2..bf2b1af 100644
--- a/src/ipc/BUILD.gn
+++ b/src/ipc/BUILD.gn
@@ -31,7 +31,7 @@
   deps = [
     "../../gn:default_deps",
     "../../gn:protobuf_lite",
-    "../../protos/perfetto/ipc:wire_protocol",
+    "../../protos/perfetto/ipc:wire_protocol_cpp",
     "../base",
   ]
   sources = [
@@ -54,7 +54,7 @@
   deps = [
     ":ipc",
     "../../gn:default_deps",
-    "../../protos/perfetto/ipc:wire_protocol",
+    "../../protos/perfetto/ipc:wire_protocol_cpp",
   ]
 }
 
@@ -65,7 +65,7 @@
     ":test_messages",
     "../../gn:default_deps",
     "../../gn:gtest_and_gmock",
-    "../../protos/perfetto/ipc:wire_protocol",
+    "../../protos/perfetto/ipc:wire_protocol_cpp",
     "../base",
     "../base:test_support",
   ]
diff --git a/src/ipc/buffered_frame_deserializer.cc b/src/ipc/buffered_frame_deserializer.cc
index dc107f7..9ef22eb 100644
--- a/src/ipc/buffered_frame_deserializer.cc
+++ b/src/ipc/buffered_frame_deserializer.cc
@@ -25,7 +25,7 @@
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/utils.h"
 
-#include "protos/perfetto/ipc/wire_protocol.pb.h"
+#include "protos/perfetto/ipc/wire_protocol.gen.h"
 
 namespace perfetto {
 namespace ipc {
@@ -166,23 +166,18 @@
   if (size == 0)
     return;
   std::unique_ptr<Frame> frame(new Frame);
-  if (frame->ParseFromArray(data, static_cast<int>(size)))
+  if (frame->ParseFromArray(data, size))
     decoded_frames_.push_back(std::move(frame));
 }
 
 // static
 std::string BufferedFrameDeserializer::Serialize(const Frame& frame) {
+  std::vector<uint8_t> payload = frame.SerializeAsArray();
+  const uint32_t payload_size = static_cast<uint32_t>(payload.size());
   std::string buf;
-  buf.reserve(1024);  // Just an educated guess to avoid trivial expansions.
-  buf.insert(0, kHeaderSize, 0);  // Reserve the space for the header.
-  frame.AppendToString(&buf);
-  const uint32_t payload_size = static_cast<uint32_t>(buf.size() - kHeaderSize);
-  PERFETTO_DCHECK(payload_size == static_cast<uint32_t>(frame.GetCachedSize()));
-  // Don't send messages larger than what the receiver can handle.
-  PERFETTO_DCHECK(kHeaderSize + payload_size <= kIPCBufferSize);
-  char header[kHeaderSize];
-  memcpy(header, base::AssumeLittleEndian(&payload_size), kHeaderSize);
-  buf.replace(0, kHeaderSize, header, kHeaderSize);
+  buf.resize(kHeaderSize + payload_size);
+  memcpy(&buf[0], base::AssumeLittleEndian(&payload_size), kHeaderSize);
+  memcpy(&buf[kHeaderSize], payload.data(), payload.size());
   return buf;
 }
 
diff --git a/src/ipc/buffered_frame_deserializer.h b/src/ipc/buffered_frame_deserializer.h
index 3aeee1f..92988e6 100644
--- a/src/ipc/buffered_frame_deserializer.h
+++ b/src/ipc/buffered_frame_deserializer.h
@@ -31,7 +31,7 @@
 namespace perfetto {
 namespace ipc {
 
-class Frame;  // Defined in the protobuf autogenerated wire_protocol.pb.h.
+class Frame;  // Defined in the protobuf autogenerated wire_protocol.gen.h.
 
 // Deserializes incoming frames, taking care of buffering and tokenization.
 // Used by both host and client to decode incoming frames.
diff --git a/src/ipc/buffered_frame_deserializer_unittest.cc b/src/ipc/buffered_frame_deserializer_unittest.cc
index 792365b..9ddf8d8 100644
--- a/src/ipc/buffered_frame_deserializer_unittest.cc
+++ b/src/ipc/buffered_frame_deserializer_unittest.cc
@@ -23,7 +23,7 @@
 #include "perfetto/ext/base/utils.h"
 #include "test/gtest_and_gmock.h"
 
-#include "protos/perfetto/ipc/wire_protocol.pb.h"
+#include "protos/perfetto/ipc/wire_protocol.gen.h"
 
 namespace perfetto {
 namespace ipc {
@@ -60,15 +60,16 @@
       padding_char = padding_char == 'z' ? '0' : padding_char + 1;
       padding[i] = padding_char;
     }
-    frame.add_data_for_testing(padding.data(), padding_size);
+    frame.add_data_for_testing(std::string(padding.data(), padding_size));
   }
-  PERFETTO_CHECK(frame.ByteSize() == static_cast<int>(payload_size));
+  PERFETTO_CHECK(frame.SerializeAsString().size() == payload_size);
   std::vector<char> encoded_frame;
   encoded_frame.resize(size);
   char* enc_buf = encoded_frame.data();
-  PERFETTO_CHECK(frame.SerializeToArray(enc_buf + kHeaderSize,
-                                        static_cast<int>(payload_size)));
+
+  std::string payload = frame.SerializeAsString();
   memcpy(enc_buf, base::AssumeLittleEndian(&payload_size), kHeaderSize);
+  memcpy(enc_buf + kHeaderSize, payload.data(), payload.size());
   PERFETTO_CHECK(encoded_frame.size() == size);
   return encoded_frame;
 }
@@ -108,8 +109,7 @@
     // Excactly one frame should be decoded, with no leftover buffer.
     auto decoded_frame = bfd.PopNextFrame();
     ASSERT_TRUE(decoded_frame);
-    ASSERT_EQ(static_cast<int32_t>(size - kHeaderSize),
-              decoded_frame->ByteSize());
+    ASSERT_EQ(size - kHeaderSize, decoded_frame->SerializeAsString().size());
     ASSERT_FALSE(bfd.PopNextFrame());
     ASSERT_EQ(0u, bfd.size());
   }
@@ -132,11 +132,11 @@
   method->set_id(0x424242);
   method->set_name("foo");
   std::vector<char> serialized_frame;
-  uint32_t payload_size = static_cast<uint32_t>(frame.ByteSize());
 
+  std::string payload = frame.SerializeAsString();
+  uint32_t payload_size = static_cast<uint32_t>(payload.size());
   serialized_frame.resize(kHeaderSize + payload_size);
-  ASSERT_TRUE(frame.SerializeToArray(serialized_frame.data() + kHeaderSize,
-                                     static_cast<int>(payload_size)));
+  memcpy(serialized_frame.data() + kHeaderSize, payload.data(), payload_size);
   memcpy(serialized_frame.data(), base::AssumeLittleEndian(&payload_size),
          kHeaderSize);
 
@@ -163,8 +163,8 @@
   // Validate the received frame2.
   std::unique_ptr<Frame> decoded_simple_frame = bfd.PopNextFrame();
   ASSERT_TRUE(decoded_simple_frame);
-  ASSERT_EQ(static_cast<int32_t>(simple_frame.size() - kHeaderSize),
-            decoded_simple_frame->ByteSize());
+  ASSERT_EQ(simple_frame.size() - kHeaderSize,
+            decoded_simple_frame->SerializeAsString().size());
 
   std::unique_ptr<Frame> decoded_frame = bfd.PopNextFrame();
   ASSERT_TRUE(decoded_frame);
@@ -238,8 +238,7 @@
     for (size_t expected_size : batch) {
       auto frame = bfd.PopNextFrame();
       ASSERT_TRUE(frame);
-      ASSERT_EQ(static_cast<int32_t>(expected_size - kHeaderSize),
-                frame->ByteSize());
+      ASSERT_EQ(expected_size - kHeaderSize, frame->SerializeAsString().size());
     }
     ASSERT_FALSE(bfd.PopNextFrame());
     ASSERT_EQ(0u, bfd.size());
@@ -301,8 +300,7 @@
       ASSERT_FALSE(decoded_frame);
     } else {
       ASSERT_TRUE(decoded_frame);
-      ASSERT_EQ(static_cast<int32_t>(size - kHeaderSize),
-                decoded_frame->ByteSize());
+      ASSERT_EQ(size - kHeaderSize, decoded_frame->SerializeAsString().size());
     }
     ASSERT_EQ(0u, bfd.size());
   }
diff --git a/src/ipc/client_impl.h b/src/ipc/client_impl.h
index 71c211f..35dea50 100644
--- a/src/ipc/client_impl.h
+++ b/src/ipc/client_impl.h
@@ -23,7 +23,7 @@
 #include "perfetto/ext/ipc/client.h"
 #include "src/ipc/buffered_frame_deserializer.h"
 
-#include "protos/perfetto/ipc/wire_protocol.pb.h"
+#include "protos/perfetto/ipc/wire_protocol.gen.h"
 
 #include <list>
 #include <map>
diff --git a/src/ipc/host_impl.cc b/src/ipc/host_impl.cc
index 1158fb8..7784305 100644
--- a/src/ipc/host_impl.cc
+++ b/src/ipc/host_impl.cc
@@ -26,7 +26,7 @@
 #include "perfetto/ext/ipc/service.h"
 #include "perfetto/ext/ipc/service_descriptor.h"
 
-#include "protos/perfetto/ipc/wire_protocol.pb.h"
+#include "protos/perfetto/ipc/wire_protocol.gen.h"
 
 // TODO(primiano): put limits on #connections/uid and req. queue (b/69093705).
 
diff --git a/src/ipc/host_impl_unittest.cc b/src/ipc/host_impl_unittest.cc
index 4e9216b..61a77dd 100644
--- a/src/ipc/host_impl_unittest.cc
+++ b/src/ipc/host_impl_unittest.cc
@@ -30,7 +30,7 @@
 #include "src/ipc/test/test_socket.h"
 #include "test/gtest_and_gmock.h"
 
-#include "protos/perfetto/ipc/wire_protocol.pb.h"
+#include "protos/perfetto/ipc/wire_protocol.gen.h"
 #include "src/ipc/test/client_unittest_messages.pb.h"
 
 namespace perfetto {
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index b2cc13a..23469d8 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -28,6 +28,7 @@
     "../../include/perfetto/ext/base",  # TODO(primiano): remove this
   ]
   sources = [
+    "field.cc",
     "message.cc",
     "message_handle.cc",
     "packed_repeated_fields.cc",
@@ -35,6 +36,7 @@
     "scattered_heap_buffer.cc",
     "scattered_stream_null_delegate.cc",
     "scattered_stream_writer.cc",
+    "static_buffer.cc",
   ]
 }
 
@@ -49,6 +51,7 @@
   testonly = true
   deps = [
     ":protozero",
+    ":testing_messages_cpp",
     ":testing_messages_lite",
     ":testing_messages_zero",
     "../../gn:default_deps",
@@ -63,6 +66,7 @@
     "proto_decoder_unittest.cc",
     "proto_utils_unittest.cc",
     "scattered_stream_writer_unittest.cc",
+    "test/cppgen_conformance_unittest.cc",
     "test/fake_scattered_buffer.cc",
     "test/fake_scattered_buffer.h",
     "test/protozero_conformance_unittest.cc",
@@ -72,10 +76,6 @@
 # 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/field.cc b/src/protozero/field.cc
new file mode 100644
index 0000000..c92f7ce
--- /dev/null
+++ b/src/protozero/field.cc
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#include "perfetto/protozero/field.h"
+
+#include "perfetto/base/logging.h"
+
+#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+// The memcpy() for fixed32/64 below needs to be adjusted if we want to
+// support big endian CPUs. There doesn't seem to be a compelling need today.
+#error Unimplemented for big endian archs.
+#endif
+
+namespace protozero {
+
+void Field::SerializeAndAppendTo(std::string* dst) {
+  namespace pu = proto_utils;
+  size_t initial_size = dst->size();
+  dst->resize(initial_size + pu::kMaxSimpleFieldEncodedSize + size_);
+  uint8_t* start = reinterpret_cast<uint8_t*>(&(*dst)[initial_size]);
+  uint8_t* wptr = start;
+  switch (type_) {
+    case static_cast<int>(pu::ProtoWireType::kVarInt): {
+      wptr = pu::WriteVarInt(pu::MakeTagVarInt(id_), wptr);
+      wptr = pu::WriteVarInt(int_value_, wptr);
+      break;
+    }
+    case static_cast<int>(pu::ProtoWireType::kFixed32): {
+      wptr = pu::WriteVarInt(pu::MakeTagFixed<uint32_t>(id_), wptr);
+      uint32_t value32 = static_cast<uint32_t>(int_value_);
+      memcpy(wptr, &value32, sizeof(value32));
+      wptr += sizeof(uint32_t);
+      break;
+    }
+    case static_cast<int>(pu::ProtoWireType::kFixed64): {
+      wptr = pu::WriteVarInt(pu::MakeTagFixed<uint64_t>(id_), wptr);
+      memcpy(wptr, &int_value_, sizeof(int_value_));
+      wptr += sizeof(uint64_t);
+      break;
+    }
+    case static_cast<int>(pu::ProtoWireType::kLengthDelimited): {
+      ConstBytes payload = as_bytes();
+      wptr = pu::WriteVarInt(pu::MakeTagLengthDelimited(id_), wptr);
+      wptr = pu::WriteVarInt(payload.size, wptr);
+      memcpy(wptr, payload.data, payload.size);
+      wptr += payload.size;
+      break;
+    }
+    default:
+      PERFETTO_FATAL("Unknown field type %u", type_);
+  }
+  size_t written_size = static_cast<size_t>(wptr - start);
+  PERFETTO_DCHECK(written_size > 0 && written_size < pu::kMaxMessageLength);
+  PERFETTO_DCHECK(initial_size + written_size <= dst->size());
+  dst->resize(initial_size + written_size);
+}
+
+}  // namespace protozero
diff --git a/src/protozero/proto_decoder.cc b/src/protozero/proto_decoder.cc
index bd563fb..9bf9ca5 100644
--- a/src/protozero/proto_decoder.cc
+++ b/src/protozero/proto_decoder.cc
@@ -60,7 +60,10 @@
   if (PERFETTO_LIKELY(*pos < 0x80)) {  // Fastpath for fields with ID < 16.
     preamble = *(pos++);
   } else {
-    pos = ParseVarInt(pos, end, &preamble);
+    const uint8_t* next = ParseVarInt(pos, end, &preamble);
+    if (PERFETTO_UNLIKELY(pos == next))
+      return res;
+    pos = next;
   }
 
   uint32_t field_id = static_cast<uint32_t>(preamble >> kFieldTypeNumBits);
@@ -208,7 +211,7 @@
   PERFETTO_CHECK(new_capacity > size_);
   std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
 
-  static_assert(PERFETTO_IS_TRIVIALLY_COPYABLE(Field),
+  static_assert(std::is_trivially_copyable<Field>::value,
                 "Field must be trivially copyable");
   memcpy(&new_storage[0], fields_, sizeof(Field) * size_);
 
diff --git a/src/protozero/proto_utils_unittest.cc b/src/protozero/proto_utils_unittest.cc
index a724189..9124490 100644
--- a/src/protozero/proto_utils_unittest.cc
+++ b/src/protozero/proto_utils_unittest.cc
@@ -194,6 +194,8 @@
   }
 }
 
+// ParseVarInt() must fail gracefully if we hit the |end| without seeing the
+// MSB == 0 (i.e. end-of-sequence).
 TEST(ProtoUtilsTest, VarIntDecodingOutOfBounds) {
   uint8_t buf[] = {0xff, 0xff, 0xff, 0xff};
   for (size_t i = 0; i < 5; i++) {
@@ -204,6 +206,27 @@
   }
 }
 
+// Even if we see a valid end-of-sequence, ParseVarInt() must fail if the number
+// is larger than 10 bytes. That would cause subtl bugs when trying to shift
+// left by more than 64 bits.
+TEST(ProtoUtilsTest, RejectVarIntTooBig) {
+  // This is the biggest valid varint we support (2**64 - 1).
+  uint8_t good[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01};
+
+  // Parsing this value must succeed.
+  uint64_t value = static_cast<uint64_t>(-1);
+  const uint8_t* res = ParseVarInt(&good[0], &good[sizeof(good)], &value);
+  EXPECT_EQ(&good[sizeof(good)], res);
+  EXPECT_EQ(value, static_cast<uint64_t>(-1ULL));
+
+  uint8_t bad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                   0xff, 0xff, 0xff, 0xff, 0x01};
+  value = static_cast<uint64_t>(-1);
+  res = ParseVarInt(&bad[0], &bad[sizeof(bad)], &value);
+  EXPECT_EQ(&bad[0], res);
+  EXPECT_EQ(0u, value);
+}
+
 }  // namespace
 }  // namespace proto_utils
 }  // namespace protozero
diff --git a/src/protozero/protoc_plugin/cppgen_plugin.cc b/src/protozero/protoc_plugin/cppgen_plugin.cc
index bbd2b23..51fb707 100644
--- a/src/protozero/protoc_plugin/cppgen_plugin.cc
+++ b/src/protozero/protoc_plugin/cppgen_plugin.cc
@@ -19,6 +19,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <map>
 #include <set>
 #include <stack>
 #include <vector>
@@ -46,16 +47,26 @@
 using perfetto::base::ToUpper;
 
 static constexpr auto TYPE_MESSAGE = FieldDescriptor::TYPE_MESSAGE;
+static constexpr auto TYPE_ENUM = FieldDescriptor::TYPE_ENUM;
+static constexpr auto TYPE_SINT32 = FieldDescriptor::TYPE_SINT32;
+static constexpr auto TYPE_SINT64 = FieldDescriptor::TYPE_SINT64;
 
 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";
+// TODO(primiano): this is temporary to avoid clashes between libprotobuf
+// and protozero-cpp classes. Effectively this causes messages like
+// perfetto.protos.DataSourceDescriptor to be generated as
+// perfetto::DataSourceDescriptor. Once libprotobuf is gone we'll be able to
+// move this back into the protos namespace.
+std::string StripPackage(const std::string& pkg) {
+  return StripSuffix(pkg, ".protos");
 }
 
 template <typename T = Descriptor>
-std::string GetFullName(const T* msg, bool with_namespace = false) {
+std::string GetFullName(const T* msg,
+                        bool with_namespace = false,
+                        const std::string& extra_namespace = "") {
   std::string full_type;
   full_type.append(msg->name());
   for (const Descriptor* par = msg->containing_type(); par;
@@ -63,8 +74,9 @@
     full_type.insert(0, par->name() + "_");
   }
   if (with_namespace) {
-    std::vector<std::string> namespaces =
-        SplitString(msg->file()->package(), ".");
+    std::string pkg = msg->file()->package();
+    pkg = extra_namespace == "" ? StripPackage(pkg) : pkg;
+    auto namespaces = SplitString(pkg + extra_namespace, ".");
     for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) {
       full_type.insert(0, *it + "::");
     }
@@ -85,6 +97,9 @@
 
  private:
   std::string GetCppType(const FieldDescriptor* field, bool constref) const;
+  std::string GetPackedBuffer(const FieldDescriptor* field) const;
+  std::string GetPackedWireType(const FieldDescriptor* field) const;
+
   void GenEnum(const EnumDescriptor*, Printer*) const;
   void GenEnumAliases(const EnumDescriptor*, Printer*) const;
   void GenClassDecl(const Descriptor*, Printer*) const;
@@ -118,12 +133,14 @@
   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 <bitset>\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/protozero/copyable_ptr.h\"\n");
   h_printer.Print("#include \"perfetto/base/export.h\"\n\n");
 
+  cc_printer.Print("#include \"perfetto/protozero/scattered_heap_buffer.h\"\n");
   cc_printer.Print(kHeader);
   cc_printer.Print("#pragma GCC diagnostic push\n");
   cc_printer.Print("#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n");
@@ -148,8 +165,9 @@
     }
   }
 
-  // Include the .pb.h for the current file.
-  cc_printer.Print("\n#include \"$f$\"\n", "f", GetProtoHeader(file));
+  // Include the .pbzero.h for the current file.
+  std::string inc_base_name = StripSuffix(file->name(), ".proto");
+  cc_printer.Print("\n#include \"$f$.pbzero.h\"\n", "f", inc_base_name);
 
   // Recursively traverse all imports and turn them into #include(s).
   std::vector<const FileDescriptor*> imports_to_visit;
@@ -160,7 +178,9 @@
     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));
+    std::string base_name = StripSuffix(cur->name(), ".proto");
+    cc_printer.Print("#include \"$f$.gen.h\"\n", "f", base_name);
+    cc_printer.Print("#include \"$f$.pbzero.h\"\n", "f", base_name);
     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()))
@@ -233,27 +253,66 @@
   }  //  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]);
+  // Note: do NOT add #includes to other generated headers (either .gen.h or
+  // .pbzero.h). Doing so is extremely hard to handle at the build-system level
+  // and requires propagating public_deps everywhere.
+  cc_printer.Print("\n");
 
-  for (const Descriptor* msg : all_types)
-    h_printer.Print("class $n$;\n", "n", GetFullName(msg));
+  // -- Begin of fwd declarations.
 
-  for (size_t i = 0; i < namespaces.size(); i++)
-    h_printer.Print("}\n");
+  // Build up the map of forward declarations.
+  std::multimap<std::string /*namespace*/, std::string /*decl*/> fwd_decls;
+  enum FwdType { kClass, kEnum };
+  auto add_fwd_decl = [&fwd_decls](FwdType cpp_type,
+                                   const std::string& full_name) {
+    auto dot = full_name.rfind("::");
+    PERFETTO_CHECK(dot != std::string::npos);
+    auto package = full_name.substr(0, dot);
+    auto name = full_name.substr(dot + 2);
+    if (cpp_type == kClass) {
+      fwd_decls.emplace(package, "class " + name + ";");
+    } else {
+      PERFETTO_CHECK(cpp_type == kEnum);
+      fwd_decls.emplace(package, "enum " + name + " : int;");
+    }
+  };
 
-  h_printer.Print("\nnamespace perfetto {\n");
-  cc_printer.Print("\nnamespace perfetto {\n");
-
-  // Generate fwd declarations for C++ types.
+  for (const Descriptor* msg : all_types) {
+    add_fwd_decl(kClass, GetFullName(msg, true));
+    add_fwd_decl(kClass, GetFullName(msg, true, ".pbzero"));
+  }
   for (const EnumDescriptor* enm : all_enums) {
-    h_printer.Print("enum $n$ : int;\n", "n", GetFullName(enm));
+    add_fwd_decl(kEnum, GetFullName(enm, true));
   }
 
-  for (const Descriptor* msg : all_types)
-    h_printer.Print("class $n$;\n", "n", GetFullName(msg));
+  // Emit forward declarations grouping by package.
+  std::string last_package;
+  auto close_last_package = [&last_package, &h_printer] {
+    if (!last_package.empty()) {
+      for (const std::string& ns : SplitString(last_package, "::"))
+        h_printer.Print("}  // namespace $ns$\n", "ns", ns);
+      h_printer.Print("\n");
+    }
+  };
+  for (const auto& kv : fwd_decls) {
+    const std::string& package = kv.first;
+    if (package != last_package) {
+      close_last_package();
+      last_package = package;
+      for (const std::string& ns : SplitString(package, "::"))
+        h_printer.Print("namespace $ns$ {\n", "ns", ns);
+    }
+    h_printer.Print("$decl$\n", "decl", kv.second);
+  }
+  close_last_package();
+
+  // -- End of fwd declarations.
+
+  auto namespaces = SplitString(StripPackage(file->package()), ".");
+  for (size_t i = 0; i < namespaces.size(); i++) {
+    h_printer.Print("namespace $n$ {\n", "n", namespaces[i]);
+    cc_printer.Print("namespace $n$ {\n", "n", namespaces[i]);
+  }
 
   // Generate declarations and definitions.
   for (const EnumDescriptor* enm : local_enums)
@@ -264,10 +323,12 @@
     GenClassDef(msg, &cc_printer);
   }
 
-  cc_printer.Print("}  // namespace perfetto\n");
-  cc_printer.Print("#pragma GCC diagnostic pop\n");
+  for (size_t i = 0; i < namespaces.size(); i++) {
+    h_printer.Print("}  // namespace $n$\n", "n", namespaces[i]);
+    cc_printer.Print("}  // namespace $n$\n", "n", namespaces[i]);
+  }
 
-  h_printer.Print("}  // namespace perfetto\n");
+  cc_printer.Print("#pragma GCC diagnostic pop\n");
   h_printer.Print("\n#endif  // $g$\n", "g", include_guard);
 
   return true;
@@ -311,6 +372,68 @@
   abort();  // for gcc
 }
 
+std::string CppObjGenerator::GetPackedBuffer(
+    const FieldDescriptor* field) const {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_FIXED32:
+      return "::protozero::PackedFixedSizeInt<uint32_t>";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "::protozero::PackedFixedSizeInt<int32_t>";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "::protozero::PackedFixedSizeInt<uint64_t>";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "::protozero::PackedFixedSizeInt<int64_t>";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "::protozero::PackedFixedSizeInt<double>";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "::protozero::PackedFixedSizeInt<float>";
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_BOOL:
+      return "::protozero::PackedVarInt";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_ENUM:
+    case FieldDescriptor::TYPE_GROUP:
+      break;  // Will abort()
+  }
+  abort();
+}
+
+std::string CppObjGenerator::GetPackedWireType(
+    const FieldDescriptor* field) const {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+    case FieldDescriptor::TYPE_FLOAT:
+      return "::protozero::proto_utils::ProtoWireType::kFixed32";
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "::protozero::proto_utils::ProtoWireType::kFixed64";
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_BOOL:
+      return "::protozero::proto_utils::ProtoWireType::kVarInt";
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+    case FieldDescriptor::TYPE_MESSAGE:
+    case FieldDescriptor::TYPE_ENUM:
+    case FieldDescriptor::TYPE_GROUP:
+      break;  // Will abort()
+  }
+  abort();
+}
+
 void CppObjGenerator::GenEnum(const EnumDescriptor* enum_desc,
                               Printer* p) const {
   std::string full_name = GetFullName(enum_desc);
@@ -368,6 +491,17 @@
     GenEnumAliases(nested_enum, p);
   }
 
+  // Generate constants with field numbers.
+  p->Print("enum FieldNumbers {\n");
+  for (int i = 0; i < msg->field_count(); i++) {
+    const FieldDescriptor* field = msg->field(i);
+    std::string name = field->camelcase_name();
+    name[0] = perfetto::base::Uppercase(name[0]);
+    p->Print("  k$n$FieldNumber = $num$,\n", "n", name, "num",
+             std::to_string(field->number()));
+  }
+  p->Print("};\n\n");
+
   p->Print("$n$();\n", "n", full_name);
   p->Print("~$n$();\n", "n", full_name);
   p->Print("$n$($n$&&) noexcept;\n", "n", full_name);
@@ -382,36 +516,58 @@
 
   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);
+  p->Print("bool ParseFromArray(const void*, size_t);\n");
+  p->Print("bool ParseRawProto(const std::string& str) {\n");
+  p->Print("  return ParseFromArray(str.data(), str.size());\n");
+  p->Print("}\n");
+
+  p->Print("std::string SerializeAsString() const;\n");
+  p->Print("std::vector<uint8_t> SerializeAsArray() const;\n");
+  p->Print("void Serialize($p$*) const;\n", "p",
+           GetFullName(msg, true, ".pbzero"));
+
+  p->Print("// (DEPRECATED) Conversion methods from/to libprotobuf types.\n");
+  p->Print("// These two will go away soon, see go/perfetto-libprotobuf.\n");
+  p->Print(
+      "template <typename T /*$p$*/> void FromProto(const T& pb_obj) { "
+      "ParseRawProto(pb_obj.SerializeAsString()); }\n",
+      "p", proto_type);
+  p->Print(
+      "template <typename T /*$p$*/> void ToProto(T* pb_obj) const { "
+      "pb_obj->Clear(); pb_obj->ParseFromString(SerializeAsString()); }\n",
+      "p", proto_type);
 
   // Generate accessors.
   for (int i = 0; i < msg->field_count(); i++) {
     const FieldDescriptor* field = msg->field(i);
+    auto set_bit = "_has_field_.set(" + std::to_string(field->number()) + ")";
     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());
+      p->Print(
+          "void set_$n$_raw(const std::string& raw) { $n$_ = raw; $s$; }\n",
+          "n", field->lowercase_name(), "s", set_bit);
     } else if (!field->is_repeated()) {
+      p->Print("bool has_$n$() const { return _has_field_[$bit$]; }\n", "n",
+               field->lowercase_name(), "bit", std::to_string(field->number()));
       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());
+        p->Print("$t$* mutable_$n$() { $s$; return $n$_.get(); }\n", "t",
+                 GetCppType(field, false), "n", field->lowercase_name(), "s",
+                 set_bit);
       } 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());
+        p->Print("void set_$n$($t$ value) { $n$_ = value; $s$; }\n", "t",
+                 GetCppType(field, true), "n", field->lowercase_name(), "s",
+                 set_bit);
         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());
+              "$n$_.assign(reinterpret_cast<const char*>(p), s); $s$; }\n",
+              "n", field->lowercase_name(), "s", set_bit);
         }
       }
     } else {  // is_repeated()
@@ -424,6 +580,13 @@
                GetCppType(field, false), "n", field->lowercase_name());
       p->Print("void clear_$n$() { $n$_.clear(); }\n", "n",
                field->lowercase_name());
+      if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+        p->Print("void add_$n$($t$ value) { $n$_.emplace_back(value); }\n", "t",
+                 GetCppType(field, false), "n", field->lowercase_name());
+      }
+      // TODO(primiano): this should be done only for TYPE_MESSAGE. Unfortuntely
+      // we didn't realize before and now we have a bunch of code that does:
+      // *msg->add_int_value() = 42 instead of msg->add_int_value(42).
       p->Print("$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); }\n",
                "t", GetCppType(field, false), "n", field->lowercase_name());
     }
@@ -433,8 +596,10 @@
   p->Indent();
 
   // Generate fields.
+  int max_field_id = 1;
   for (int i = 0; i < msg->field_count(); i++) {
     const FieldDescriptor* field = msg->field(i);
+    max_field_id = std::max(max_field_id, field->number());
     if (field->options().lazy()) {
       p->Print("std::string $n$_;  // [lazy=true]\n", "n",
                field->lowercase_name());
@@ -455,6 +620,10 @@
   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->Print("\nstd::bitset<$id$> _has_field_{};\n", "id",
+           std::to_string(max_field_id + 1));
+
   p->Outdent();
   p->Print("};\n\n");
 }
@@ -485,104 +654,156 @@
 
   std::string proto_type = GetFullName(msg, true);
 
-  // Genrate the ParseRawProto() method definition.
-  p->Print("void $f$::ParseRawProto(const std::string& raw) {\n", "f",
+  // Generate the ParseRawProto() method definition.
+  p->Print("bool $f$::ParseFromArray(const void* raw, size_t size) {\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()
+    if (field->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->Print("unknown_fields_.clear();\n");
+  p->Print("bool packed_error = false;\n");
+  p->Print("\n");
+  p->Print("::protozero::ProtoDecoder dec(raw, size);\n");
+  p->Print("for (auto field = dec.ReadField(); field.valid(); ");
+  p->Print("field = dec.ReadField()) {\n");
+  p->Indent();
+  p->Print("if (field.id() < _has_field_.size()) {\n");
+  p->Print("  _has_field_.set(field.id());\n");
+  p->Print("}\n");
+  p->Print("switch (field.id()) {\n");
+  p->Indent();
+  for (int i = 0; i < msg->field_count(); i++) {
+    const FieldDescriptor* field = msg->field(i);
+    p->Print("case $id$ /* $n$ */:\n", "id", std::to_string(field->number()),
+             "n", field->lowercase_name());
+    p->Indent();
+    if (field->options().lazy()) {
+      p->Print("$n$_ = field.as_std_string();\n", "n", field->lowercase_name());
+    } else {
+      std::string statement;
+      if (field->type() == TYPE_MESSAGE) {
+        statement = "$rval$.ParseRawProto(field.as_std_string());\n";
+      } else {
+        if (field->type() == TYPE_SINT32 || field->type() == TYPE_SINT64) {
+          // sint32/64 fields are special and need to be zig-zag-decoded.
+          statement = "field.get_signed(&$rval$);\n";
+        } else {
+          statement = "field.get(&$rval$);\n";
+        }
+      }
+      if (field->is_packed()) {
+        PERFETTO_CHECK(field->is_repeated());
+        if (field->type() == TYPE_SINT32 || field->type() == TYPE_SINT64) {
+          PERFETTO_FATAL("packed signed (zigzag) fields are not supported");
+        }
+        p->Print(
+            "for (::protozero::PackedRepeatedFieldIterator<$w$, $c$> "
+            "rep(field.data(), field.size(), &packed_error); rep; ++rep) {\n",
+            "w", GetPackedWireType(field), "c", GetCppType(field, false));
+        p->Print("  $n$_.emplace_back(*rep);\n", "n", field->lowercase_name());
+        p->Print("}\n");
+      } else if (field->is_repeated()) {
+        p->Print("$n$_.emplace_back();\n", "n", field->lowercase_name());
+        p->Print(statement.c_str(), "rval",
+                 field->lowercase_name() + "_.back()");
+      } else if (field->type() == TYPE_MESSAGE) {
+        p->Print(statement.c_str(), "rval",
+                 "(*" + field->lowercase_name() + "_)");
+      } else {
+        p->Print(statement.c_str(), "rval", field->lowercase_name() + "_");
+      }
+    }
+    p->Print("break;\n");
+    p->Outdent();
+  }  // for (field)
+  p->Print("default:\n");
+  p->Print("  field.SerializeAndAppendTo(&unknown_fields_);\n");
+  p->Print("  break;\n");
+  p->Outdent();
+  p->Print("}\n");  // switch(field.id)
+  p->Outdent();
+  p->Print("}\n");                                           // for(field)
+  p->Print("return !packed_error && !dec.bytes_left();\n");  // for(field)
   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);
+  // Generate the SerializeAsString() method definition.
+  p->Print("std::string $f$::SerializeAsString() const {\n", "f", full_name);
   p->Indent();
-  p->Print("proto->Clear();\n");
+  p->Print("::protozero::HeapBuffered<$p$> msg;\n", "p",
+           GetFullName(msg, true, ".pbzero"));
+  p->Print("Serialize(msg.get());\n");
+  p->Print("return msg.SerializeAsString();\n");
+  p->Outdent();
+  p->Print("}\n\n");
+
+  // Generate the SerializeAsArray() method definition.
+  p->Print("std::vector<uint8_t> $f$::SerializeAsArray() const {\n", "f",
+           full_name);
+  p->Indent();
+  p->Print("::protozero::HeapBuffered<$p$> msg;\n", "p",
+           GetFullName(msg, true, ".pbzero"));
+  p->Print("Serialize(msg.get());\n");
+  p->Print("return msg.SerializeAsArray();\n");
+  p->Outdent();
+  p->Print("}\n\n");
+
+  // Generaate the Serialize() method that writes the fields into the passed
+  // protozero |msg| write-only interface |msg|.
+  p->Print("void $f$::Serialize($p$* msg) const {\n", "f", full_name, "p",
+           GetFullName(msg, true, ".pbzero"));
+  p->Indent();
   for (int i = 0; i < msg->field_count(); i++) {
-    p->Print("\n");
     const FieldDescriptor* field = msg->field(i);
+    std::string fld_name = field->lowercase_name();
     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());
+      p->Print("msg->set_$n$_raw($n$_);\n", "n", fld_name);
+    } else {
+      std::string enum_type;
+      if (field->type() == TYPE_ENUM)
+        enum_type = GetFullName(field->enum_type(), true, ".pbzero");
+      if (field->is_packed()) {
+        PERFETTO_CHECK(field->is_repeated());
+        p->Print("{\n");
+        p->Indent();
+        p->Print("$p$ pack;\n", "p", GetPackedBuffer(field));
+        p->Print("for (auto& it : $n$_)\n", "n", fld_name);
+        p->Print("  pack.Append(it);\n");
+        p->Print("msg->set_$n$(pack);\n", "n", fld_name);
+        p->Outdent();
+        p->Print("}\n");
+      } else if (field->is_repeated()) {
+        p->Print("for (auto& it : $n$_) {\n", "n", fld_name);
+        if (field->type() == TYPE_MESSAGE) {
+          p->Print("  it.Serialize(msg->add_$n$());\n", "n", fld_name);
+        } else if (field->type() == TYPE_ENUM) {
+          p->Print("  msg->add_$n$(static_cast<::$e$>(it));\n", "n", fld_name,
+                   "e", enum_type);
+        } else {
+          p->Print("  msg->add_$n$(it);\n", "n", fld_name);
+        }
+        p->Print("}\n");
+      } else {  // repeated = false
+        p->Print("if (_has_field_[$id$]) { ", "id",
+                 std::to_string(field->number()));
+        if (field->type() == TYPE_MESSAGE) {
+          p->Print("$n$_->Serialize(msg->set_$n$());", "n", fld_name);
+        } else if (field->type() == TYPE_ENUM) {
+          p->Print("msg->set_$n$(static_cast<::$e$>($n$_));", "n", fld_name,
+                   "e", enum_type);
+        } else {
+          p->Print("msg->set_$n$($n$_);", "n", fld_name);
+        }
+        p->Print(" }\n");
       }
-    } 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");
+  }  // for (field)
+  p->Print(
+      "msg->AppendRawProtoBytes(unknown_fields_.data(), "
+      "unknown_fields_.size());\n");
   p->Outdent();
   p->Print("}\n\n");
 }
diff --git a/src/protozero/static_buffer.cc b/src/protozero/static_buffer.cc
new file mode 100644
index 0000000..cb4737b
--- /dev/null
+++ b/src/protozero/static_buffer.cc
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "perfetto/protozero/static_buffer.h"
+
+#include "perfetto/base/logging.h"
+
+namespace protozero {
+
+StaticBufferDelegate::~StaticBufferDelegate() = default;
+
+ContiguousMemoryRange StaticBufferDelegate::GetNewBuffer() {
+  if (get_new_buffer_called_once_) {
+    // This is the 2nd time GetNewBuffer is called. The estimate is wrong. We
+    // shouldn't try to grow the buffer after the initial call.
+    PERFETTO_FATAL("Static buffer too small");
+  }
+  get_new_buffer_called_once_ = true;
+  return range_;
+}
+
+}  // namespace protozero
diff --git a/src/protozero/test/cppgen_conformance_unittest.cc b/src/protozero/test/cppgen_conformance_unittest.cc
new file mode 100644
index 0000000..040b507
--- /dev/null
+++ b/src/protozero/test/cppgen_conformance_unittest.cc
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ */
+
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/packed_repeated_fields.h"
+#include "test/gtest_and_gmock.h"
+
+// Autogenerated headers in out/*/gen/
+#include "src/protozero/test/example_proto/library.gen.h"
+#include "src/protozero/test/example_proto/test_messages.gen.h"
+#include "src/protozero/test/example_proto/test_messages.pb.h"
+
+// Generated by the cppgen compiler.
+namespace pbtest = protozero::test;
+
+// Generated by the official protobuf compiler.
+namespace pbgold = protozero::test::protos;
+
+namespace protozero {
+namespace {
+
+using testing::ElementsAreArray;
+
+// The two functions below are templated because they are re-used both on the
+// libprotobuf and protozero versions to check both libproto -> zero and
+// zero -> libproto compatibility.
+template <typename T>
+void SetTestingFields(T* msg) {
+  msg->set_field_int32(-1);
+  msg->set_field_int64(-333123456789ll);
+  msg->set_field_uint32(600);
+  msg->set_field_uint64(333123456789ll);
+  msg->set_field_sint32(-5);
+  msg->set_field_sint64(-9000);
+  msg->set_field_fixed32(12345);
+  msg->set_field_fixed64(444123450000ll);
+  msg->set_field_sfixed32(-69999);
+  msg->set_field_sfixed64(-200);
+  msg->set_field_float(3.14f);
+  msg->set_field_double(0.5555);
+  msg->set_field_bool(true);
+
+  msg->set_small_enum(decltype(msg->small_enum())::TO_BE);
+  msg->set_signed_enum(decltype(msg->signed_enum())::NEGATIVE);
+  msg->set_big_enum(decltype(msg->big_enum())::BEGIN);
+
+  msg->set_field_string("FizzBuzz");
+  msg->set_field_bytes(reinterpret_cast<const uint8_t*>("\x11\x00\xBE\xEF"), 4);
+  msg->add_repeated_int32(1);
+  msg->add_repeated_int32(-1);
+  msg->add_repeated_int32(100);
+  msg->add_repeated_int32(2000000);
+}
+
+template <typename T>
+void CheckTestingFields(const T& msg) {
+  EXPECT_EQ(-1, msg.field_int32());
+  EXPECT_EQ(-333123456789ll, msg.field_int64());
+  EXPECT_EQ(600u, msg.field_uint32());
+  EXPECT_EQ(333123456789ull, msg.field_uint64());
+  EXPECT_EQ(-5, msg.field_sint32());
+  EXPECT_EQ(-9000, msg.field_sint64());
+  EXPECT_EQ(12345u, msg.field_fixed32());
+  EXPECT_EQ(444123450000ull, msg.field_fixed64());
+  EXPECT_EQ(-69999, msg.field_sfixed32());
+  EXPECT_EQ(-200, msg.field_sfixed64());
+  EXPECT_FLOAT_EQ(3.14f, msg.field_float());
+  EXPECT_DOUBLE_EQ(0.5555, msg.field_double());
+  EXPECT_EQ(true, msg.field_bool());
+  EXPECT_EQ(decltype(msg.small_enum())::TO_BE, msg.small_enum());
+  EXPECT_EQ(decltype(msg.signed_enum())::NEGATIVE, msg.signed_enum());
+  EXPECT_EQ(decltype(msg.big_enum())::BEGIN, msg.big_enum());
+  EXPECT_EQ("FizzBuzz", msg.field_string());
+  EXPECT_EQ(std::string("\x11\x00\xBE\xEF", 4), msg.field_bytes());
+  ASSERT_THAT(msg.repeated_int32(), ElementsAreArray({1, -1, 100, 2000000}));
+}
+
+TEST(ProtoCppConformanceTest, GenEncode_GoldDecode) {
+  pbtest::EveryField msg;
+  SetTestingFields(&msg);
+  std::string serialized = msg.SerializeAsString();
+
+  pbgold::EveryField gold_msg;
+  gold_msg.ParseFromString(serialized);
+  CheckTestingFields(gold_msg);
+  EXPECT_EQ(serialized.size(), static_cast<size_t>(gold_msg.ByteSize()));
+}
+
+TEST(ProtoCppConformanceTest, GoldEncode_GenDecode) {
+  pbgold::EveryField gold_msg;
+  SetTestingFields(&gold_msg);
+  std::string serialized = gold_msg.SerializeAsString();
+
+  pbtest::EveryField msg;
+  EXPECT_TRUE(msg.ParseRawProto(serialized));
+  CheckTestingFields(msg);
+}
+
+TEST(ProtoCppConformanceTest, GenEncode_GenDecode) {
+  pbtest::EveryField msg;
+  SetTestingFields(&msg);
+  std::string serialized = msg.SerializeAsString();
+
+  pbtest::EveryField dec_msg;
+  dec_msg.ParseRawProto(serialized);
+  CheckTestingFields(dec_msg);
+  EXPECT_EQ(serialized.size(), dec_msg.SerializeAsString().size());
+}
+
+TEST(ProtoCppConformanceTest, NestedMessages) {
+  pbtest::NestedA msg_a;
+  pbtest::NestedA::NestedB* msg_b = msg_a.add_repeated_a();
+  pbtest::NestedA::NestedB::NestedC* msg_c = msg_b->mutable_value_b();
+  msg_c->set_value_c(321);
+  msg_b = msg_a.add_repeated_a();
+  msg_a.mutable_super_nested()->set_value_c(1000);
+  std::string serialized = msg_a.SerializeAsString();
+
+  pbgold::NestedA gold_msg_a;
+  gold_msg_a.ParseFromString(serialized);
+  EXPECT_EQ(2, gold_msg_a.repeated_a_size());
+  EXPECT_EQ(321, gold_msg_a.repeated_a(0).value_b().value_c());
+  EXPECT_FALSE(gold_msg_a.repeated_a(1).has_value_b());
+  EXPECT_EQ(gold_msg_a.repeated_a(1).value_b().value_c(), 0);
+  EXPECT_EQ(1000, gold_msg_a.super_nested().value_c());
+}
+
+// Tests that unknown fields are preserved when re-serializing. This test uses
+// the messages NestedA and NestedA_V2, where NestedA_V2 mimics a future
+// extension of NestedA. It starts filling the V2 version, than decodes it with
+// V1, then re-encodes V1 and decodes with V2 and finally check that all the V2
+// original fields have been preserved.
+TEST(ProtoCppConformanceTest, PreserveUnknownFields) {
+  std::string serialized;
+  {
+    pbtest::TestVersioning_V2 msg_v2;
+    msg_v2.set_root_int(10);
+    msg_v2.set_root_int_v2(11);
+    msg_v2.add_enumz(pbtest::TestVersioning_V2::ONE);
+    msg_v2.add_enumz(pbtest::TestVersioning_V2::TWO);
+    msg_v2.add_enumz(pbtest::TestVersioning_V2::THREE_V2);
+    msg_v2.set_root_string("root-string");
+    msg_v2.add_rep_string("root-rep-string-1");
+    msg_v2.add_rep_string("root-rep-string-2");
+    for (int i = 0; i < 3; i++) {
+      auto* sub1 = i == 0 ? msg_v2.mutable_sub1() : msg_v2.add_sub1_rep();
+      sub1->set_sub1_int(12);
+      sub1->set_sub1_string("sub1-string");
+      sub1->set_sub1_int_v2(13);
+      sub1->set_sub1_string_v2("sub1-string-v2");
+
+      auto* sub2 = i == 0 ? msg_v2.mutable_sub2() : msg_v2.add_sub2_rep();
+      sub2->set_sub2_int(14);
+      sub2->set_sub2_string("sub2-string");
+    }
+    {
+      pbtest::TestVersioning_V2::Sub1_V2 lazy;
+      lazy.set_sub1_int(15);
+      lazy.set_sub1_string("sub1-lazy-string");
+      lazy.set_sub1_int_v2(16);
+      lazy.set_sub1_string_v2("sub1-lazy-string-v2");
+      msg_v2.set_sub1_lazy_raw(lazy.SerializeAsString());
+    }
+    {
+      pbtest::TestVersioning_V2::Sub2_V2 lazy;
+      lazy.set_sub2_int(17);
+      lazy.set_sub2_string("sub2-v2-lazy-string");
+      msg_v2.set_sub2_lazy_raw(lazy.SerializeAsString());
+    }
+
+    serialized = msg_v2.SerializeAsString();
+  }
+
+  // Now decode with an earlier version that has less fields. Then re-serialize
+  // the v1 message.
+  {
+    pbtest::TestVersioning_V1 msg_v1;
+    EXPECT_TRUE(msg_v1.ParseRawProto(serialized));
+    EXPECT_EQ(msg_v1.root_int(), 10);
+    EXPECT_EQ(msg_v1.enumz_size(), 3);
+    // These are to workaround "ODR-usage" rules that would require that the
+    // constexpr in the .gen.h file have a matching symbol definition in the .cc
+    // file.
+    const auto ONE = pbtest::TestVersioning_V1::ONE;
+    const auto TWO = pbtest::TestVersioning_V1::TWO;
+    EXPECT_EQ(msg_v1.enumz()[0], ONE);
+    EXPECT_EQ(msg_v1.enumz()[1], TWO);
+    EXPECT_EQ(static_cast<int>(msg_v1.enumz()[2]), 3);
+    EXPECT_EQ(msg_v1.root_string(), "root-string");
+    EXPECT_EQ(msg_v1.rep_string_size(), 2);
+    EXPECT_EQ(msg_v1.rep_string()[0], "root-rep-string-1");
+    EXPECT_EQ(msg_v1.rep_string()[1], "root-rep-string-2");
+    EXPECT_EQ(msg_v1.sub1_rep_size(), 2);
+    for (size_t i = 0; i < 3; i++) {
+      auto* sub1 = i == 0 ? &msg_v1.sub1() : &msg_v1.sub1_rep()[i - 1];
+      EXPECT_EQ(sub1->sub1_int(), 12);
+      EXPECT_EQ(sub1->sub1_string(), "sub1-string");
+    }
+
+    // Append an extra field and change the valaue of an existing one before
+    // re-serializing.
+    msg_v1.set_root_int(101);
+    msg_v1.add_rep_string("extra-string");
+    serialized = msg_v1.SerializeAsString();
+  }
+
+  // Decode the re-serialized v1 message with with v2. Check that the _v2
+  // fields have been preserved in the double de/serializataion across versions.
+  {
+    pbtest::TestVersioning_V2 msg_v2;
+    EXPECT_TRUE(msg_v2.ParseRawProto(serialized));
+    EXPECT_EQ(msg_v2.root_int(), 101);
+    EXPECT_EQ(msg_v2.root_int_v2(), 11);
+    EXPECT_EQ(msg_v2.enumz_size(), 3);
+    const auto ONE = pbtest::TestVersioning_V2::ONE;
+    const auto TWO = pbtest::TestVersioning_V2::TWO;
+    const auto THREE_V2 = pbtest::TestVersioning_V2::THREE_V2;
+    EXPECT_EQ(msg_v2.enumz()[0], ONE);
+    EXPECT_EQ(msg_v2.enumz()[1], TWO);
+    EXPECT_EQ(msg_v2.enumz()[2], THREE_V2);
+    EXPECT_EQ(msg_v2.root_string(), "root-string");
+    EXPECT_EQ(msg_v2.rep_string_size(), 3);
+    EXPECT_EQ(msg_v2.rep_string()[0], "root-rep-string-1");
+    EXPECT_EQ(msg_v2.rep_string()[1], "root-rep-string-2");
+    EXPECT_EQ(msg_v2.rep_string()[2], "extra-string");
+    EXPECT_EQ(msg_v2.sub1_rep_size(), 2);
+    for (size_t i = 0; i < 3; i++) {
+      auto* sub1 = i == 0 ? &msg_v2.sub1() : &msg_v2.sub1_rep()[i - 1];
+      EXPECT_EQ(sub1->sub1_int(), 12);
+      EXPECT_EQ(sub1->sub1_string(), "sub1-string");
+      EXPECT_EQ(sub1->sub1_int_v2(), 13);
+      EXPECT_EQ(sub1->sub1_string_v2(), "sub1-string-v2");
+      auto* sub2 = i == 0 ? &msg_v2.sub2() : &msg_v2.sub2_rep()[i - 1];
+      EXPECT_EQ(sub2->sub2_int(), 14);
+      EXPECT_EQ(sub2->sub2_string(), "sub2-string");
+    }
+    {
+      pbtest::TestVersioning_V2::Sub1_V2 lazy;
+      EXPECT_TRUE(lazy.ParseRawProto(msg_v2.sub1_lazy_raw()));
+      EXPECT_EQ(lazy.sub1_int(), 15);
+      EXPECT_EQ(lazy.sub1_string(), "sub1-lazy-string");
+      EXPECT_EQ(lazy.sub1_int_v2(), 16);
+      EXPECT_EQ(lazy.sub1_string_v2(), "sub1-lazy-string-v2");
+    }
+    {
+      pbtest::TestVersioning_V2::Sub2_V2 lazy;
+      EXPECT_TRUE(lazy.ParseRawProto(msg_v2.sub2_lazy_raw()));
+      EXPECT_EQ(lazy.sub2_int(), 17);
+      EXPECT_EQ(lazy.sub2_string(), "sub2-v2-lazy-string");
+    }
+  }
+}
+
+// Checks that unset fields aren't zero-initialized in the decode -> re-encode
+// process.
+TEST(ProtoCppConformanceTest, DontDefaultInitialize) {
+  pbtest::EveryField msg;
+  EXPECT_FALSE(msg.has_field_int32());
+  msg.set_field_int32(0);
+  EXPECT_TRUE(msg.has_field_int32());
+
+  EXPECT_FALSE(msg.has_field_float());
+  msg.set_field_float(.0f);
+  EXPECT_TRUE(msg.has_field_float());
+
+  EXPECT_FALSE(msg.has_field_string());
+  msg.set_field_string("");
+  EXPECT_TRUE(msg.has_field_string());
+
+  pbtest::EveryField dec;
+  dec.ParseRawProto(msg.SerializeAsString());
+  std::string reserialized = dec.SerializeAsString();
+
+  pbgold::EveryField gold_msg;
+  gold_msg.ParseFromString(reserialized);
+  EXPECT_TRUE(gold_msg.has_field_int32());
+  EXPECT_EQ(gold_msg.field_int32(), 0);
+  EXPECT_TRUE(gold_msg.has_field_float());
+  EXPECT_FLOAT_EQ(gold_msg.field_float(), .0f);
+  EXPECT_TRUE(gold_msg.has_field_string());
+  EXPECT_EQ(gold_msg.field_string(), "");
+  EXPECT_FALSE(gold_msg.has_field_int64());
+  EXPECT_FALSE(gold_msg.has_field_uint64());
+  EXPECT_FALSE(gold_msg.has_field_bytes());
+}
+
+// Tests serialization and deserialization of packed encoding fields.
+TEST(ProtoCppConformanceTest, PackedRepeatedFields) {
+  std::string serialized;
+  {
+    pbtest::PackedRepeatedFields msg;
+
+    for (int i = -100; i < 100; i++)
+      msg.add_field_int32(i);
+
+    for (uint32_t i = 100; i < 200; i++)
+      msg.add_field_fixed32(i);
+
+    for (int64_t i = 5000000000; i < 5000001000; i++)
+      msg.add_field_sfixed64(i);
+
+    serialized = msg.SerializeAsString();
+  }
+  {
+    pbtest::PackedRepeatedFields msg;
+    EXPECT_TRUE(msg.ParseRawProto(serialized));
+
+    std::vector<int> exp_int32;
+    for (int i = -100; i < 100; i++)
+      exp_int32.emplace_back(i);
+    ASSERT_THAT(msg.field_int32(), ElementsAreArray(exp_int32));
+
+    std::vector<uint32_t> exp_fixed32;
+    for (uint32_t i = 100; i < 200; i++)
+      exp_fixed32.emplace_back(i);
+    ASSERT_THAT(msg.field_fixed32(), ElementsAreArray(exp_fixed32));
+
+    std::vector<int64_t> exp_sfixed64;
+    for (int64_t i = 5000000000; i < 5000001000; i++)
+      exp_sfixed64.emplace_back(i);
+    ASSERT_THAT(msg.field_sfixed64(), ElementsAreArray(exp_sfixed64));
+  }
+}
+}  // namespace
+}  // namespace protozero
diff --git a/src/protozero/test/example_proto/test_messages.proto b/src/protozero/test/example_proto/test_messages.proto
index db8212c..298b77f 100644
--- a/src/protozero/test/example_proto/test_messages.proto
+++ b/src/protozero/test/example_proto/test_messages.proto
@@ -104,3 +104,56 @@
   repeated fixed32 field_fixed32 = 2 [packed = true];
   repeated sfixed64 field_sfixed64 = 3 [packed = true];
 }
+
+// The following two messages are for testing that unknown fields being
+// preserved in the decode->reencode path.
+
+message TestVersioning_V1 {
+  enum Enumz_V1 {
+    ONE = 1;
+    TWO = 2;
+  }
+  message Sub1_V1 {
+    optional int32 sub1_int = 1;
+    optional string sub1_string = 2;
+  }
+  optional int32 root_int = 1;
+  repeated Enumz_V1 enumz = 2;
+  optional string root_string = 3;
+  repeated string rep_string = 4;
+  optional Sub1_V1 sub1 = 5;
+  repeated Sub1_V1 sub1_rep = 6;
+  optional Sub1_V1 sub1_lazy = 7 [lazy = true];
+}
+
+message TestVersioning_V2 {
+  enum Enumz_V2 {
+    ONE = 1;
+    TWO = 2;
+    THREE_V2 = 3;
+  }
+  message Sub1_V2 {
+    optional int32 sub1_int = 1;
+    optional string sub1_string = 2;
+    optional int32 sub1_int_v2 = 3;      // New in v2.
+    optional string sub1_string_v2 = 4;  // New in v2.
+  }
+  message Sub2_V2 {  // New in v2.
+    optional int32 sub2_int = 1;
+    optional string sub2_string = 2;
+  }
+
+  optional int32 root_int = 1;
+  repeated Enumz_V2 enumz = 2;
+  optional string root_string = 3;
+  repeated string rep_string = 4;
+  optional Sub1_V2 sub1 = 5;
+  repeated Sub1_V2 sub1_rep = 6;
+  optional Sub1_V2 sub1_lazy = 7 [lazy = true];
+
+  // New fields introduced in V2.
+  optional int32 root_int_v2 = 10;
+  optional Sub2_V2 sub2 = 11;
+  repeated Sub2_V2 sub2_rep = 12;
+  optional Sub2_V2 sub2_lazy = 13 [lazy = true];
+}
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 80d394d..a096cd2 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -357,6 +357,7 @@
 perfetto_unittest_source_set("unittests") {
   testonly = true
   sources = [
+    "basic_types_unittest.cc",
     "clock_tracker_unittest.cc",
     "event_tracker_unittest.cc",
     "forwarding_trace_parser_unittest.cc",
diff --git a/src/trace_processor/basic_types_unittest.cc b/src/trace_processor/basic_types_unittest.cc
new file mode 100644
index 0000000..a2a0fd2
--- /dev/null
+++ b/src/trace_processor/basic_types_unittest.cc
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include "perfetto/trace_processor/basic_types.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+TEST(SqlValueTest, DifferentTypes) {
+  ASSERT_LT(SqlValue(), SqlValue::Long(10));
+  ASSERT_LT(SqlValue::Long(10), SqlValue::Double(10.0));
+  ASSERT_LT(SqlValue::Double(10.0), SqlValue::String("10"));
+}
+
+TEST(SqlValueTest, CompareLong) {
+  SqlValue int32_min = SqlValue::Long(std::numeric_limits<int32_t>::min());
+  SqlValue minus_1 = SqlValue::Long(-1);
+  SqlValue zero = SqlValue::Long(0);
+  SqlValue uint32_max = SqlValue::Long(std::numeric_limits<uint32_t>::max());
+
+  ASSERT_LT(int32_min, minus_1);
+  ASSERT_LT(int32_min, uint32_max);
+  ASSERT_LT(minus_1, uint32_max);
+
+  ASSERT_GT(uint32_max, zero);
+
+  ASSERT_EQ(zero, zero);
+}
+
+TEST(SqlValueTest, CompareDouble) {
+  SqlValue int32_min = SqlValue::Double(std::numeric_limits<int32_t>::min());
+  SqlValue minus_1 = SqlValue::Double(-1.0);
+  SqlValue zero = SqlValue::Double(0);
+  SqlValue uint32_max = SqlValue::Double(std::numeric_limits<uint32_t>::max());
+
+  ASSERT_LT(int32_min, minus_1);
+  ASSERT_LT(int32_min, uint32_max);
+  ASSERT_LT(minus_1, uint32_max);
+
+  ASSERT_GT(uint32_max, zero);
+
+  ASSERT_EQ(zero, zero);
+}
+
+TEST(SqlValueTest, CompareString) {
+  SqlValue a = SqlValue::String("a");
+  SqlValue aa = SqlValue::String("aa");
+  SqlValue b = SqlValue::String("b");
+
+  ASSERT_LT(a, aa);
+  ASSERT_LT(aa, b);
+  ASSERT_LT(a, b);
+
+  ASSERT_GT(aa, a);
+
+  ASSERT_EQ(a, a);
+  ASSERT_EQ(aa, SqlValue::String("aa"));
+}
+
+}  // namespace
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/clock_tracker.cc b/src/trace_processor/clock_tracker.cc
index 87559e0..696a110 100644
--- a/src/trace_processor/clock_tracker.cc
+++ b/src/trace_processor/clock_tracker.cc
@@ -38,22 +38,56 @@
 
 ClockTracker::~ClockTracker() = default;
 
-void ClockTracker::AddSnapshot(const std::map<ClockId, int64_t>& clocks) {
+void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
   const auto snapshot_id = cur_snapshot_id_++;
 
   // Compute the fingerprint of the snapshot by hashing all clock ids. This is
   // used by the clock pathfinding logic.
   base::Hash hasher;
-  for (const auto& id_and_ts : clocks)
-    hasher.Update(id_and_ts.first);
+  for (const auto& clock : clocks)
+    hasher.Update(clock.clock_id);
   const auto snapshot_hash = static_cast<SnapshotHash>(hasher.digest());
 
   // Add a new entry in each clock's snapshot vector.
-  for (const auto& id_and_ts : clocks) {
-    ClockId clock_id = id_and_ts.first;
-    ClockDomain& clock = clocks_[clock_id];
-    const int64_t timestamp_ns = clock.ToNs(id_and_ts.second);
-    ClockSnapshots& vect = clock.snapshots[snapshot_hash];
+  for (const auto& clock : clocks) {
+    ClockId clock_id = clock.clock_id;
+    ClockDomain& domain = clocks_[clock_id];
+    if (domain.snapshots.empty()) {
+      if (clock.is_incremental && !ClockIsSeqScoped(clock_id)) {
+        PERFETTO_ELOG("Clock sync error: the global clock with id=%" PRIu64
+                      " cannot use incremental encoding; this is only "
+                      "supported for sequence-scoped clocks.",
+                      clock_id);
+        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
+        return;
+      }
+      domain.unit_multiplier_ns = clock.unit_multiplier_ns;
+      domain.is_incremental = clock.is_incremental;
+    } else if (PERFETTO_UNLIKELY(
+                   domain.unit_multiplier_ns != clock.unit_multiplier_ns ||
+                   domain.is_incremental != clock.is_incremental)) {
+      PERFETTO_ELOG("Clock sync error: the clock domain with id=%" PRIu64
+                    " (unit=%" PRIu64
+                    ", incremental=%d), was previously registered with "
+                    "different properties (unit=%" PRIu64 ", incremental=%d).",
+                    clock_id, clock.unit_multiplier_ns, clock.is_incremental,
+                    domain.unit_multiplier_ns, domain.is_incremental);
+      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
+      return;
+    }
+    const int64_t timestamp_ns =
+        clock.absolute_timestamp * domain.unit_multiplier_ns;
+    domain.last_timestamp_ns = timestamp_ns;
+
+    ClockSnapshots& vect = domain.snapshots[snapshot_hash];
+    if (!vect.snapshot_ids.empty() &&
+        PERFETTO_UNLIKELY(vect.snapshot_ids.back() == snapshot_id)) {
+      PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
+                    " at snapshot %" PRIu32 ".",
+                    clock_id, snapshot_id);
+      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
+      return;
+    }
 
     // Clock ids in the range [64, 128) are sequence-scoped and must be
     // translated to global ids via SeqScopedClockIdToGlobal() before calling
@@ -110,11 +144,11 @@
     auto it2 = it1;
     ++it2;
     for (; it2 != clocks.end(); ++it2) {
-      if (!non_monotonic_clocks_.count(it1->first))
-        graph_.emplace(it1->first, it2->first, snapshot_hash);
+      if (!non_monotonic_clocks_.count(it1->clock_id))
+        graph_.emplace(it1->clock_id, it2->clock_id, snapshot_hash);
 
-      if (!non_monotonic_clocks_.count(it2->first))
-        graph_.emplace(it2->first, it1->first, snapshot_hash);
+      if (!non_monotonic_clocks_.count(it2->clock_id))
+        graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
     }
   }
 }
@@ -176,15 +210,15 @@
 
   // Iterate trough the path found and translate timestamps onto the new clock
   // domain on each step, until the target domain is reached.
-  int64_t ns = GetClock(src_clock_id).ToNs(src_timestamp);
+  int64_t ns = GetClock(src_clock_id)->ToNs(src_timestamp);
   for (uint32_t i = 0; i < path.len; ++i) {
     const ClockGraphEdge edge = path.at(i);
-    const ClockDomain& cur_clock = GetClock(std::get<0>(edge));
-    const ClockDomain& next_clock = GetClock(std::get<1>(edge));
+    ClockDomain* cur_clock = GetClock(std::get<0>(edge));
+    ClockDomain* next_clock = GetClock(std::get<1>(edge));
     const SnapshotHash hash = std::get<2>(edge);
 
     // Find the closest timestamp within the snapshots of the source clock.
-    const ClockSnapshots& cur_snap = cur_clock.GetSnapshot(hash);
+    const ClockSnapshots& cur_snap = cur_clock->GetSnapshot(hash);
     const auto& ts_vec = cur_snap.timestamps_ns;
     auto it = std::upper_bound(ts_vec.begin(), ts_vec.end(), ns);
     if (it != ts_vec.begin())
@@ -199,7 +233,7 @@
     // And use that to retrieve the corresponding time in the next clock domain.
     // The snapshot id must exist in the target clock domain. If it doesn't
     // either the hash logic or the pathfinding logic are bugged.
-    const ClockSnapshots& next_snap = next_clock.GetSnapshot(hash);
+    const ClockSnapshots& next_snap = next_clock->GetSnapshot(hash);
     auto next_it = std::lower_bound(next_snap.snapshot_ids.begin(),
                                     next_snap.snapshot_ids.end(), snapshot_id);
     PERFETTO_DCHECK(next_it != next_snap.snapshot_ids.end() &&
diff --git a/src/trace_processor/clock_tracker.h b/src/trace_processor/clock_tracker.h
index 6c83bb1..c261249 100644
--- a/src/trace_processor/clock_tracker.h
+++ b/src/trace_processor/clock_tracker.h
@@ -124,12 +124,35 @@
     return (static_cast<uint64_t>(seq_id) << 32) | clock_id;
   }
 
+  // Returns whether |global_clock_id| represents a sequence-scoped clock, i.e.
+  // a ClockId returned by SeqScopedClockIdToGlobal().
+  static bool ClockIsSeqScoped(ClockId global_clock_id) {
+    // If the id is > 2**32, this is a sequence-scoped clock id translated into
+    // the global namespace.
+    return (global_clock_id >> 32) > 0;
+  }
+
   explicit ClockTracker(TraceProcessorContext*);
   virtual ~ClockTracker();
 
+  // Clock description and its value in a snapshot.
+  struct ClockValue {
+    ClockValue(ClockId id, int64_t ts) : clock_id(id), absolute_timestamp(ts) {}
+    ClockValue(ClockId id, int64_t ts, int64_t unit, bool incremental)
+        : clock_id(id),
+          absolute_timestamp(ts),
+          unit_multiplier_ns(unit),
+          is_incremental(incremental) {}
+
+    ClockId clock_id;
+    int64_t absolute_timestamp;
+    int64_t unit_multiplier_ns = 1;
+    bool is_incremental = false;
+  };
+
   // Appends a new snapshot for the given clock domains.
   // This is typically called by the code that reads the ClockSnapshot packet.
-  void AddSnapshot(const std::map<ClockId, int64_t>&);
+  void AddSnapshot(const std::vector<ClockValue>&);
 
   base::Optional<int64_t> Convert(ClockId src_clock_id,
                                   int64_t src_timestamp,
@@ -193,8 +216,27 @@
     // One time-series for each hash.
     std::map<SnapshotHash, ClockSnapshots> snapshots;
 
-    // TODO(primiano): support other resolutions.
-    int64_t ToNs(int64_t timestamp) const { return timestamp * 1; }
+    // Multiplier for timestamps given in this domain.
+    int64_t unit_multiplier_ns = 1;
+
+    // Whether this clock domain encodes timestamps as deltas. This is only
+    // supported on sequence-local domains.
+    bool is_incremental = false;
+
+    // If |is_incremental| is true, this stores the most recent absolute
+    // timestamp in nanoseconds.
+    int64_t last_timestamp_ns = 0;
+
+    // Treats |timestamp| as delta timestamp if the clock uses incremental
+    // encoding, and as absolute timestamp otherwise.
+    int64_t ToNs(int64_t timestamp) {
+      if (!is_incremental)
+        return timestamp * unit_multiplier_ns;
+
+      int64_t delta_ns = timestamp * unit_multiplier_ns;
+      last_timestamp_ns += delta_ns;
+      return last_timestamp_ns;
+    }
 
     const ClockSnapshots& GetSnapshot(uint32_t hash) const {
       auto it = snapshots.find(hash);
@@ -208,10 +250,10 @@
 
   ClockPath FindPath(ClockId src, ClockId target);
 
-  const ClockDomain& GetClock(ClockId clock_id) const {
+  ClockDomain* GetClock(ClockId clock_id) {
     auto it = clocks_.find(clock_id);
     PERFETTO_DCHECK(it != clocks_.end());
-    return it->second;
+    return &it->second;
   }
 
   TraceProcessorContext* const context_;
diff --git a/src/trace_processor/clock_tracker_unittest.cc b/src/trace_processor/clock_tracker_unittest.cc
index 824728b..e1628af 100644
--- a/src/trace_processor/clock_tracker_unittest.cc
+++ b/src/trace_processor/clock_tracker_unittest.cc
@@ -158,6 +158,55 @@
   EXPECT_EQ(*ct_.Convert(MONOTONIC_RAW, 753, REALTIME), 753 - 1 - 50 + 9000);
 }
 
+TEST_F(ClockTrackerTest, SequenceScopedClocks) {
+  ct_.AddSnapshot({{MONOTONIC, 1000}, {BOOTTIME, 100000}});
+
+  ClockTracker::ClockId c64_1 = ct_.SeqScopedClockIdToGlobal(1, 64);
+  ClockTracker::ClockId c65_1 = ct_.SeqScopedClockIdToGlobal(1, 65);
+  ClockTracker::ClockId c66_1 = ct_.SeqScopedClockIdToGlobal(1, 66);
+  ClockTracker::ClockId c66_2 = ct_.SeqScopedClockIdToGlobal(2, 64);
+
+  ct_.AddSnapshot(
+      {{MONOTONIC, 10000},
+       {c64_1, 100000},
+       {c65_1, 100, /*unit_multiplier_ns=*/1000, /*is_incremental=*/false},
+       {c66_1, 10, /*unit_multiplier_ns=*/1000, /*is_incremental=*/true}});
+
+  // c64_1 is non-incremental and in nanos.
+  EXPECT_EQ(*ct_.Convert(c64_1, 150000, MONOTONIC), 60000);
+  EXPECT_EQ(*ct_.Convert(c64_1, 150000, BOOTTIME), 159000);
+  EXPECT_EQ(*ct_.ToTraceTime(c64_1, 150000), 159000);
+
+  // c65_1 is non-incremental and in micros.
+  EXPECT_EQ(*ct_.Convert(c65_1, 150, MONOTONIC), 60000);
+  EXPECT_EQ(*ct_.Convert(c65_1, 150, BOOTTIME), 159000);
+  EXPECT_EQ(*ct_.ToTraceTime(c65_1, 150), 159000);
+
+  // c66_1 is incremental and in micros.
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 11 */, MONOTONIC), 11000);
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 12 */, MONOTONIC), 12000);
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 13 */, BOOTTIME), 112000);
+  EXPECT_EQ(*ct_.ToTraceTime(c66_1, 2 /* abs 15 */), 114000);
+
+  ct_.AddSnapshot(
+      {{MONOTONIC, 20000},
+       {c66_1, 20, /*unit_multiplier_ns=*/1000, /*is_incremental=*/true}});
+  ct_.AddSnapshot(
+      {{MONOTONIC, 20000},
+       {c66_2, 20, /*unit_multiplier_ns=*/1000, /*is_incremental=*/true}});
+
+  // c66_1 and c66_2 are both incremental and in micros, but shouldn't affect
+  // each other.
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 21 */, MONOTONIC), 21000);
+  EXPECT_EQ(*ct_.Convert(c66_2, 2 /* abs 22 */, MONOTONIC), 22000);
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 22 */, MONOTONIC), 22000);
+  EXPECT_EQ(*ct_.Convert(c66_2, 2 /* abs 24 */, MONOTONIC), 24000);
+  EXPECT_EQ(*ct_.Convert(c66_1, 1 /* abs 23 */, BOOTTIME), 122000);
+  EXPECT_EQ(*ct_.Convert(c66_2, 2 /* abs 26 */, BOOTTIME), 125000);
+  EXPECT_EQ(*ct_.ToTraceTime(c66_1, 2 /* abs 25 */), 124000);
+  EXPECT_EQ(*ct_.ToTraceTime(c66_2, 4 /* abs 30 */), 129000);
+}
+
 }  // namespace
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/db/bit_vector_benchmark.cc b/src/trace_processor/db/bit_vector_benchmark.cc
index 6c896d1..54c00f9 100644
--- a/src/trace_processor/db/bit_vector_benchmark.cc
+++ b/src/trace_processor/db/bit_vector_benchmark.cc
@@ -22,6 +22,20 @@
 
 using perfetto::trace_processor::BitVector;
 
+bool IsBenchmarkFunctionalOnly() {
+  return getenv("BENCHMARK_FUNCTIONAL_TEST_ONLY") != nullptr;
+}
+
+void BitVectorArgs(benchmark::internal::Benchmark* b) {
+  b->Arg(64);
+
+  if (!IsBenchmarkFunctionalOnly()) {
+    b->Arg(512);
+    b->Arg(8192);
+    b->Arg(123456);
+    b->Arg(1234567);
+  }
+}
 }
 
 static void BM_BitVectorAppendTrue(benchmark::State& state) {
@@ -72,12 +86,7 @@
     benchmark::ClobberMemory();
   }
 }
-BENCHMARK(BM_BitVectorSet)
-    ->Arg(64)
-    ->Arg(512)
-    ->Arg(8192)
-    ->Arg(123456)
-    ->Arg(1234567);
+BENCHMARK(BM_BitVectorSet)->Apply(BitVectorArgs);
 
 static void BM_BitVectorClear(benchmark::State& state) {
   static constexpr uint32_t kRandomSeed = 42;
@@ -107,12 +116,7 @@
     benchmark::ClobberMemory();
   }
 }
-BENCHMARK(BM_BitVectorClear)
-    ->Arg(64)
-    ->Arg(512)
-    ->Arg(8192)
-    ->Arg(123456)
-    ->Arg(1234567);
+BENCHMARK(BM_BitVectorClear)->Apply(BitVectorArgs);
 
 static void BM_BitVectorIndexOfNthSet(benchmark::State& state) {
   static constexpr uint32_t kRandomSeed = 42;
@@ -142,12 +146,7 @@
     pool_idx = (pool_idx + 1) % kPoolSize;
   }
 }
-BENCHMARK(BM_BitVectorIndexOfNthSet)
-    ->Arg(64)
-    ->Arg(512)
-    ->Arg(8192)
-    ->Arg(123456)
-    ->Arg(1234567);
+BENCHMARK(BM_BitVectorIndexOfNthSet)->Apply(BitVectorArgs);
 
 static void BM_BitVectorGetNumBitsSet(benchmark::State& state) {
   static constexpr uint32_t kRandomSeed = 42;
@@ -175,12 +174,7 @@
   }
   PERFETTO_CHECK(res == count);
 }
-BENCHMARK(BM_BitVectorGetNumBitsSet)
-    ->Arg(64)
-    ->Arg(512)
-    ->Arg(8192)
-    ->Arg(123456)
-    ->Arg(1234567);
+BENCHMARK(BM_BitVectorGetNumBitsSet)->Apply(BitVectorArgs);
 
 static void BM_BitVectorResize(benchmark::State& state) {
   static constexpr uint32_t kRandomSeed = 42;
@@ -239,9 +233,4 @@
     benchmark::ClobberMemory();
   }
 }
-BENCHMARK(BM_BitVectorUpdateSetBits)
-    ->Arg(64)
-    ->Arg(512)
-    ->Arg(8192)
-    ->Arg(123456)
-    ->Arg(1234567);
+BENCHMARK(BM_BitVectorUpdateSetBits)->Apply(BitVectorArgs);
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index b2af643..518ac6a 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -142,6 +142,16 @@
     PERFETTO_FATAL("For GCC");
   }
 
+  // Sorts |idx| in ascending or descending order (determined by |desc|) based
+  // on the contents of this column.
+  void StableSort(bool desc, std::vector<uint32_t>* idx) const {
+    if (desc) {
+      StableSort<true /* desc */>(idx);
+    } else {
+      StableSort<false /* desc */>(idx);
+    }
+  }
+
   // Updates the given RowMap by only keeping rows where this column meets the
   // given filter constraint.
   void FilterInto(FilterOp op, SqlValue value, RowMap* rm) const {
@@ -580,6 +590,63 @@
     }
   }
 
+  template <bool desc>
+  void StableSort(std::vector<uint32_t>* out) const {
+    switch (type_) {
+      case ColumnType::kInt32: {
+        if (IsNullable()) {
+          StableSort<desc, int32_t, true /* is_nullable */>(out);
+        } else {
+          StableSort<desc, int32_t, false /* is_nullable */>(out);
+        }
+        break;
+      }
+      case ColumnType::kUint32: {
+        if (IsNullable()) {
+          StableSort<desc, uint32_t, true /* is_nullable */>(out);
+        } else {
+          StableSort<desc, uint32_t, false /* is_nullable */>(out);
+        }
+        break;
+      }
+      case ColumnType::kInt64: {
+        if (IsNullable()) {
+          StableSort<desc, int64_t, true /* is_nullable */>(out);
+        } else {
+          StableSort<desc, int64_t, false /* is_nullable */>(out);
+        }
+        break;
+      }
+      case ColumnType::kString: {
+        row_map().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
+          auto a_str = GetStringPoolStringAtIdx(a_idx);
+          auto b_str = GetStringPoolStringAtIdx(b_idx);
+          return desc ? b_str < a_str : a_str < b_str;
+        });
+        break;
+      }
+      case ColumnType::kId:
+        row_map().StableSort(out, [](uint32_t a_idx, uint32_t b_idx) {
+          return desc ? b_idx < a_idx : a_idx < b_idx;
+        });
+    }
+  }
+
+  template <bool desc, typename T, bool is_nullable>
+  void StableSort(std::vector<uint32_t>* out) const {
+    const auto& sv = sparse_vector<T>();
+    row_map().StableSort(out, [&sv](uint32_t a_idx, uint32_t b_idx) {
+      if (is_nullable) {
+        auto a_val = sv.Get(a_idx);
+        auto b_val = sv.Get(b_idx);
+        return desc ? b_val < a_val : a_val < b_val;
+      }
+      auto a_val = sv.GetNonNull(a_idx);
+      auto b_val = sv.GetNonNull(b_idx);
+      return desc ? b_val < a_val : a_val < b_val;
+    });
+  }
+
   template <typename T>
   static ColumnType ToColumnType() {
     if (std::is_same<T, uint32_t>::value) {
diff --git a/src/trace_processor/db/row_map.h b/src/trace_processor/db/row_map.h
index 53264da..6cbf045 100644
--- a/src/trace_processor/db/row_map.h
+++ b/src/trace_processor/db/row_map.h
@@ -127,6 +127,9 @@
       }
     }
 
+    Iterator(Iterator&&) noexcept = default;
+    Iterator& operator=(Iterator&&) = default;
+
     // Forwards the iterator to the next row of the RowMap.
     void Next() {
       switch (rm_->mode_) {
@@ -190,6 +193,9 @@
     }
 
    private:
+    Iterator(const Iterator&) = delete;
+    Iterator& operator=(const Iterator&) = delete;
+
     // Only one of the below will be non-null depending on the mode of the
     // RowMap.
     std::unique_ptr<RangeIterator> range_it_;
@@ -391,6 +397,18 @@
       return;
     }
 
+    if (mode_ == Mode::kRange && other.mode_ == Mode::kRange) {
+      // If both RowMaps have ranges, we can just take the smallest intersection
+      // of them as the new RowMap.
+      // This case is important to optimize as it comes up with sorted columns.
+      start_idx_ = std::max(start_idx_, other.start_idx_);
+      end_idx_ = std::min(end_idx_, other.end_idx_);
+
+      if (end_idx_ <= start_idx_)
+        *this = RowMap();
+      return;
+    }
+
     // TODO(lalitm): improve efficiency of this if we end up needing it.
     RemoveIf([&other](uint32_t row) { return !other.Contains(row); });
   }
@@ -434,6 +452,26 @@
     }
   }
 
+  template <typename Comparator>
+  void StableSort(std::vector<uint32_t>* out, Comparator c) const {
+    switch (mode_) {
+      case Mode::kRange: {
+        StableSort(out, c, [this](uint32_t off) { return start_idx_ + off; });
+        break;
+      }
+      case Mode::kBitVector: {
+        StableSort(out, c, [this](uint32_t off) {
+          return bit_vector_.IndexOfNthSet(off);
+        });
+        break;
+      }
+      case Mode::kIndexVector: {
+        StableSort(out, c, [this](uint32_t off) { return index_vector_[off]; });
+        break;
+      }
+    }
+  }
+
   // Returns the iterator over the rows in this RowMap.
   Iterator IterateRows() const { return Iterator(this); }
 
@@ -530,6 +568,13 @@
     }
   }
 
+  template <typename Comparator, typename Indexer>
+  void StableSort(std::vector<uint32_t>* out, Comparator c, Indexer i) const {
+    std::stable_sort(
+        out->begin(), out->end(),
+        [&c, &i](uint32_t a, uint32_t b) { return c(i(a), i(b)); });
+  }
+
   RowMap SelectRowsSlow(const RowMap& selector) const;
 
   Mode mode_ = Mode::kRange;
diff --git a/src/trace_processor/db/table.cc b/src/trace_processor/db/table.cc
index 3b22356..d23ba87 100644
--- a/src/trace_processor/db/table.cc
+++ b/src/trace_processor/db/table.cc
@@ -96,17 +96,36 @@
   std::vector<uint32_t> idx(size_);
   std::iota(idx.begin(), idx.end(), 0);
 
-  // Sort the row indices according to the given order by constraints.
-  std::sort(idx.begin(), idx.end(), [this, &od](uint32_t a, uint32_t b) {
-    for (const Order& o : od) {
-      const Column& col = columns_[o.col_idx];
-      int cmp =
-          col.Get(a) < col.Get(b) ? -1 : (col.Get(b) < col.Get(a) ? 1 : 0);
-      if (cmp != 0)
-        return o.desc ? cmp > 0 : cmp < 0;
-    }
-    return false;
-  });
+  // As our data is columnar, it's always more efficient to sort one column
+  // at a time rather than try and sort lexiographically all at once.
+  // To preserve correctness, we need to stably sort the index vector once
+  // for each order by in *reverse* order. Reverse order is important as it
+  // preserves the lexiographical property.
+  //
+  // For example, suppose we have the following:
+  // Table {
+  //   Column x;
+  //   Column y
+  //   Column z;
+  // }
+  //
+  // Then, to sort "y asc, x desc", we could do one of two things:
+  //  1) sort the index vector all at once and on each index, we compare
+  //     y then z. This is slow as the data is columnar and we need to
+  //     repeatedly branch inside each column.
+  //  2) we can stably sort first on x desc and then sort on y asc. This will
+  //     first put all the x in the correct order such that when we sort on
+  //     y asc, we will have the correct order of x where y is the same (since
+  //     the sort is stable).
+  //
+  // TODO(lalitm): it is possible that we could sort the last constraint (i.e.
+  // the first constraint in the below loop) in a non-stable way. However, this
+  // is more subtle than it appears as we would then need special handling where
+  // there are order bys on a column which is already sorted (e.g. ts, id).
+  // Investigate whether the performance gains from this are worthwhile.
+  for (auto it = od.rbegin(); it != od.rend(); ++it) {
+    columns_[it->col_idx].StableSort(it->desc, &idx);
+  }
 
   // Return a copy of this table with the RowMaps using the computed ordered
   // RowMap.
diff --git a/src/trace_processor/db/table.h b/src/trace_processor/db/table.h
index e9410b4..a5e71b9 100644
--- a/src/trace_processor/db/table.h
+++ b/src/trace_processor/db/table.h
@@ -43,6 +43,9 @@
       }
     }
 
+    Iterator(Iterator&&) noexcept = default;
+    Iterator& operator=(Iterator&&) = default;
+
     // Advances the iterator to the next row of the table.
     void Next() {
       for (auto& it : its_) {
@@ -60,6 +63,9 @@
     }
 
    private:
+    Iterator(const Iterator&) = delete;
+    Iterator& operator=(const Iterator&) = delete;
+
     const Table* table_ = nullptr;
     std::vector<RowMap::Iterator> its_;
   };
diff --git a/src/trace_processor/importers/proto/graphics_event_parser.cc b/src/trace_processor/importers/proto/graphics_event_parser.cc
index f891c83..a1e38cb 100644
--- a/src/trace_processor/importers/proto/graphics_event_parser.cc
+++ b/src/trace_processor/importers/proto/graphics_event_parser.cc
@@ -309,37 +309,95 @@
 void GraphicsEventParser::UpdateVulkanMemoryAllocationCounters(
     UniquePid upid,
     const VulkanMemoryEvent::Decoder& event) {
-  if (event.source() == VulkanMemoryEvent::SOURCE_DRIVER) {
-    auto allocation_scope = static_cast<VulkanMemoryEvent::AllocationScope>(
-        event.allocation_scope());
-    if (event.operation() == VulkanMemoryEvent::OP_CREATE) {
-      vulkan_driver_memory_counters_[allocation_scope] += event.memory_size();
-    } else if (event.operation() == VulkanMemoryEvent::OP_DESTROY) {
-      vulkan_driver_memory_counters_[allocation_scope] -= event.memory_size();
-    }
-    StringId track_id =
-        context_->vulkan_memory_tracker->FindAllocationScopeCounterString(
-            allocation_scope);
-    TrackId track =
-        context_->track_tracker->InternProcessCounterTrack(track_id, upid);
-    context_->event_tracker->PushCounter(
-        event.timestamp(), vulkan_driver_memory_counters_[allocation_scope],
-        track);
-  } else if (event.source() == VulkanMemoryEvent::SOURCE_BUFFER ||
-             event.source() == VulkanMemoryEvent::SOURCE_IMAGE) {
-    auto memory_type = static_cast<uint32_t>(event.memory_type());
-    if (event.operation() == VulkanMemoryEvent::OP_BIND) {
-      vulkan_device_memory_counters_[memory_type] += event.memory_size();
-    } else if (event.operation() == VulkanMemoryEvent::OP_DESTROY_BOUND) {
-      vulkan_device_memory_counters_[memory_type] -= event.memory_size();
-    }
-    StringId track_id =
-        context_->vulkan_memory_tracker->FindMemoryTypeCounterString(
-            memory_type);
-    TrackId track =
-        context_->track_tracker->InternProcessCounterTrack(track_id, upid);
-    context_->event_tracker->PushCounter(
-        event.timestamp(), vulkan_device_memory_counters_[memory_type], track);
+  StringId track_id = kNullStringId;
+  TrackId track = UINT32_MAX;
+  auto allocation_scope = VulkanMemoryEvent::SCOPE_UNSPECIFIED;
+  uint32_t memory_type = UINT32_MAX;
+  switch (event.source()) {
+    case VulkanMemoryEvent::SOURCE_DRIVER:
+      allocation_scope = static_cast<VulkanMemoryEvent::AllocationScope>(
+          event.allocation_scope());
+      switch (event.operation()) {
+        case VulkanMemoryEvent::OP_CREATE:
+          vulkan_driver_memory_counters_[allocation_scope] +=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_DESTROY:
+          vulkan_driver_memory_counters_[allocation_scope] -=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_UNSPECIFIED:
+        case VulkanMemoryEvent::OP_BIND:
+        case VulkanMemoryEvent::OP_DESTROY_BOUND:
+        case VulkanMemoryEvent::OP_ANNOTATIONS:
+          return;
+      }
+      track_id =
+          context_->vulkan_memory_tracker->FindAllocationScopeCounterString(
+              allocation_scope);
+      track =
+          context_->track_tracker->InternProcessCounterTrack(track_id, upid);
+      context_->event_tracker->PushCounter(
+          event.timestamp(), vulkan_driver_memory_counters_[allocation_scope],
+          track);
+      break;
+
+    case VulkanMemoryEvent::SOURCE_DEVICE_MEMORY:
+      memory_type = static_cast<uint32_t>(event.memory_type());
+      switch (event.operation()) {
+        case VulkanMemoryEvent::OP_CREATE:
+          vulkan_device_memory_counters_allocate_[memory_type] +=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_DESTROY:
+          vulkan_device_memory_counters_allocate_[memory_type] -=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_UNSPECIFIED:
+        case VulkanMemoryEvent::OP_BIND:
+        case VulkanMemoryEvent::OP_DESTROY_BOUND:
+        case VulkanMemoryEvent::OP_ANNOTATIONS:
+          return;
+      }
+      track_id = context_->vulkan_memory_tracker->FindMemoryTypeCounterString(
+          memory_type,
+          VulkanMemoryTracker::DeviceCounterType::kAllocationCounter);
+      track =
+          context_->track_tracker->InternProcessCounterTrack(track_id, upid);
+      context_->event_tracker->PushCounter(
+          event.timestamp(),
+          vulkan_device_memory_counters_allocate_[memory_type], track);
+      break;
+
+    case VulkanMemoryEvent::SOURCE_BUFFER:
+    case VulkanMemoryEvent::SOURCE_IMAGE:
+      memory_type = static_cast<uint32_t>(event.memory_type());
+      switch (event.operation()) {
+        case VulkanMemoryEvent::OP_BIND:
+          vulkan_device_memory_counters_bind_[memory_type] +=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_DESTROY_BOUND:
+          vulkan_device_memory_counters_bind_[memory_type] -=
+              event.memory_size();
+          break;
+        case VulkanMemoryEvent::OP_UNSPECIFIED:
+        case VulkanMemoryEvent::OP_CREATE:
+        case VulkanMemoryEvent::OP_DESTROY:
+        case VulkanMemoryEvent::OP_ANNOTATIONS:
+          return;
+      }
+      track_id = context_->vulkan_memory_tracker->FindMemoryTypeCounterString(
+          memory_type, VulkanMemoryTracker::DeviceCounterType::kBindCounter);
+      track =
+          context_->track_tracker->InternProcessCounterTrack(track_id, upid);
+      context_->event_tracker->PushCounter(
+          event.timestamp(), vulkan_device_memory_counters_bind_[memory_type],
+          track);
+      break;
+    case VulkanMemoryEvent::SOURCE_UNSPECIFIED:
+    case VulkanMemoryEvent::SOURCE_DEVICE:
+      return;
   }
 }
 
diff --git a/src/trace_processor/importers/proto/graphics_event_parser.h b/src/trace_processor/importers/proto/graphics_event_parser.h
index 489933f..a5f7f4a 100644
--- a/src/trace_processor/importers/proto/graphics_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_event_parser.h
@@ -77,7 +77,9 @@
                      ProtoEnumHasher>
       vulkan_driver_memory_counters_;
   std::unordered_map<uint32_t /*memory_type*/, int64_t /*counter_value*/>
-      vulkan_device_memory_counters_;
+      vulkan_device_memory_counters_allocate_;
+  std::unordered_map<uint32_t /*memory_type*/, int64_t /*counter_value*/>
+      vulkan_device_memory_counters_bind_;
   // For GpuLog
   const StringId gpu_log_track_name_id_;
   const StringId gpu_log_scope_id_;
diff --git a/src/trace_processor/importers/proto/heap_graph_module.cc b/src/trace_processor/importers/proto/heap_graph_module.cc
index 50bba45..7216d90 100644
--- a/src/trace_processor/importers/proto/heap_graph_module.cc
+++ b/src/trace_processor/importers/proto/heap_graph_module.cc
@@ -65,6 +65,28 @@
   }
 }
 
+// Iterate over a repeated field of varints, independent of whether it is
+// packed or not.
+template <int32_t field_no, typename T, typename F>
+bool ForEachVarInt(const T& decoder, F fn) {
+  auto field = decoder.template at<field_no>();
+  bool parse_error = false;
+  if (field.type() == protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+    // packed repeated
+    auto it = decoder.template GetPackedRepeated<
+        ::protozero::proto_utils::ProtoWireType::kVarInt, uint64_t>(
+        field_no, &parse_error);
+    for (; it; ++it)
+      fn(*it);
+  } else {
+    // non-packed repeated
+    auto it = decoder.template GetRepeated<uint64_t>(field_no);
+    for (; it; ++it)
+      fn(*it);
+  }
+  return parse_error;
+}
+
 }  // namespace
 
 void HeapGraphModule::ParseHeapGraph(int64_t ts, protozero::ConstBytes blob) {
@@ -78,21 +100,37 @@
     obj.object_id = object.id();
     obj.self_size = object.self_size();
     obj.type_id = object.type_id();
-    auto ref_field_ids_it = object.reference_field_id();
-    auto ref_object_ids_it = object.reference_object_id();
-    for (; ref_field_ids_it && ref_object_ids_it;
-         ++ref_field_ids_it, ++ref_object_ids_it) {
-      HeapGraphTracker::SourceObject::Reference ref;
-      ref.field_name_id = *ref_field_ids_it;
-      ref.owned_object_id = *ref_object_ids_it;
-      obj.references.emplace_back(std::move(ref));
+
+    std::vector<uint64_t> field_ids;
+    std::vector<uint64_t> object_ids;
+
+    bool parse_error = ForEachVarInt<
+        protos::pbzero::HeapGraphObject::kReferenceFieldIdFieldNumber>(
+        object, [&field_ids](uint64_t value) { field_ids.push_back(value); });
+
+    if (!parse_error) {
+      parse_error = ForEachVarInt<
+          protos::pbzero::HeapGraphObject::kReferenceObjectIdFieldNumber>(
+          object,
+          [&object_ids](uint64_t value) { object_ids.push_back(value); });
     }
 
-    if (ref_field_ids_it || ref_object_ids_it) {
-      context_->storage->IncrementIndexedStats(stats::heap_graph_missing_packet,
-                                               static_cast<int>(upid));
+    if (parse_error) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
+      break;
+    }
+    if (field_ids.size() != object_ids.size()) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
       continue;
     }
+    for (size_t i = 0; i < field_ids.size(); ++i) {
+      HeapGraphTracker::SourceObject::Reference ref;
+      ref.field_name_id = field_ids[i];
+      ref.owned_object_id = object_ids[i];
+      obj.references.emplace_back(std::move(ref));
+    }
     context_->heap_graph_tracker->AddObject(upid, ts, std::move(obj));
   }
   for (auto it = heap_graph.type_names(); it; ++it) {
@@ -118,8 +156,16 @@
 
     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);
+    bool parse_error =
+        ForEachVarInt<protos::pbzero::HeapGraphRoot::kObjectIdsFieldNumber>(
+            entry, [&src_root](uint64_t value) {
+              src_root.object_ids.emplace_back(value);
+            });
+    if (parse_error) {
+      context_->storage->IncrementIndexedStats(
+          stats::heap_graph_malformed_packet, static_cast<int>(upid));
+      break;
+    }
     context_->heap_graph_tracker->AddRoot(upid, ts, std::move(src_root));
   }
   if (!heap_graph.continued()) {
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index e2d6aef..43ccee0 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -80,8 +80,11 @@
     }
     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, 0, -1, 0, it->second,
-         base::nullopt});
+         static_cast<int64_t>(obj.self_size), /*retained_size=*/-1,
+         /*unique_retained_size=*/-1, /*reference_set_id=*/-1,
+         /*reachable=*/0, /*type_name=*/it->second,
+         /*deobfuscated_type_name=*/base::nullopt,
+         /*root_type=*/base::nullopt});
     int64_t row = context_->storage->heap_graph_object_table().size() - 1;
     object_id_to_row_.emplace(obj.object_id, row);
     walker_.AddNode(row, obj.self_size);
@@ -95,6 +98,7 @@
 
     int64_t reference_set_id =
         context_->storage->heap_graph_reference_table().size();
+    std::set<int64_t> seen_owned;
     for (const SourceObject::Reference& ref : obj.references) {
       // This is true for unset reference fields.
       if (ref.owned_object_id == 0)
@@ -107,7 +111,10 @@
         continue;
 
       int64_t owned_row = it->second;
-      walker_.AddEdge(owner_row, owned_row);
+      bool inserted;
+      std::tie(std::ignore, inserted) = seen_owned.emplace(owned_row);
+      if (inserted)
+        walker_.AddEdge(owner_row, owned_row);
 
       auto field_name_it = interned_field_names_.find(ref.field_name_id);
       if (field_name_it == interned_field_names_.end()) {
@@ -118,7 +125,8 @@
       }
       StringPool::Id field_name = field_name_it->second;
       context_->storage->mutable_heap_graph_reference_table()->Insert(
-          {reference_set_id, owner_row, owned_row, field_name});
+          {reference_set_id, owner_row, owned_row, field_name,
+           /*deobfuscated_field_name=*/base::nullopt});
     }
     context_->storage->mutable_heap_graph_object_table()
         ->mutable_reference_set_id()
diff --git a/src/trace_processor/importers/proto/heap_graph_walker.cc b/src/trace_processor/importers/proto/heap_graph_walker.cc
index 8655d85..b512571 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_walker.cc
@@ -66,8 +66,11 @@
 }
 
 void HeapGraphWalker::AddEdge(int64_t owner_row, int64_t owned_row) {
-  GetNode(owner_row).children.emplace(&GetNode(owned_row));
-  GetNode(owned_row).parents.emplace(&GetNode(owner_row));
+  Node& owner_node = GetNode(owner_row);
+  Node& owned_node = GetNode(owned_row);
+
+  owner_node.children.emplace_back(&owned_node);
+  owned_node.parents.emplace_back(&owner_node);
 }
 
 void HeapGraphWalker::MarkRoot(int64_t row) {
@@ -268,23 +271,43 @@
 }
 
 void HeapGraphWalker::FindSCC(Node* node) {
-  node->node_index = node->lowlink = next_node_index_++;
-  node_stack_.push_back(node);
-  node->on_stack = true;
-  for (Node* child : node->children) {
-    PERFETTO_CHECK(child->reachable);
-    if (child->node_index == 0) {
-      FindSCC(child);
-      if (child->lowlink < node->lowlink)
-        node->lowlink = child->lowlink;
-    } else if (child->on_stack) {
-      if (child->node_index < node->lowlink)
+  std::vector<Node*> walk_stack;
+  std::vector<size_t> walk_child;
+
+  walk_stack.emplace_back(node);
+  walk_child.emplace_back(0);
+
+  while (!walk_stack.empty()) {
+    node = walk_stack.back();
+    size_t& child_idx = walk_child.back();
+
+    if (child_idx == 0) {
+      node->node_index = node->lowlink = next_node_index_++;
+      node_stack_.push_back(node);
+      node->on_stack = true;
+    } else {
+      Node* prev_child = node->children[child_idx - 1];
+      if (prev_child->node_index > node->node_index &&
+          prev_child->lowlink < node->lowlink)
+        node->lowlink = prev_child->lowlink;
+    }
+
+    if (child_idx == node->children.size()) {
+      if (node->lowlink == node->node_index)
+        FoundSCC(node);
+      walk_stack.pop_back();
+      walk_child.pop_back();
+    } else {
+      Node* child = node->children[child_idx++];
+      PERFETTO_CHECK(child->reachable);
+      if (child->node_index == 0) {
+        walk_stack.emplace_back(child);
+        walk_child.emplace_back(0);
+      } else if (child->on_stack && child->node_index < node->lowlink) {
         node->lowlink = child->node_index;
+      }
     }
   }
-
-  if (node->lowlink == node->node_index)
-    FoundSCC(node);
 }
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/heap_graph_walker.h b/src/trace_processor/importers/proto/heap_graph_walker.h
index b23f2a3..c05c6df 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker.h
+++ b/src/trace_processor/importers/proto/heap_graph_walker.h
@@ -120,11 +120,8 @@
 
  private:
   struct Node {
-    // These are sets to conveniently get rid of double edges between nodes.
-    // We do not care if an object owns another object via multiple references
-    // or only one.
-    std::set<Node*> children;
-    std::set<Node*> parents;
+    std::vector<Node*> children;
+    std::vector<Node*> parents;
     uint64_t self_size = 0;
     uint64_t retained_size = 0;
 
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 0d184a4..f8c8bdf 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -2266,10 +2266,9 @@
   context_.sorter.reset(new TraceSorter(
       &context_, std::numeric_limits<int64_t>::max() /*window size*/));
 
-  std::map<ClockTracker::ClockId, int64_t> clock_map;
-  clock_map[protos::pbzero::ClockSnapshot::Clock::BOOTTIME] = 0u;
-  clock_map[protos::pbzero::ClockSnapshot::Clock::MONOTONIC] = 1000000u;
-  clock_->AddSnapshot(clock_map);
+  clock_->AddSnapshot(
+      {{protos::pbzero::ClockSnapshot::Clock::BOOTTIME, 0},
+       {protos::pbzero::ClockSnapshot::Clock::MONOTONIC, 1000000}});
 
   {
     auto* packet = trace_.add_packet();
diff --git a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
index 013bc81..44e4266 100644
--- a/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
+++ b/src/trace_processor/importers/proto/proto_trace_tokenizer.cc
@@ -413,7 +413,7 @@
 
 util::Status ProtoTraceTokenizer::ParseClockSnapshot(ConstBytes blob,
                                                      uint32_t seq_id) {
-  std::map<ClockTracker::ClockId, int64_t> clock_map;
+  std::vector<ClockTracker::ClockValue> clocks;
   protos::pbzero::ClockSnapshot::Decoder evt(blob.data, blob.size);
   for (auto it = evt.clocks(); it; ++it) {
     protos::pbzero::ClockSnapshot::Clock::Decoder clk(*it);
@@ -427,9 +427,14 @@
       }
       clock_id = ClockTracker::SeqScopedClockIdToGlobal(seq_id, clk.clock_id());
     }
-    clock_map[clock_id] = static_cast<int64_t>(clk.timestamp());
+    int64_t unit_multiplier_ns =
+        clk.unit_multiplier_ns()
+            ? static_cast<int64_t>(clk.unit_multiplier_ns())
+            : 1;
+    clocks.emplace_back(clock_id, clk.timestamp(), unit_multiplier_ns,
+                        clk.is_incremental());
   }
-  context_->clock_tracker->AddSnapshot(clock_map);
+  context_->clock_tracker->AddSnapshot(clocks);
   return util::OkStatus();
 }
 
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 14afab1..e93578c 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -212,7 +212,12 @@
     } else {
       auto args = proc.cmdline();
       base::StringView argv0 = args ? *args : base::StringView();
-      context_->process_tracker->SetProcessMetadata(pid, ppid, argv0);
+      UniquePid upid =
+          context_->process_tracker->SetProcessMetadata(pid, ppid, argv0);
+      if (proc.has_uid()) {
+        context_->process_tracker->SetProcessUid(
+            upid, static_cast<uint32_t>(proc.uid()));
+      }
     }
   }
 
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
index 28d6f01..a5b92bc 100644
--- a/src/trace_processor/metrics/BUILD.gn
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -22,7 +22,6 @@
   "android/android_cpu_agg.sql",
   "android/android_mem.sql",
   "android/android_mem_unagg.sql",
-  "android/android_process_growth.sql",
   "android/android_ion.sql",
   "android/android_lmk.sql",
   "android/android_powrails.sql",
@@ -35,6 +34,7 @@
   "android/java_heap_stats.sql",
   "android/process_unagg_mem_view.sql",
   "android/process_mem.sql",
+  "android/process_metadata.sql",
   "android/mem_stats_priority_breakdown.sql",
   "android/span_view_stats.sql",
   "android/upid_span_view.sql",
diff --git a/src/trace_processor/metrics/android/android_package_list.sql b/src/trace_processor/metrics/android/android_package_list.sql
index ff9bbfe..7ca9c15 100644
--- a/src/trace_processor/metrics/android/android_package_list.sql
+++ b/src/trace_processor/metrics/android/android_package_list.sql
@@ -15,30 +15,41 @@
 --
 
 -- Get distinct packages list
+DROP VIEW IF EXISTS package_arg_ids;
+
 CREATE VIEW package_arg_ids AS
 SELECT int_value AS arg_set_id
 FROM metadata WHERE name = 'android_packages_list';
 
 -- Generate a table mapping package names to their attributes
+DROP VIEW IF EXISTS package_args;
+
 CREATE VIEW package_args AS
 SELECT arg_set_id, key, string_value, int_value
 FROM package_arg_ids JOIN args USING(arg_set_id);
 
+DROP TABLE IF EXISTS package_list;
+
 CREATE TABLE package_list(
   package_name TEXT PRIMARY KEY,
   uid INT,
-  version_code INT
+  version_code INT,
+  debuggable INT
 );
 
 INSERT OR REPLACE INTO package_list
-SELECT names.name, uids.uid, versions.version
+SELECT names.name, uids.uid, versions.version, debuggable.is_debug
 FROM
   (SELECT arg_set_id, string_value name FROM package_args WHERE key = 'name')
     AS names
   JOIN (SELECT arg_set_id, int_value uid FROM package_args WHERE key = 'uid')
     AS uids USING (arg_set_id)
   JOIN (SELECT arg_set_id, int_value version FROM package_args WHERE key = 'version_code')
-    AS versions USING (arg_set_id);
+    AS versions USING (arg_set_id)
+  JOIN (SELECT arg_set_id, int_value is_debug FROM package_args WHERE key = 'debuggable')
+    AS debuggable USING (arg_set_id);
+
+DROP VIEW IF EXISTS android_package_list_output;
 
 CREATE VIEW android_package_list_output AS
 SELECT AndroidPackageList(
diff --git a/src/trace_processor/metrics/android/android_process_growth.sql b/src/trace_processor/metrics/android/android_process_growth.sql
deleted file mode 100644
index 956ce92..0000000
--- a/src/trace_processor/metrics/android/android_process_growth.sql
+++ /dev/null
@@ -1,69 +0,0 @@
---
--- Copyright 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
---
---     https://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
-
-SELECT RUN_METRIC('android/process_mem.sql');
-
-CREATE VIEW malloc_memory_delta AS
-SELECT upid, SUM(size) AS delta
-FROM heap_profile_allocation
-GROUP BY 1;
-
-CREATE VIEW malloc_memory_allocated AS
-SELECT upid, SUM(size) AS total
-FROM heap_profile_allocation
-WHERE size > 0
-GROUP BY 1;
-
-CREATE VIEW anon_and_swap_delta AS
-SELECT DISTINCT
-  upid,
-  FIRST_VALUE(anon_and_swap_val) OVER upid_window AS start_val,
-  LAST_VALUE(anon_and_swap_val) OVER upid_window AS end_val
-FROM anon_and_swap_span
-WINDOW upid_window AS (
-  PARTITION BY upid
-  ORDER BY ts
-  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
-);
-
-CREATE VIEW process_growth AS
-SELECT
-  process.pid AS pid,
-  process.name AS process_name,
-  CAST(asd.start_val AS BIG INT) AS anon_and_swap_start_value,
-  CAST(asd.end_val - asd.start_val AS BIG INT) AS anon_and_swap_change,
-  malloc_memory_delta.delta AS malloc_memory_delta,
-  malloc_memory_allocated.total AS malloc_memory_total
-FROM anon_and_swap_delta AS asd
-JOIN process USING (upid)
-LEFT JOIN malloc_memory_delta USING (upid)
-LEFT JOIN malloc_memory_allocated USING (upid);
-
-CREATE VIEW instance_metrics_proto AS
-SELECT AndroidProcessGrowth_InstanceMetrics(
-  'pid', pid,
-  'process_name', process_name,
-  'anon_and_swap_start_value', anon_and_swap_start_value,
-  'anon_and_swap_change_bytes', anon_and_swap_change,
-  'malloc_memory_change_bytes', malloc_memory_delta,
-  'malloc_memory_total_allocated_bytes', malloc_memory_total
-) AS instance_metric
-FROM process_growth;
-
-CREATE VIEW android_process_growth_output AS
-SELECT AndroidProcessGrowth(
-  'instance_metrics', (SELECT RepeatedField(instance_metric) FROM instance_metrics_proto)
-);
diff --git a/src/trace_processor/metrics/android/heap_profile_callsites.sql b/src/trace_processor/metrics/android/heap_profile_callsites.sql
index ce2aeb4..f84a8ca 100644
--- a/src/trace_processor/metrics/android/heap_profile_callsites.sql
+++ b/src/trace_processor/metrics/android/heap_profile_callsites.sql
@@ -14,6 +14,8 @@
 -- limitations under the License.
 --
 
+SELECT RUN_METRIC('android/process_metadata.sql');
+
 CREATE VIEW memory_delta AS
 SELECT upid, SUM(size) AS delta
 FROM heap_profile_allocation
@@ -216,6 +218,7 @@
 SELECT HeapProfileCallsites_InstanceStats(
     'pid', process.pid,
     'process_name', process.name,
+    'process', process_metadata.metadata,
     'callsites', repeated_callsite_proto,
     'profile_delta_bytes', memory_delta.delta,
     'profile_total_bytes', memory_total.total
@@ -223,7 +226,8 @@
 FROM process_callsite_proto
 JOIN memory_total USING (upid)
 JOIN memory_delta USING (upid)
-JOIN process USING (upid);
+JOIN process USING (upid)
+JOIN process_metadata USING (upid);
 
 CREATE VIEW heap_profile_callsites_output AS
 SELECT HeapProfileCallsites(
diff --git a/src/trace_processor/metrics/android/java_heap_stats.sql b/src/trace_processor/metrics/android/java_heap_stats.sql
index d8f2f34..e5d80b2 100644
--- a/src/trace_processor/metrics/android/java_heap_stats.sql
+++ b/src/trace_processor/metrics/android/java_heap_stats.sql
@@ -14,6 +14,8 @@
 -- limitations under the License.
 --
 
+SELECT RUN_METRIC('android/process_metadata.sql');
+
 CREATE VIEW total_size_samples AS
 SELECT upid, graph_sample_ts, SUM(self_size) AS total_size
 FROM heap_graph_object
@@ -43,16 +45,16 @@
 CREATE TABLE heap_graph_instance_stats AS
 SELECT
   upid,
-  process.name process_name,
+  process_metadata.metadata AS process_metadata,
   RepeatedField(sample_proto) AS sample_protos
-FROM heap_graph_sample_protos JOIN process USING (upid)
+FROM heap_graph_sample_protos JOIN process_metadata USING (upid)
 GROUP BY 1, 2;
 
 CREATE VIEW java_heap_stats_output AS
 SELECT JavaHeapStats(
   'instance_stats', RepeatedField(JavaHeapStats_InstanceStats(
     'upid', upid,
-    'process_name', process_name,
+    'process', process_metadata,
     'samples', sample_protos
   )))
 FROM heap_graph_instance_stats;
diff --git a/src/trace_processor/metrics/android/process_metadata.sql b/src/trace_processor/metrics/android/process_metadata.sql
new file mode 100644
index 0000000..59e86bd
--- /dev/null
+++ b/src/trace_processor/metrics/android/process_metadata.sql
@@ -0,0 +1,31 @@
+--
+-- Copyright 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
+--
+--     https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+SELECT RUN_METRIC('android/android_package_list.sql');
+
+DROP TABLE IF EXISTS process_metadata;
+
+CREATE TABLE process_metadata AS
+SELECT
+  process.upid,
+  AndroidProcessMetadata(
+    'name', process.name,
+    'uid', uid,
+    'package_name', plist.package_name,
+    'apk_version_code', plist.version_code,
+    'debuggable', plist.debuggable
+  ) AS metadata
+FROM process LEFT JOIN package_list plist USING (uid);
diff --git a/src/trace_processor/metrics/metrics.descriptor.h b/src/trace_processor/metrics/metrics.descriptor.h
index df7696c..9507204 100644
--- a/src/trace_processor/metrics/metrics.descriptor.h
+++ b/src/trace_processor/metrics/metrics.descriptor.h
@@ -12,14 +12,14 @@
 // SHA1(tools/gen_binary_descriptors)
 // 192b582ae52bb07b3d3ba66a94bcfd3127a5f42f
 // SHA1(protos/perfetto/metrics/metrics.proto)
-// 4279eeace6a7d9647e484e65b8265ea211a02b6c
+// fb0504ef20a790f031fc622ba1b9312cb97d67a6
 
 // This is the proto Metrics encoded as a ProtoFileDescriptor to allow
 // for reflection without libprotobuf full/non-lite protos.
 
 namespace perfetto {
 
-constexpr std::array<uint8_t, 10312> kMetricsDescriptor{
+constexpr std::array<uint8_t, 10105> kMetricsDescriptor{
     {0x0a, 0x98, 0x03, 0x0a, 0x31, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
      0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
      0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
@@ -262,470 +262,460 @@
      0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
      0x6f, 0x6f, 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05,
      0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52,
-     0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0x90,
-     0x04, 0x0a, 0x34, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65,
+     0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xaf,
+     0x02, 0x0a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65,
      0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-     0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x70,
-     0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x77, 0x74,
-     0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72,
-     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
-     0x22, 0xc2, 0x03, 0x0a, 0x14, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-     0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x77, 0x74,
-     0x68, 0x12, 0x60, 0x0a, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
-     0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20,
-     0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
-     0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61,
-     0x6e, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x0f,
-     0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x73, 0x1a, 0xc7, 0x02, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x74,
-     0x61, 0x6e, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
-     0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
-     0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f,
-     0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
-     0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
-     0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x19, 0x61, 0x6e, 0x6f, 0x6e,
-     0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x73, 0x74,
-     0x61, 0x72, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20,
-     0x01, 0x28, 0x03, 0x52, 0x15, 0x61, 0x6e, 0x6f, 0x6e, 0x41, 0x6e, 0x64,
-     0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, 0x56, 0x61, 0x6c,
-     0x75, 0x65, 0x12, 0x3a, 0x0a, 0x1a, 0x61, 0x6e, 0x6f, 0x6e, 0x5f, 0x61,
-     0x6e, 0x64, 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x63, 0x68, 0x61, 0x6e,
-     0x67, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01,
-     0x28, 0x03, 0x52, 0x16, 0x61, 0x6e, 0x6f, 0x6e, 0x41, 0x6e, 0x64, 0x53,
-     0x77, 0x61, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x79, 0x74,
-     0x65, 0x73, 0x12, 0x3b, 0x0a, 0x1a, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
-     0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x6e,
-     0x67, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01,
-     0x28, 0x03, 0x52, 0x17, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x4d, 0x65,
-     0x6d, 0x6f, 0x72, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x79,
-     0x74, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x23, 0x6d, 0x61, 0x6c, 0x6c, 0x6f,
-     0x63, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x6f, 0x74,
-     0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, 0x64,
-     0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03,
-     0x52, 0x1f, 0x6d, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x4d, 0x65, 0x6d, 0x6f,
-     0x72, 0x79, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63,
-     0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x02, 0x48,
-     0x03, 0x0a, 0xaf, 0x02, 0x0a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
-     0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
-     0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-     0x64, 0x2f, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66,
-     0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22,
-     0xe5, 0x01, 0x0a, 0x10, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49,
-     0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x40, 0x0a, 0x06,
-     0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
-     0x32, 0x28, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
-     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f,
-     0x69, 0x64, 0x49, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e,
-     0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x52, 0x06, 0x62, 0x75, 0x66, 0x66,
-     0x65, 0x72, 0x1a, 0x8e, 0x01, 0x0a, 0x06, 0x42, 0x75, 0x66, 0x66, 0x65,
-     0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
-     0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a,
-     0x0e, 0x61, 0x76, 0x67, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79,
-     0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x61,
-     0x76, 0x67, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12,
-     0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f,
-     0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52,
-     0x0c, 0x6d, 0x69, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65,
-     0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x69, 0x7a,
-     0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
-     0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79,
-     0x74, 0x65, 0x73, 0x42, 0x02, 0x48, 0x03, 0x0a, 0x95, 0x02, 0x0a, 0x30,
-     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
-     0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6c, 0x6d, 0x6b, 0x5f,
-     0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-     0x12, 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70,
-     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x10, 0x41, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
-     0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
-     0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
-     0x4e, 0x0a, 0x0c, 0x62, 0x79, 0x5f, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63,
-     0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e,
+     0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x69,
+     0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72,
+     0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
+     0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22, 0xe5, 0x01, 0x0a,
+     0x10, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x4d,
+     0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x40, 0x0a, 0x06, 0x62, 0x75, 0x66,
+     0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e,
      0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c,
-     0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x42, 0x79, 0x4f,
-     0x6f, 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x0a, 0x62, 0x79, 0x4f,
-     0x6f, 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x46, 0x0a, 0x0a, 0x42,
-     0x79, 0x4f, 0x6f, 0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x0a,
-     0x0d, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x61,
-     0x64, 0x6a, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6f,
-     0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x41, 0x64, 0x6a, 0x12, 0x14, 0x0a,
-     0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
-     0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x02, 0x48, 0x03, 0x0a,
-     0xf4, 0x02, 0x0a, 0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
-     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
-     0x70, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6d, 0x65, 0x74,
+     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49,
+     0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x42, 0x75, 0x66,
+     0x66, 0x65, 0x72, 0x52, 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a,
+     0x8e, 0x01, 0x0a, 0x06, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x12,
+     0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+     0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x76,
+     0x67, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
+     0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x61, 0x76, 0x67, 0x53,
+     0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0e,
+     0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74,
+     0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x6d, 0x69,
+     0x6e, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24,
+     0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62,
+     0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c,
+     0x6d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73,
+     0x42, 0x02, 0x48, 0x03, 0x0a, 0x95, 0x02, 0x0a, 0x30, 0x70, 0x72, 0x6f,
+     0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+     0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64,
+     0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6c, 0x6d, 0x6b, 0x5f, 0x6d, 0x65, 0x74,
      0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70,
      0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-     0x6f, 0x73, 0x22, 0xa5, 0x02, 0x0a, 0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f,
-     0x69, 0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73,
-     0x12, 0x4e, 0x0a, 0x0b, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x72, 0x61,
-     0x69, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e,
-     0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50,
-     0x6f, 0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x50, 0x6f,
-     0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0a, 0x70, 0x6f,
-     0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x4e, 0x0a, 0x0a,
-     0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21,
-     0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f,
-     0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69,
-     0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4d, 0x73, 0x12, 0x1d, 0x0a,
-     0x0a, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x5f, 0x75, 0x77, 0x73, 0x18,
-     0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x65, 0x72, 0x67,
-     0x79, 0x55, 0x77, 0x73, 0x1a, 0x70, 0x0a, 0x0a, 0x50, 0x6f, 0x77, 0x65,
-     0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
-     0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-     0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x0b, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79,
-     0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
-     0x2d, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70,
-     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-     0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x2e,
-     0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a,
-     0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x42, 0x02,
-     0x48, 0x03, 0x0a, 0xac, 0x0e, 0x0a, 0x34, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-     0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d,
-     0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
-     0x69, 0x64, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x6d,
-     0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
-     0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x22, 0xde, 0x0d, 0x0a, 0x14, 0x41, 0x6e, 0x64,
-     0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d,
-     0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x47, 0x0a, 0x07, 0x73, 0x74, 0x61,
-     0x72, 0x74, 0x75, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d,
-     0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-     0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69,
-     0x63, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x07, 0x73,
-     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x1a, 0xe0, 0x01, 0x0a, 0x12, 0x54,
-     0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x72, 0x65, 0x61,
-     0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x75, 0x6e,
-     0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18,
-     0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69,
-     0x6e, 0x67, 0x44, 0x75, 0x72, 0x4e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x72,
-     0x75, 0x6e, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x5f,
-     0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x75,
-     0x6e, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x4e, 0x73, 0x12,
-     0x3f, 0x0a, 0x1c, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75,
-     0x70, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x65, 0x65, 0x70,
-     0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
-     0x03, 0x52, 0x19, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75,
-     0x70, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x6c, 0x65, 0x65, 0x70, 0x44,
-     0x75, 0x72, 0x4e, 0x73, 0x12, 0x3b, 0x0a, 0x1a, 0x69, 0x6e, 0x74, 0x65,
-     0x72, 0x72, 0x75, 0x70, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c,
-     0x65, 0x65, 0x70, 0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x04,
-     0x20, 0x01, 0x28, 0x03, 0x52, 0x17, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72,
-     0x75, 0x70, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x6c, 0x65, 0x65, 0x70,
-     0x44, 0x75, 0x72, 0x4e, 0x73, 0x1a, 0x1e, 0x0a, 0x05, 0x53, 0x6c, 0x69,
-     0x63, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73,
-     0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x75, 0x72, 0x4e,
-     0x73, 0x1a, 0xbb, 0x08, 0x0a, 0x0c, 0x54, 0x6f, 0x46, 0x69, 0x72, 0x73,
-     0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x75,
-     0x72, 0x5f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
-     0x64, 0x75, 0x72, 0x4e, 0x73, 0x12, 0x72, 0x0a, 0x19, 0x6d, 0x61, 0x69,
-     0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x5f,
-     0x74, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02,
-     0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
-     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75,
-     0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x54, 0x61, 0x73, 0x6b,
-     0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x72, 0x65, 0x61, 0x6b, 0x64, 0x6f,
-     0x77, 0x6e, 0x52, 0x15, 0x6d, 0x61, 0x69, 0x6e, 0x54, 0x68, 0x72, 0x65,
-     0x61, 0x64, 0x42, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74,
-     0x65, 0x12, 0x41, 0x0a, 0x1d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70,
-     0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x73, 0x70, 0x61,
-     0x77, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03,
-     0x20, 0x01, 0x28, 0x0d, 0x52, 0x1a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50,
-     0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x53, 0x70, 0x61, 0x77,
-     0x6e, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x15,
-     0x74, 0x69, 0x6d, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
-     0x79, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x04, 0x20,
-     0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
-     0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65,
-     0x52, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69,
-     0x74, 0x79, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x66, 0x0a,
-     0x19, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69,
-     0x74, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61,
-     0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70,
+     0x6f, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x10, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+     0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12,
+     0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75,
+     0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x6f,
+     0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4e, 0x0a, 0x0c,
+     0x62, 0x79, 0x5f, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65,
+     0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d,
+     0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x42, 0x79, 0x4f, 0x6f, 0x6d, 0x53,
+     0x63, 0x6f, 0x72, 0x65, 0x52, 0x0a, 0x62, 0x79, 0x4f, 0x6f, 0x6d, 0x53,
+     0x63, 0x6f, 0x72, 0x65, 0x1a, 0x46, 0x0a, 0x0a, 0x42, 0x79, 0x4f, 0x6f,
+     0x6d, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6f, 0x6f,
+     0x6d, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x5f, 0x61, 0x64, 0x6a, 0x18,
+     0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6f, 0x6d, 0x53, 0x63,
+     0x6f, 0x72, 0x65, 0x41, 0x64, 0x6a, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f,
+     0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63,
+     0x6f, 0x75, 0x6e, 0x74, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xf4, 0x02, 0x0a,
+     0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66,
+     0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+     0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x70, 0x6f, 0x77,
+     0x72, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66,
+     0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22,
+     0xa5, 0x02, 0x0a, 0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50,
+     0x6f, 0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x4e, 0x0a,
+     0x0b, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x72, 0x61, 0x69, 0x6c, 0x73,
+     0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x65,
+     0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x50, 0x6f, 0x77, 0x65, 0x72,
+     0x52, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0a, 0x70, 0x6f, 0x77, 0x65, 0x72,
+     0x52, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x4e, 0x0a, 0x0a, 0x45, 0x6e, 0x65,
+     0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x74,
+     0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6d, 0x73, 0x18,
+     0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73,
+     0x74, 0x61, 0x6d, 0x70, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e,
+     0x65, 0x72, 0x67, 0x79, 0x5f, 0x75, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01,
+     0x28, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x55, 0x77,
+     0x73, 0x1a, 0x70, 0x0a, 0x0a, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61,
+     0x69, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+     0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+     0x4e, 0x0a, 0x0b, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x5f, 0x64, 0x61,
+     0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70,
      0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-     0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74,
-     0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e,
-     0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65, 0x41,
-     0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x54, 0x68, 0x72, 0x65, 0x61,
-     0x64, 0x4d, 0x61, 0x69, 0x6e, 0x12, 0x5f, 0x0a, 0x15, 0x74, 0x69, 0x6d,
-     0x65, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69,
-     0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
+     0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f,
+     0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x45, 0x6e, 0x65,
+     0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x65, 0x6e, 0x65,
+     0x72, 0x67, 0x79, 0x44, 0x61, 0x74, 0x61, 0x42, 0x02, 0x48, 0x03, 0x0a,
+     0xac, 0x0e, 0x0a, 0x34, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+     0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+     0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72,
+     0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65,
+     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x73, 0x22, 0xde, 0x0d, 0x0a, 0x14, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+     0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72,
+     0x69, 0x63, 0x12, 0x47, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75,
+     0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x65,
+     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61,
+     0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53,
+     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72,
+     0x74, 0x75, 0x70, 0x1a, 0xe0, 0x01, 0x0a, 0x12, 0x54, 0x61, 0x73, 0x6b,
+     0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x72, 0x65, 0x61, 0x6b, 0x64, 0x6f,
+     0x77, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e,
+     0x67, 0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01,
+     0x28, 0x03, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x44,
+     0x75, 0x72, 0x4e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x75, 0x6e, 0x6e,
+     0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18,
+     0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x75, 0x6e, 0x6e, 0x61,
+     0x62, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x4e, 0x73, 0x12, 0x3f, 0x0a, 0x1c,
+     0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x69,
+     0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x75,
+     0x72, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19,
+     0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x69,
+     0x62, 0x6c, 0x65, 0x53, 0x6c, 0x65, 0x65, 0x70, 0x44, 0x75, 0x72, 0x4e,
+     0x73, 0x12, 0x3b, 0x0a, 0x1a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75,
+     0x70, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x65, 0x65, 0x70,
+     0x5f, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
+     0x03, 0x52, 0x17, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74,
+     0x69, 0x62, 0x6c, 0x65, 0x53, 0x6c, 0x65, 0x65, 0x70, 0x44, 0x75, 0x72,
+     0x4e, 0x73, 0x1a, 0x1e, 0x0a, 0x05, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x12,
+     0x15, 0x0a, 0x06, 0x64, 0x75, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x01, 0x20,
+     0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x75, 0x72, 0x4e, 0x73, 0x1a, 0xbb,
+     0x08, 0x0a, 0x0c, 0x54, 0x6f, 0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72,
+     0x61, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x75, 0x72, 0x5f, 0x6e,
+     0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x75, 0x72,
+     0x4e, 0x73, 0x12, 0x72, 0x0a, 0x19, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x74,
+     0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x74, 0x61, 0x73,
+     0x6b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+     0x0b, 0x32, 0x38, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72,
+     0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65,
+     0x74, 0x72, 0x69, 0x63, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61,
+     0x74, 0x65, 0x42, 0x72, 0x65, 0x61, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x52,
+     0x15, 0x6d, 0x61, 0x69, 0x6e, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x42,
+     0x79, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x41,
+     0x0a, 0x1d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x63,
+     0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x65,
+     0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+     0x0d, 0x52, 0x1a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x63,
+     0x65, 0x73, 0x73, 0x65, 0x73, 0x53, 0x70, 0x61, 0x77, 0x6e, 0x65, 0x64,
+     0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x15, 0x74, 0x69, 0x6d,
+     0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x6d,
+     0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
      0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
      0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f,
      0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74,
      0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x13, 0x74,
-     0x69, 0x6d, 0x65, 0x42, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69,
-     0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5b, 0x0a, 0x13, 0x74, 0x69,
+     0x69, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x4d,
+     0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x66, 0x0a, 0x19, 0x74, 0x69,
      0x6d, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f,
-     0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
-     0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70,
-     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-     0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x11, 0x74, 0x69,
-     0x6d, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74,
-     0x61, 0x72, 0x74, 0x12, 0x5d, 0x0a, 0x14, 0x74, 0x69, 0x6d, 0x65, 0x5f,
-     0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x73,
-     0x75, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
-     0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53,
-     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x12, 0x74, 0x69, 0x6d, 0x65,
-     0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x75,
-     0x6d, 0x65, 0x12, 0x5a, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63,
-     0x68, 0x6f, 0x72, 0x65, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72,
-     0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72,
-     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
-     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72,
-     0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c,
-     0x69, 0x63, 0x65, 0x52, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x6f,
-     0x72, 0x65, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72, 0x12, 0x66,
-     0x0a, 0x19, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72,
-     0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x63,
-     0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
-     0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53,
-     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65,
-     0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50,
-     0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x66, 0x0a, 0x19, 0x74, 0x69,
-     0x6d, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74,
-     0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18,
-     0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66,
+     0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
+     0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66,
      0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
      0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74,
      0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69,
-     0x63, 0x65, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x75, 0x72, 0x69,
-     0x6e, 0x67, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65,
-     0x73, 0x73, 0x12, 0x4b, 0x0a, 0x23, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f,
-     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x61,
-     0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x70, 0x75, 0x5f,
-     0x72, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52,
-     0x1e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
-     0x73, 0x54, 0x6f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x43,
-     0x70, 0x75, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x1a, 0xbb, 0x02, 0x0a, 0x07,
-     0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
-     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
-     0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
-     0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
-     0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-     0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d,
-     0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
-     0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
-     0x0b, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65,
-     0x12, 0x2c, 0x0a, 0x12, 0x7a, 0x79, 0x67, 0x6f, 0x74, 0x65, 0x5f, 0x6e,
-     0x65, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04,
-     0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x7a, 0x79, 0x67, 0x6f, 0x74, 0x65,
-     0x4e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x43,
-     0x0a, 0x1e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x68,
-     0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65,
-     0x73, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01,
-     0x28, 0x0d, 0x52, 0x1b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79,
-     0x48, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65,
-     0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x0e, 0x74,
-     0x6f, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x6d,
-     0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x65,
-     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-     0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61,
-     0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x54,
-     0x6f, 0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52,
-     0x0c, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d,
-     0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xb7, 0x07, 0x0a, 0x3c, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
-     0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70,
-     0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73,
-     0x69, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
+     0x63, 0x65, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65, 0x41, 0x63, 0x74, 0x69,
+     0x76, 0x69, 0x74, 0x79, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x61,
+     0x69, 0x6e, 0x12, 0x5f, 0x0a, 0x15, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62,
+     0x69, 0x6e, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+     0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
      0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x22, 0xe1, 0x06, 0x0a, 0x14, 0x48, 0x65, 0x61, 0x70,
-     0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73,
-     0x69, 0x74, 0x65, 0x73, 0x12, 0x5a, 0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x74,
-     0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01,
-     0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48,
-     0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61,
-     0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74,
-     0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x69,
-     0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73,
-     0x1a, 0x3e, 0x0a, 0x05, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
-     0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-     0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x70,
-     0x70, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
-     0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67,
-     0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x8e, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x75,
-     0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74,
-     0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
-     0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75,
-     0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
-     0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
-     0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12,
-     0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x75,
-     0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x65,
-     0x6c, 0x74, 0x61, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
-     0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,
-     0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x65, 0x6c, 0x74, 0x61,
-     0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0xa6, 0x02, 0x0a, 0x08, 0x43, 0x61,
-     0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61,
-     0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x61,
-     0x73, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
-     0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
-     0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12,
-     0x41, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
+     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53,
+     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+     0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x13, 0x74, 0x69, 0x6d, 0x65,
+     0x42, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+     0x69, 0x6f, 0x6e, 0x12, 0x5b, 0x0a, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+     0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x74, 0x61,
+     0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74,
+     0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e,
+     0x53, 0x6c, 0x69, 0x63, 0x65, 0x52, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x41,
+     0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74,
+     0x12, 0x5d, 0x0a, 0x14, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x61, 0x63, 0x74,
+     0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65,
+     0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72,
+     0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c,
+     0x69, 0x63, 0x65, 0x52, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x41, 0x63, 0x74,
+     0x69, 0x76, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12,
+     0x5a, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x68, 0x6f, 0x72,
+     0x65, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72, 0x18, 0x09, 0x20,
+     0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
+     0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
+     0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65,
+     0x52, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x6f, 0x72, 0x65, 0x6f,
+     0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72, 0x12, 0x66, 0x0a, 0x19, 0x74,
+     0x69, 0x6d, 0x65, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x73,
+     0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
+     0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72,
+     0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c,
+     0x69, 0x63, 0x65, 0x52, 0x16, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x65, 0x66,
+     0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63,
+     0x65, 0x73, 0x73, 0x12, 0x66, 0x0a, 0x19, 0x74, 0x69, 0x6d, 0x65, 0x5f,
+     0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74,
+     0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01,
      0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
-     0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61,
-     0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c,
-     0x73, 0x69, 0x74, 0x65, 0x73, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52,
-     0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x73, 0x65,
-     0x6c, 0x66, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x18, 0x04, 0x20,
-     0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65,
-     0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c,
-     0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-     0x65, 0x72, 0x73, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x66, 0x41, 0x6c, 0x6c,
-     0x6f, 0x63, 0x73, 0x12, 0x51, 0x0a, 0x0c, 0x63, 0x68, 0x69, 0x6c, 0x64,
-     0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
-     0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70,
-     0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73,
-     0x69, 0x74, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
-     0x73, 0x52, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x41, 0x6c, 0x6c, 0x6f,
-     0x63, 0x73, 0x1a, 0xf2, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61,
-     0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
-     0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70,
-     0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
-     0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-     0x52, 0x0b, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d,
-     0x65, 0x12, 0x4c, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74,
-     0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70,
+     0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64,
+     0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d,
+     0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x52,
+     0x16, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x53,
+     0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12,
+     0x4b, 0x0a, 0x23, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f,
+     0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x61, 0x63, 0x74, 0x69,
+     0x76, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x70, 0x75, 0x5f, 0x72, 0x61, 0x74,
+     0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x1e, 0x6f, 0x74,
+     0x68, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f,
+     0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x43, 0x70, 0x75, 0x52,
+     0x61, 0x74, 0x69, 0x6f, 0x1a, 0xbb, 0x02, 0x0a, 0x07, 0x53, 0x74, 0x61,
+     0x72, 0x74, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72,
+     0x74, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
+     0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x49, 0x64, 0x12,
+     0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e,
+     0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70,
+     0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21,
+     0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61,
+     0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72,
+     0x6f, 0x63, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a,
+     0x12, 0x7a, 0x79, 0x67, 0x6f, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f,
+     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
+     0x08, 0x52, 0x10, 0x7a, 0x79, 0x67, 0x6f, 0x74, 0x65, 0x4e, 0x65, 0x77,
+     0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x43, 0x0a, 0x1e, 0x61,
+     0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x68, 0x6f, 0x73, 0x74,
+     0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f,
+     0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
+     0x1b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x48, 0x6f, 0x73,
+     0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x43,
+     0x6f, 0x75, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x0e, 0x74, 0x6f, 0x5f, 0x66,
+     0x69, 0x72, 0x73, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05,
+     0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
+     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
+     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75,
+     0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x54, 0x6f, 0x46, 0x69,
+     0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0c, 0x74, 0x6f,
+     0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x42, 0x02,
+     0x48, 0x03, 0x0a, 0xfb, 0x01, 0x0a, 0x36, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d,
+     0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+     0x69, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d,
+     0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22, 0xab, 0x01, 0x0a, 0x16, 0x41,
+     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
+     0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a,
+     0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+     0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64,
+     0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12,
+     0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e,
+     0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70,
+     0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28,
+     0x0a, 0x10, 0x61, 0x70, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+     0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
+     0x52, 0x0e, 0x61, 0x70, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+     0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x62, 0x75,
+     0x67, 0x67, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
+     0x52, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x61, 0x62, 0x6c, 0x65,
+     0x42, 0x02, 0x48, 0x03, 0x0a, 0xb2, 0x08, 0x0a, 0x3c, 0x70, 0x72, 0x6f,
+     0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+     0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64,
+     0x72, 0x6f, 0x69, 0x64, 0x2f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70, 0x72,
+     0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69,
+     0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x73, 0x1a, 0x36, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+     0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x61,
+     0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa4,
+     0x07, 0x0a, 0x14, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69,
+     0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12,
+     0x5a, 0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f,
+     0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+     0x33, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70,
+     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72,
+     0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74,
+     0x65, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53,
+     0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+     0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a, 0x3e, 0x0a, 0x05, 0x46,
+     0x72, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+     0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+     0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f,
+     0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+     0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x1a,
+     0x8e, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73,
+     0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f,
+     0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74,
+     0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a,
+     0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
+     0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61,
+     0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65,
+     0x6c, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20,
+     0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x43, 0x6f,
+     0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x6c, 0x74, 0x61,
+     0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
+     0x52, 0x0a, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x42, 0x79, 0x74, 0x65, 0x73,
+     0x1a, 0xa6, 0x02, 0x0a, 0x08, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74,
+     0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20,
+     0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x1f, 0x0a,
+     0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68,
+     0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65,
+     0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x05, 0x66, 0x72,
+     0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
+     0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
+     0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66,
+     0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73,
+     0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d,
+     0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x73, 0x65, 0x6c, 0x66, 0x5f, 0x61, 0x6c,
+     0x6c, 0x6f, 0x63, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e,
+     0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
+     0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f,
+     0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
+     0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a,
+     0x73, 0x65, 0x6c, 0x66, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x12, 0x51,
+     0x0a, 0x0c, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+     0x63, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70,
      0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
      0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69,
      0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2e,
-     0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x52, 0x09, 0x63, 0x61,
-     0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70,
-     0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61,
-     0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
-     0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x6c,
-     0x74, 0x61, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70,
-     0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c,
-     0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
-     0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x74,
-     0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x02, 0x48, 0x03, 0x0a,
-     0x8c, 0x02, 0x0a, 0x32, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
-     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
-     0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66,
-     0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22,
-     0xc0, 0x01, 0x0a, 0x12, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50,
-     0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x47,
-     0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01,
-     0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
-     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
-     0x65, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
-     0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x1a,
-     0x61, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x21,
-     0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61,
-     0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61,
-     0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a,
-     0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03,
-     0x75, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69,
-     0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
-     0x03, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f,
-     0x64, 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0x80, 0x02, 0x0a, 0x39, 0x70,
-     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61,
-     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x75, 0x6e, 0x73, 0x79, 0x6d,
-     0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d,
-     0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65,
-     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-     0x73, 0x22, 0xad, 0x01, 0x0a, 0x12, 0x55, 0x6e, 0x73, 0x79, 0x6d, 0x62,
-     0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
-     0x12, 0x41, 0x0a, 0x06, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01,
-     0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x55,
-     0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46,
-     0x72, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52,
-     0x06, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x1a, 0x54, 0x0a, 0x05, 0x46,
-     0x72, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75,
-     0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f,
-     0x64, 0x75, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c,
-     0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
-     0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61,
-     0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
-     0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x02, 0x48,
-     0x03, 0x0a, 0xa4, 0x03, 0x0a, 0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0b, 0x63, 0x68,
+     0x69, 0x6c, 0x64, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x73, 0x1a, 0xb5, 0x02,
+     0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74,
+     0x61, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x01,
+     0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x21, 0x0a,
+     0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d,
+     0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f,
+     0x63, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x07,
+     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
+     0x0b, 0x32, 0x27, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72,
+     0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x65,
+     0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x63,
+     0x65, 0x73, 0x73, 0x12, 0x4c, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x73,
+     0x69, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e,
+     0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
+     0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f,
+     0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
+     0x73, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x52, 0x09,
+     0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a,
+     0x13, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c,
+     0x74, 0x61, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01,
+     0x28, 0x03, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x44,
+     0x65, 0x6c, 0x74, 0x61, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a,
+     0x13, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x6f, 0x74,
+     0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01,
+     0x28, 0x03, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54,
+     0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x02, 0x48,
+     0x03, 0x0a, 0x8c, 0x02, 0x0a, 0x32, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
      0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
      0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-     0x64, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f,
-     0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
-     0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x22, 0xd5, 0x02, 0x0a, 0x0d, 0x4a, 0x61, 0x76,
-     0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x53,
-     0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73,
-     0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c,
-     0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61,
-     0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61,
-     0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x69, 0x6e,
-     0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a,
-     0x65, 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0e, 0x0a,
-     0x02, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x74,
-     0x73, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69,
-     0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x68, 0x65,
-     0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65,
-     0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x70,
-     0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
-     0x11, 0x72, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x65,
-     0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x87, 0x01, 0x0a, 0x0d, 0x49,
-     0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73,
-     0x12, 0x12, 0x0a, 0x04, 0x75, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
-     0x28, 0x0d, 0x52, 0x04, 0x75, 0x70, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c,
-     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
-     0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x63,
-     0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x07, 0x73,
-     0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
-     0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
-     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48,
-     0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x6d,
-     0x70, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
-     0x42, 0x02, 0x48, 0x03, 0x0a, 0xed, 0x10, 0x0a, 0x25, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
-     0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
-     0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
+     0x64, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69,
+     0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65,
+     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x73, 0x22, 0xc0, 0x01, 0x0a, 0x12, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+     0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74,
+     0x12, 0x47, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73,
+     0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x61, 0x63, 0x6b,
+     0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x50, 0x61, 0x63, 0x6b,
+     0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+     0x73, 0x1a, 0x61, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+     0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f,
+     0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+     0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+     0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
+     0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x65, 0x72,
+     0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20,
+     0x01, 0x28, 0x03, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+     0x43, 0x6f, 0x64, 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0x80, 0x02, 0x0a,
+     0x39, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66,
+     0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+     0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x75, 0x6e, 0x73,
+     0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72,
+     0x61, 0x6d, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
      0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x1a, 0x31, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
-     0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
-     0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-     0x2f, 0x62, 0x61, 0x74, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74,
+     0x74, 0x6f, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x12, 0x55, 0x6e, 0x73, 0x79,
+     0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d,
+     0x65, 0x73, 0x12, 0x41, 0x0a, 0x06, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73,
+     0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x55, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65,
+     0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x46, 0x72, 0x61, 0x6d,
+     0x65, 0x52, 0x06, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x1a, 0x54, 0x0a,
+     0x05, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f,
+     0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+     0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75,
+     0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+     0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a,
+     0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01,
+     0x28, 0x03, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42,
+     0x02, 0x48, 0x03, 0x0a, 0xfc, 0x03, 0x0a, 0x35, 0x70, 0x72, 0x6f, 0x74,
      0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f,
      0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72,
-     0x6f, 0x69, 0x64, 0x2f, 0x63, 0x70, 0x75, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-     0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72,
-     0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
-     0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f, 0x6d, 0x65,
-     0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36,
-     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65,
-     0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
-     0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f,
-     0x75, 0x6e, 0x61, 0x67, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x69, 0x64, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x68, 0x65, 0x61,
+     0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x1a, 0x36, 0x70, 0x72, 0x6f, 0x74,
      0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f,
      0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72,
      0x6f, 0x69, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f,
-     0x67, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f,
+     0x74, 0x6f, 0x22, 0xf5, 0x02, 0x0a, 0x0d, 0x4a, 0x61, 0x76, 0x61, 0x48,
+     0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x53, 0x0a, 0x0e,
+     0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61,
+     0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x73, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53,
+     0x74, 0x61, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
+     0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x69, 0x6e, 0x73, 0x74,
+     0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a, 0x65, 0x0a,
+     0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x74,
+     0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x74, 0x73, 0x12,
+     0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65,
+     0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x68, 0x65, 0x61, 0x70,
+     0x53, 0x69, 0x7a, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, 0x61, 0x63,
+     0x68, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73,
+     0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x72,
+     0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x70,
+     0x53, 0x69, 0x7a, 0x65, 0x1a, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x73,
+     0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x12,
+     0x0a, 0x04, 0x75, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
+     0x52, 0x04, 0x75, 0x70, 0x69, 0x64, 0x12, 0x41, 0x0a, 0x07, 0x70, 0x72,
+     0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+     0x27, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70,
+     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+     0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x74, 0x61,
+     0x64, 0x61, 0x74, 0x61, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
+     0x73, 0x12, 0x3f, 0x0a, 0x07, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+     0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61,
+     0x74, 0x73, 0x2e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x07, 0x73,
+     0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xe0,
+     0x0f, 0x0a, 0x25, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65,
+     0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+     0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70,
+     0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x1a, 0x31, 0x70,
+     0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+     0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61,
+     0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x62, 0x61, 0x74, 0x74, 0x5f,
+     0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+     0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+     0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x63, 0x70,
+     0x75, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f,
+     0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+     0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+     0x6d, 0x65, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70,
+     0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
+     0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+     0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f, 0x75, 0x6e, 0x61, 0x67, 0x67, 0x5f,
+     0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
      0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72,
      0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
      0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x69, 0x6f,
@@ -782,7 +772,7 @@
      0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x78,
      0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x69, 0x64, 0x78, 0x12,
      0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
-     0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x80, 0x09,
+     0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xa9, 0x08,
      0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69,
      0x63, 0x73, 0x12, 0x48, 0x0a, 0x0c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
      0x64, 0x5f, 0x62, 0x61, 0x74, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
@@ -817,69 +807,62 @@
      0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
      0x4c, 0x69, 0x73, 0x74, 0x52, 0x12, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
      0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74,
-     0x12, 0x5b, 0x0a, 0x16, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f,
-     0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x77,
-     0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70,
-     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-     0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72,
-     0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x52,
-     0x14, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63,
-     0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x12, 0x42, 0x0a,
-     0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x69, 0x6f, 0x6e,
-     0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72,
-     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
-     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x4d,
-     0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f,
-     0x69, 0x64, 0x49, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64,
-     0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6c, 0x6d, 0x6b, 0x18, 0x08, 0x20, 0x01,
-     0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
-     0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64,
-     0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69,
-     0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d,
-     0x6b, 0x12, 0x4d, 0x0a, 0x10, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-     0x5f, 0x70, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x07, 0x20,
-     0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
-     0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61,
-     0x69, 0x6c, 0x73, 0x52, 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
-     0x50, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x4e, 0x0a, 0x0f,
-     0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x72,
-     0x74, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e,
+     0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f,
+     0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
      0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
-     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53,
-     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
-     0x52, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61,
-     0x72, 0x74, 0x75, 0x70, 0x12, 0x5b, 0x0a, 0x16, 0x68, 0x65, 0x61, 0x70,
-     0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c,
-     0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b,
-     0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
-     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50,
-     0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69,
-     0x74, 0x65, 0x73, 0x52, 0x14, 0x68, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f,
-     0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
-     0x73, 0x12, 0x45, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6d,
-     0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28,
-     0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
-     0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63,
-     0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x74,
-     0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
-     0x12, 0x54, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c,
-     0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
-     0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x65, 0x72, 0x66,
+     0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49,
+     0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e,
+     0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0b,
+     0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6c, 0x6d, 0x6b, 0x18,
+     0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66,
      0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
-     0x55, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64,
-     0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x79,
-     0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d,
-     0x65, 0x73, 0x12, 0x46, 0x0a, 0x0f, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x68,
-     0x65, 0x61, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x11, 0x20,
-     0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
-     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61,
-     0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
-     0x0d, 0x6a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61,
-     0x74, 0x73, 0x2a, 0x06, 0x08, 0xc2, 0x03, 0x10, 0xf4, 0x03, 0x2a, 0x06,
-     0x08, 0xf4, 0x03, 0x10, 0xe9, 0x07, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05,
-     0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f,
-     0x42, 0x02, 0x48, 0x03}};
+     0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d, 0x65,
+     0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+     0x64, 0x4c, 0x6d, 0x6b, 0x12, 0x4d, 0x0a, 0x10, 0x61, 0x6e, 0x64, 0x72,
+     0x6f, 0x69, 0x64, 0x5f, 0x70, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73,
+     0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x65,
+     0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0f, 0x61, 0x6e, 0x64, 0x72,
+     0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x12,
+     0x4e, 0x0a, 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x73,
+     0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+     0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+     0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+     0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74,
+     0x72, 0x69, 0x63, 0x52, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+     0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x5b, 0x0a, 0x16, 0x68,
+     0x65, 0x61, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f,
+     0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20,
+     0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+     0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65,
+     0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c,
+     0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x52, 0x14, 0x68, 0x65, 0x61, 0x70,
+     0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73,
+     0x69, 0x74, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x63,
+     0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03,
+     0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
+     0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x54,
+     0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+     0x52, 0x0d, 0x74, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64,
+     0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x79, 0x6d,
+     0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d,
+     0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70,
+     0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+     0x6f, 0x73, 0x2e, 0x55, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69,
+     0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x12, 0x75,
+     0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46,
+     0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x0f, 0x6a, 0x61, 0x76,
+     0x61, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73,
+     0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72,
+     0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+     0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61,
+     0x74, 0x73, 0x52, 0x0d, 0x6a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70,
+     0x53, 0x74, 0x61, 0x74, 0x73, 0x2a, 0x06, 0x08, 0xc2, 0x03, 0x10, 0xf4,
+     0x03, 0x2a, 0x06, 0x08, 0xf4, 0x03, 0x10, 0xe9, 0x07, 0x4a, 0x04, 0x08,
+     0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08,
+     0x0d, 0x10, 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x42, 0x02, 0x48,
+     0x03}};
 
 }  // namespace perfetto
 
diff --git a/src/trace_processor/process_table.cc b/src/trace_processor/process_table.cc
index adc9d1e..a25c0fa 100644
--- a/src/trace_processor/process_table.cc
+++ b/src/trace_processor/process_table.cc
@@ -47,6 +47,7 @@
           SqliteTable::Column(Column::kEndTs, "end_ts", SqlValue::Type::kLong),
           SqliteTable::Column(Column::kParentUpid, "parent_upid",
                               SqlValue::Type::kLong),
+          SqliteTable::Column(Column::kUid, "uid", SqlValue::Type::kLong),
       },
       {Column::kUpid});
   return util::OkStatus();
@@ -73,7 +74,8 @@
     : SqliteTable::Cursor(table), storage_(table->storage_) {}
 
 int ProcessTable::Cursor::Filter(const QueryConstraints& qc,
-                                 sqlite3_value** argv) {
+                                 sqlite3_value** argv,
+                                 FilterHistory) {
   min_ = 0;
   max_ = static_cast<uint32_t>(storage_->process_count());
   desc_ = false;
@@ -147,6 +149,14 @@
       }
       break;
     }
+    case Column::kUid: {
+      if (process.uid.has_value()) {
+        sqlite3_result_int64(context, process.uid.value());
+      } else {
+        sqlite3_result_null(context);
+      }
+      break;
+    }
     default:
       PERFETTO_FATAL("Unknown column %d", N);
       break;
diff --git a/src/trace_processor/process_table.h b/src/trace_processor/process_table.h
index c4c1ed5..7e661a6 100644
--- a/src/trace_processor/process_table.h
+++ b/src/trace_processor/process_table.h
@@ -36,14 +36,17 @@
     kPid = 2,
     kStartTs = 3,
     kEndTs = 4,
-    kParentUpid = 5
+    kParentUpid = 5,
+    kUid = 6
   };
   class Cursor : public SqliteTable::Cursor {
    public:
     Cursor(ProcessTable*);
 
     // Implementation of Table::Cursor.
-    int Filter(const QueryConstraints&, sqlite3_value**) override;
+    int Filter(const QueryConstraints&,
+               sqlite3_value**,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/trace_processor/process_tracker.cc b/src/trace_processor/process_tracker.cc
index e9c0335..1ccc4b7 100644
--- a/src/trace_processor/process_tracker.cc
+++ b/src/trace_processor/process_tracker.cc
@@ -194,6 +194,10 @@
   return upid;
 }
 
+void ProcessTracker::SetProcessUid(UniquePid upid, uint32_t uid) {
+  context_->storage->GetMutableProcess(upid)->uid = uid;
+}
+
 void ProcessTracker::SetProcessNameIfUnset(UniquePid upid,
                                            StringId process_name_id) {
   TraceStorage::Process* process = context_->storage->GetMutableProcess(upid);
diff --git a/src/trace_processor/process_tracker.h b/src/trace_processor/process_tracker.h
index 7c7ea55..985212b 100644
--- a/src/trace_processor/process_tracker.h
+++ b/src/trace_processor/process_tracker.h
@@ -91,6 +91,9 @@
                                        base::Optional<uint32_t> ppid,
                                        base::StringView name);
 
+  // Sets the process user id.
+  void SetProcessUid(UniquePid upid, uint32_t uid);
+
   // Assigns the given name to the process identified by |upid| if it does not
   // have a name yet.
   void SetProcessNameIfUnset(UniquePid upid, StringId process_name_id);
diff --git a/src/trace_processor/span_join_operator_table.cc b/src/trace_processor/span_join_operator_table.cc
index 931289c..6067483 100644
--- a/src/trace_processor/span_join_operator_table.cc
+++ b/src/trace_processor/span_join_operator_table.cc
@@ -169,8 +169,14 @@
   return std::unique_ptr<SpanJoinOperatorTable::Cursor>(new Cursor(this, db_));
 }
 
-int SpanJoinOperatorTable::BestIndex(const QueryConstraints&, BestIndexInfo*) {
+int SpanJoinOperatorTable::BestIndex(const QueryConstraints& qc,
+                                     BestIndexInfo* info) {
   // TODO(lalitm): figure out cost estimation.
+  const auto& ob = qc.order_by();
+  if (ob.size() == 1 && ob.front().iColumn == Column::kTimestamp &&
+      !ob.front().desc) {
+    info->sqlite_omit_order_by = true;
+  }
   return SQLITE_OK;
 }
 
@@ -187,8 +193,7 @@
       continue;
 
     if (col_name == kTsColumnName || col_name == kDurColumnName) {
-      // We don't support constraints on ts or duration in the child tables.
-      PERFETTO_DFATAL("ts or duration constraints on child tables");
+      // Allow SQLite handle any constraints on ts or duration.
       continue;
     }
     auto op = sqlite_utils::OpToString(cs.op);
@@ -278,7 +283,8 @@
       table_(table) {}
 
 int SpanJoinOperatorTable::Cursor::Filter(const QueryConstraints& qc,
-                                          sqlite3_value** argv) {
+                                          sqlite3_value** argv,
+                                          FilterHistory) {
   int err = t1_.Initialize(qc, argv);
   if (err != SQLITE_OK)
     return err;
diff --git a/src/trace_processor/span_join_operator_table.h b/src/trace_processor/span_join_operator_table.h
index eb96161..dfc4439 100644
--- a/src/trace_processor/span_join_operator_table.h
+++ b/src/trace_processor/span_join_operator_table.h
@@ -227,7 +227,9 @@
     Cursor(SpanJoinOperatorTable*, sqlite3* db);
     ~Cursor() override = default;
 
-    int Filter(const QueryConstraints& qc, sqlite3_value** argv) override;
+    int Filter(const QueryConstraints& qc,
+               sqlite3_value** argv,
+               FilterHistory) override;
     int Column(sqlite3_context* context, int N) override;
     int Next() override;
     int Eof() override;
diff --git a/src/trace_processor/sql_stats_table.cc b/src/trace_processor/sql_stats_table.cc
index 0d434a0..11da41b 100644
--- a/src/trace_processor/sql_stats_table.cc
+++ b/src/trace_processor/sql_stats_table.cc
@@ -66,7 +66,9 @@
 
 SqlStatsTable::Cursor::~Cursor() = default;
 
-int SqlStatsTable::Cursor::Filter(const QueryConstraints&, sqlite3_value**) {
+int SqlStatsTable::Cursor::Filter(const QueryConstraints&,
+                                  sqlite3_value**,
+                                  FilterHistory) {
   *this = Cursor(table_);
   num_rows_ = storage_->sql_stats().size();
   return SQLITE_OK;
diff --git a/src/trace_processor/sql_stats_table.h b/src/trace_processor/sql_stats_table.h
index 0ff06a7..7793f2e 100644
--- a/src/trace_processor/sql_stats_table.h
+++ b/src/trace_processor/sql_stats_table.h
@@ -47,7 +47,9 @@
     ~Cursor() override;
 
     // Implementation of SqliteTable::Cursor.
-    int Filter(const QueryConstraints&, sqlite3_value**) override;
+    int Filter(const QueryConstraints&,
+               sqlite3_value**,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index 8b3dfc8..698f5f5 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -119,6 +119,34 @@
   return SQLITE_OK;
 }
 
+int DbSqliteTable::ModifyConstraints(QueryConstraints* qc) {
+  using C = QueryConstraints::Constraint;
+
+  // Reorder constraints to consider the constraints on columns which are
+  // cheaper to filter first.
+  auto* cs = qc->mutable_constraints();
+  std::sort(cs->begin(), cs->end(), [this](const C& a, const C& b) {
+    uint32_t a_idx = static_cast<uint32_t>(a.column);
+    uint32_t b_idx = static_cast<uint32_t>(b.column);
+    const auto& a_col = table_->GetColumn(a_idx);
+    const auto& b_col = table_->GetColumn(b_idx);
+
+    // Id columns are always very cheap to filter on so try and get them
+    // first.
+    if (a_col.IsId() && !b_col.IsId())
+      return true;
+
+    // Sorted columns are also quite cheap to filter so order them after
+    // any id columns.
+    if (a_col.IsSorted() && !b_col.IsSorted())
+      return true;
+
+    // TODO(lalitm): introduce more orderings here based on empirical data.
+    return false;
+  });
+  return SQLITE_OK;
+}
+
 double DbSqliteTable::EstimateCost(const QueryConstraints& qc) {
   // Currently our cost estimation algorithm is quite simplistic but is good
   // enough for the simplest cases.
@@ -158,11 +186,30 @@
     : SqliteTable::Cursor(table), initial_db_table_(table->table_) {}
 
 int DbSqliteTable::Cursor::Filter(const QueryConstraints& qc,
-                                  sqlite3_value** argv) {
+                                  sqlite3_value** argv,
+                                  FilterHistory history) {
   // Clear out the iterator before filtering to ensure the destructor is run
   // before the table's destructor.
   iterator_ = base::nullopt;
 
+  if (history == FilterHistory::kSame && qc.constraints().size() == 1 &&
+      sqlite_utils::IsOpEq(qc.constraints().front().op)) {
+    // If we've seen the same constraint set with a single equality constraint
+    // more than |kRepeatedThreshold| times, we assume we will see it more
+    // in the future and thus cache a table sorted on the column. That way,
+    // future equality constraints can binary search for the value instead of
+    // doing a full table scan.
+    constexpr uint32_t kRepeatedThreshold = 3;
+    if (!sorted_cache_table_ && repeated_cache_count_++ > kRepeatedThreshold) {
+      const auto& c = qc.constraints().front();
+      uint32_t col = static_cast<uint32_t>(c.column);
+      sorted_cache_table_ = initial_db_table_->Sort({Order{col, false}});
+    }
+  } else {
+    sorted_cache_table_ = base::nullopt;
+    repeated_cache_count_ = 0;
+  }
+
   // We reuse this vector to reduce memory allocations on nested subqueries.
   constraints_.resize(qc.constraints().size());
   for (size_t i = 0; i < qc.constraints().size(); ++i) {
@@ -183,7 +230,11 @@
     orders_[i] = Order{col, static_cast<bool>(ob.desc)};
   }
 
-  db_table_ = initial_db_table_->Filter(constraints_).Sort(orders_);
+  // Try and use the sorted cache table (if it exists) to speed up the sorting.
+  // Otherwise, just use the original table.
+  auto* source =
+      sorted_cache_table_ ? &*sorted_cache_table_ : &*initial_db_table_;
+  db_table_ = source->Filter(constraints_).Sort(orders_);
   iterator_ = db_table_->IterateRows();
 
   return SQLITE_OK;
diff --git a/src/trace_processor/sqlite/db_sqlite_table.h b/src/trace_processor/sqlite/db_sqlite_table.h
index 6afcbfe..f6adf0f 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.h
+++ b/src/trace_processor/sqlite/db_sqlite_table.h
@@ -30,18 +30,35 @@
    public:
     explicit Cursor(DbSqliteTable* table);
 
+    Cursor(Cursor&&) noexcept = default;
+    Cursor& operator=(Cursor&&) = default;
+
     // Implementation of SqliteTable::Cursor.
-    int Filter(const QueryConstraints& qc, sqlite3_value** argv) override;
+    int Filter(const QueryConstraints& qc,
+               sqlite3_value** argv,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
 
    private:
+    Cursor(const Cursor&) = delete;
+    Cursor& operator=(const Cursor&) = delete;
+
     const Table* initial_db_table_ = nullptr;
 
     base::Optional<Table> db_table_;
     base::Optional<Table::Iterator> iterator_;
 
+    // Stores a sorted version of |db_table_| sorted on a repeated equals
+    // constraint. This allows speeding up repeated subqueries in joins
+    // significantly.
+    base::Optional<Table> sorted_cache_table_;
+
+    // Stores the count of repeated equality queries to decide whether it is
+    // wortwhile to sort |db_table_| to create |sorted_cache_table_|.
+    uint32_t repeated_cache_count_ = 0;
+
     std::vector<Constraint> constraints_;
     std::vector<Order> orders_;
   };
@@ -58,6 +75,7 @@
                     const char* const*,
                     SqliteTable::Schema*) override final;
   std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
+  int ModifyConstraints(QueryConstraints*) override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
  private:
diff --git a/src/trace_processor/sqlite/sqlite_table.cc b/src/trace_processor/sqlite/sqlite_table.cc
index 512d672..8456ad2 100644
--- a/src/trace_processor/sqlite/sqlite_table.cc
+++ b/src/trace_processor/sqlite/sqlite_table.cc
@@ -130,9 +130,7 @@
   return SQLITE_READONLY;
 }
 
-const QueryConstraints& SqliteTable::ParseConstraints(int idxNum,
-                                                      const char* idxStr,
-                                                      int argc) {
+bool SqliteTable::ReadConstraints(int idxNum, const char* idxStr, int argc) {
   bool cache_hit = true;
   if (idxNum != qc_hash_) {
     qc_cache_ = QueryConstraints::FromString(idxStr);
@@ -143,7 +141,7 @@
     PERFETTO_LOG("[%s::ParseConstraints] constraints=%s argc=%d cache_hit=%d",
                  name_.c_str(), idxStr, argc, cache_hit);
   }
-  return qc_cache_;
+  return cache_hit;
 }
 
 SqliteTable::Cursor::Cursor(SqliteTable* table) : table_(table) {
diff --git a/src/trace_processor/sqlite/sqlite_table.h b/src/trace_processor/sqlite/sqlite_table.h
index c53baaf..2564ebc 100644
--- a/src/trace_processor/sqlite/sqlite_table.h
+++ b/src/trace_processor/sqlite/sqlite_table.h
@@ -74,13 +74,28 @@
   // API for subclasses to implement.
   class Cursor : public sqlite3_vtab_cursor {
    public:
+    // Enum for the history of calls to Filter.
+    enum class FilterHistory : uint32_t {
+      // Indicates that constraint set passed is the different to the
+      // previous Filter call.
+      kDifferent = 0,
+
+      // Indicates that the constraint set passed is the same as the previous
+      // Filter call.
+      // This can be useful for subclasses to perform optimizations on repeated
+      // nested subqueries.
+      kSame = 1,
+    };
+
     Cursor(SqliteTable* table);
     virtual ~Cursor();
 
     // Methods to be implemented by derived table classes.
 
     // Called to intialise the cursor with the constraints of the query.
-    virtual int Filter(const QueryConstraints& qc, sqlite3_value**) = 0;
+    virtual int Filter(const QueryConstraints& qc,
+                       sqlite3_value**,
+                       FilterHistory) = 0;
 
     // Called to forward the cursor to the next row in the table.
     virtual int Next() = 0;
@@ -233,11 +248,14 @@
     module->xBestIndex = [](sqlite3_vtab* t, sqlite3_index_info* i) {
       return static_cast<TTable*>(t)->BestIndexInternal(i);
     };
-    module->xFilter = [](sqlite3_vtab_cursor* c, int i, const char* s, int a,
+    module->xFilter = [](sqlite3_vtab_cursor* vc, int i, const char* s, int a,
                          sqlite3_value** v) {
-      const auto& qc =
-          static_cast<Cursor*>(c)->table_->ParseConstraints(i, s, a);
-      return static_cast<TCursor*>(c)->Filter(qc, v);
+      auto* c = static_cast<Cursor*>(vc);
+      bool is_cached = c->table_->ReadConstraints(i, s, a);
+
+      auto history = is_cached ? Cursor::FilterHistory::kSame
+                               : Cursor::FilterHistory::kDifferent;
+      return static_cast<TCursor*>(c)->Filter(c->table_->qc_cache_, v, history);
     };
     module->xNext = [](sqlite3_vtab_cursor* c) {
       return static_cast<TCursor*>(c)->Next();
@@ -315,9 +333,7 @@
     };
   }
 
-  const QueryConstraints& ParseConstraints(int idxNum,
-                                           const char* idxStr,
-                                           int argc);
+  bool ReadConstraints(int idxNum, const char* idxStr, int argc);
 
   // Overriden functions from sqlite3_vtab.
   int OpenInternal(sqlite3_vtab_cursor**);
diff --git a/src/trace_processor/stats_table.cc b/src/trace_processor/stats_table.cc
index 8881897..ab4599a 100644
--- a/src/trace_processor/stats_table.cc
+++ b/src/trace_processor/stats_table.cc
@@ -55,7 +55,9 @@
 StatsTable::Cursor::Cursor(StatsTable* table)
     : SqliteTable::Cursor(table), table_(table), storage_(table->storage_) {}
 
-int StatsTable::Cursor::Filter(const QueryConstraints&, sqlite3_value**) {
+int StatsTable::Cursor::Filter(const QueryConstraints&,
+                               sqlite3_value**,
+                               FilterHistory) {
   *this = Cursor(table_);
   return SQLITE_OK;
 }
diff --git a/src/trace_processor/stats_table.h b/src/trace_processor/stats_table.h
index 3a1a591..3a25413 100644
--- a/src/trace_processor/stats_table.h
+++ b/src/trace_processor/stats_table.h
@@ -38,7 +38,9 @@
     Cursor(StatsTable*);
 
     // Implementation of SqliteTable::Cursor.
-    int Filter(const QueryConstraints&, sqlite3_value**) override;
+    int Filter(const QueryConstraints&,
+               sqlite3_value**,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/trace_processor/storage_table.cc b/src/trace_processor/storage_table.cc
index aec5810..09300d2 100644
--- a/src/trace_processor/storage_table.cc
+++ b/src/trace_processor/storage_table.cc
@@ -170,7 +170,8 @@
     : SqliteTable::Cursor(table), table_(table) {}
 
 int StorageTable::Cursor::Filter(const QueryConstraints& qc,
-                                 sqlite3_value** argv) {
+                                 sqlite3_value** argv,
+                                 FilterHistory) {
   iterator_ = table_->CreateBestRowIterator(qc, argv);
   if (!iterator_)
     return SQLITE_ERROR;
diff --git a/src/trace_processor/storage_table.h b/src/trace_processor/storage_table.h
index 74247f6..e03a776 100644
--- a/src/trace_processor/storage_table.h
+++ b/src/trace_processor/storage_table.h
@@ -37,7 +37,9 @@
     Cursor(StorageTable* table);
 
     // Implementation of SqliteTable::Cursor.
-    int Filter(const QueryConstraints& qc, sqlite3_value** argv) override;
+    int Filter(const QueryConstraints& qc,
+               sqlite3_value** argv,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/trace_processor/tables/macros_benchmark.cc b/src/trace_processor/tables/macros_benchmark.cc
index 779acb2..8150371 100644
--- a/src/trace_processor/tables/macros_benchmark.cc
+++ b/src/trace_processor/tables/macros_benchmark.cc
@@ -44,6 +44,32 @@
 }  // namespace trace_processor
 }  // namespace perfetto
 
+namespace {
+
+bool IsBenchmarkFunctionalOnly() {
+  return getenv("BENCHMARK_FUNCTIONAL_TEST_ONLY") != nullptr;
+}
+
+void TableFilterArgs(benchmark::internal::Benchmark* b) {
+  if (IsBenchmarkFunctionalOnly()) {
+    b->Arg(1024);
+  } else {
+    b->RangeMultiplier(8);
+    b->Range(1024, 2 * 1024 * 1024);
+  }
+}
+
+void TableSortArgs(benchmark::internal::Benchmark* b) {
+  if (IsBenchmarkFunctionalOnly()) {
+    b->Arg(64);
+  } else {
+    b->RangeMultiplier(8);
+    b->Range(1024, 256 * 1024);
+  }
+}
+
+}  // namespace
+
 using perfetto::trace_processor::ChildTestTable;
 using perfetto::trace_processor::RootTestTable;
 using perfetto::trace_processor::SqlValue;
@@ -80,9 +106,7 @@
       it = child.IterateRows();
   }
 }
-BENCHMARK(BM_TableIteratorChild)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableIteratorChild)->Apply(TableFilterArgs);
 
 static void BM_TableFilterIdColumn(benchmark::State& state) {
   StringPool pool;
@@ -96,9 +120,7 @@
     benchmark::DoNotOptimize(root.Filter({root.id().eq(SqlValue::Long(30))}));
   }
 }
-BENCHMARK(BM_TableFilterIdColumn)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterIdColumn)->Apply(TableFilterArgs);
 
 static void BM_TableFilterRootNonNullEqMatchMany(benchmark::State& state) {
   StringPool pool;
@@ -118,9 +140,7 @@
         root.Filter({root.root_non_null().eq(SqlValue::Long(0))}));
   }
 }
-BENCHMARK(BM_TableFilterRootNonNullEqMatchMany)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterRootNonNullEqMatchMany)->Apply(TableFilterArgs);
 
 static void BM_TableFilterRootNullableEqMatchMany(benchmark::State& state) {
   StringPool pool;
@@ -144,9 +164,7 @@
         root.Filter({root.root_nullable().eq(SqlValue::Long(1))}));
   }
 }
-BENCHMARK(BM_TableFilterRootNullableEqMatchMany)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterRootNullableEqMatchMany)->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildNonNullEqMatchMany(benchmark::State& state) {
   StringPool pool;
@@ -169,9 +187,7 @@
         child.Filter({child.child_non_null().eq(SqlValue::Long(0))}));
   }
 }
-BENCHMARK(BM_TableFilterChildNonNullEqMatchMany)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterChildNonNullEqMatchMany)->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildNullableEqMatchMany(benchmark::State& state) {
   StringPool pool;
@@ -197,9 +213,7 @@
         child.Filter({child.child_nullable().eq(SqlValue::Long(1))}));
   }
 }
-BENCHMARK(BM_TableFilterChildNullableEqMatchMany)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterChildNullableEqMatchMany)->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildNonNullEqMatchManyInParent(
     benchmark::State& state) {
@@ -224,8 +238,7 @@
   }
 }
 BENCHMARK(BM_TableFilterChildNonNullEqMatchManyInParent)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+    ->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildNullableEqMatchManyInParent(
     benchmark::State& state) {
@@ -250,8 +263,7 @@
   }
 }
 BENCHMARK(BM_TableFilterChildNullableEqMatchManyInParent)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+    ->Apply(TableFilterArgs);
 
 static void BM_TableFilterParentSortedEq(benchmark::State& state) {
   StringPool pool;
@@ -270,9 +282,7 @@
         root.Filter({root.root_sorted().eq(SqlValue::Long(22))}));
   }
 }
-BENCHMARK(BM_TableFilterParentSortedEq)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterParentSortedEq)->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildSortedEq(benchmark::State& state) {
   StringPool pool;
@@ -293,9 +303,7 @@
         child.Filter({child.child_sorted().eq(SqlValue::Long(22))}));
   }
 }
-BENCHMARK(BM_TableFilterChildSortedEq)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterChildSortedEq)->Apply(TableFilterArgs);
 
 static void BM_TableFilterChildSortedEqInParent(benchmark::State& state) {
   StringPool pool;
@@ -319,9 +327,7 @@
         child.Filter({child.root_sorted().eq(SqlValue::Long(22))}));
   }
 }
-BENCHMARK(BM_TableFilterChildSortedEqInParent)
-    ->RangeMultiplier(8)
-    ->Range(1024, 2 * 1024 * 1024);
+BENCHMARK(BM_TableFilterChildSortedEqInParent)->Apply(TableFilterArgs);
 
 static void BM_TableSortRootNonNull(benchmark::State& state) {
   StringPool pool;
@@ -342,7 +348,7 @@
     benchmark::DoNotOptimize(root.Sort({root.root_non_null().ascending()}));
   }
 }
-BENCHMARK(BM_TableSortRootNonNull)->RangeMultiplier(8)->Range(1024, 256 * 1024);
+BENCHMARK(BM_TableSortRootNonNull)->Apply(TableSortArgs);
 
 static void BM_TableSortRootNullable(benchmark::State& state) {
   StringPool pool;
@@ -365,9 +371,7 @@
     benchmark::DoNotOptimize(root.Sort({root.root_nullable().ascending()}));
   }
 }
-BENCHMARK(BM_TableSortRootNullable)
-    ->RangeMultiplier(8)
-    ->Range(1024, 256 * 1024);
+BENCHMARK(BM_TableSortRootNullable)->Apply(TableSortArgs);
 
 static void BM_TableSortChildNonNullInParent(benchmark::State& state) {
   StringPool pool;
@@ -395,9 +399,7 @@
     benchmark::DoNotOptimize(child.Sort({child.root_non_null().ascending()}));
   }
 }
-BENCHMARK(BM_TableSortChildNonNullInParent)
-    ->RangeMultiplier(8)
-    ->Range(1024, 256 * 1024);
+BENCHMARK(BM_TableSortChildNonNullInParent)->Apply(TableSortArgs);
 
 static void BM_TableSortChildNullableInParent(benchmark::State& state) {
   StringPool pool;
@@ -429,6 +431,4 @@
     benchmark::DoNotOptimize(child.Sort({child.root_nullable().ascending()}));
   }
 }
-BENCHMARK(BM_TableSortChildNullableInParent)
-    ->RangeMultiplier(8)
-    ->Range(1024, 256 * 1024);
+BENCHMARK(BM_TableSortChildNullableInParent)->Apply(TableSortArgs);
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index 2561596..13f3330 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -42,18 +42,19 @@
 
 PERFETTO_TP_TABLE(PERFETTO_TP_SYMBOL_DEF);
 
-#define PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF(NAME, PARENT, C) \
-  NAME(HeapGraphObjectTable, "heap_graph_object")          \
-  PERFETTO_TP_ROOT_TABLE(PARENT, C)                        \
-  C(int64_t, upid)                                         \
-  C(int64_t, graph_sample_ts)                              \
-  C(int64_t, object_id)                                    \
-  C(int64_t, self_size)                                    \
-  C(int64_t, retained_size)                                \
-  C(int64_t, unique_retained_size)                         \
-  C(int64_t, reference_set_id)                             \
-  C(int32_t, reachable)                                    \
-  C(StringPool::Id, type_name)                             \
+#define PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF(NAME, PARENT, C)  \
+  NAME(HeapGraphObjectTable, "heap_graph_object")           \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                         \
+  C(int64_t, upid)                                          \
+  C(int64_t, graph_sample_ts)                               \
+  C(int64_t, object_id)                                     \
+  C(int64_t, self_size)                                     \
+  C(int64_t, retained_size)                                 \
+  C(int64_t, unique_retained_size)                          \
+  C(int64_t, reference_set_id)                              \
+  C(int32_t, reachable)                                     \
+  C(StringPool::Id, type_name)                              \
+  C(base::Optional<StringPool::Id>, deobfuscated_type_name) \
   C(base::Optional<StringPool::Id>, root_type)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF);
@@ -64,7 +65,8 @@
   C(int64_t, reference_set_id)                                \
   C(int64_t, owner_id)                                        \
   C(int64_t, owned_id)                                        \
-  C(StringPool::Id, field_name)
+  C(StringPool::Id, field_name)                               \
+  C(base::Optional<StringPool::Id>, deobfuscated_field_name)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_REFERENCE_DEF);
 
diff --git a/src/trace_processor/thread_table.cc b/src/trace_processor/thread_table.cc
index c98127d..1ead7c5 100644
--- a/src/trace_processor/thread_table.cc
+++ b/src/trace_processor/thread_table.cc
@@ -73,7 +73,8 @@
     : SqliteTable::Cursor(table), storage_(table->storage_), table_(table) {}
 
 int ThreadTable::Cursor::Filter(const QueryConstraints& qc,
-                                sqlite3_value** argv) {
+                                sqlite3_value** argv,
+                                FilterHistory) {
   *this = Cursor(table_);
 
   min_ = 0;
diff --git a/src/trace_processor/thread_table.h b/src/trace_processor/thread_table.h
index 43484d1..152399f 100644
--- a/src/trace_processor/thread_table.h
+++ b/src/trace_processor/thread_table.h
@@ -43,7 +43,9 @@
     Cursor(ThreadTable* table);
 
     // Implementation of Table::Cursor.
-    int Filter(const QueryConstraints&, sqlite3_value**) override;
+    int Filter(const QueryConstraints&,
+               sqlite3_value**,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 7243b42..2d40985 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -115,6 +115,7 @@
     StringId name_id = 0;
     uint32_t pid = 0;
     base::Optional<UniquePid> parent_upid;
+    base::Optional<uint32_t> uid;
   };
 
   // Information about a unique thread seen in a trace.
diff --git a/src/trace_processor/vulkan_memory_tracker.cc b/src/trace_processor/vulkan_memory_tracker.cc
index 0ffebc1..310f73e 100644
--- a/src/trace_processor/vulkan_memory_tracker.cc
+++ b/src/trace_processor/vulkan_memory_tracker.cc
@@ -85,18 +85,37 @@
 }
 
 StringId VulkanMemoryTracker::FindMemoryTypeCounterString(
-    uint32_t memory_type) {
+    uint32_t memory_type,
+    DeviceCounterType counter_type) {
   StringId res = kNullStringId;
-  auto it = memory_type_counter_string_map_.find(memory_type);
-  if (it == memory_type_counter_string_map_.end()) {
-    auto type_counter_str =
-        vulkan_device_memory_counter_str_ + std::to_string(memory_type);
-    res = context_->storage->InternString(
-        base::StringView(type_counter_str.c_str(), type_counter_str.length()));
-    memory_type_counter_string_map_.emplace(memory_type, res);
-    return res;
+  std::unordered_map<uint32_t, StringId>::iterator it;
+  std::string type_counter_str;
+  switch (counter_type) {
+    case DeviceCounterType::kAllocationCounter:
+      it = memory_type_allocation_counter_string_map_.find(memory_type);
+      if (it == memory_type_allocation_counter_string_map_.end()) {
+        type_counter_str = vulkan_device_memory_counter_str_ +
+                           std::to_string(memory_type) + ".allocation";
+        res = context_->storage->InternString(base::StringView(
+            type_counter_str.c_str(), type_counter_str.length()));
+        memory_type_allocation_counter_string_map_.emplace(memory_type, res);
+      } else {
+        res = it->second;
+      }
+      break;
+    case DeviceCounterType::kBindCounter:
+      it = memory_type_bind_counter_string_map_.find(memory_type);
+      if (it == memory_type_bind_counter_string_map_.end()) {
+        type_counter_str = vulkan_device_memory_counter_str_ +
+                           std::to_string(memory_type) + ".bind";
+        res = context_->storage->InternString(base::StringView(
+            type_counter_str.c_str(), type_counter_str.length()));
+        memory_type_bind_counter_string_map_.emplace(memory_type, res);
+      } else {
+        res = it->second;
+      }
+      break;
   }
-  res = it->second;
   return res;
 }
 
diff --git a/src/trace_processor/vulkan_memory_tracker.h b/src/trace_processor/vulkan_memory_tracker.h
index a501f4a..f7cc9b8 100644
--- a/src/trace_processor/vulkan_memory_tracker.h
+++ b/src/trace_processor/vulkan_memory_tracker.h
@@ -31,6 +31,11 @@
 
 class VulkanMemoryTracker {
  public:
+  enum class DeviceCounterType {
+    kAllocationCounter = 0,
+    kBindCounter = 1,
+  };
+
   explicit VulkanMemoryTracker(TraceProcessorContext* context);
   ~VulkanMemoryTracker() = default;
 
@@ -52,7 +57,8 @@
   StringId FindOperationString(VulkanMemoryEvent::Operation);
   StringId FindAllocationScopeString(VulkanMemoryEvent::AllocationScope);
   StringId FindAllocationScopeCounterString(VulkanMemoryEvent::AllocationScope);
-  StringId FindMemoryTypeCounterString(uint32_t /*memory_type*/);
+  StringId FindMemoryTypeCounterString(uint32_t /*memory_type*/,
+                                       DeviceCounterType);
 
  private:
   TraceProcessorContext* const context_;
@@ -64,7 +70,9 @@
   std::vector<StringId> scope_strs_id_;
   std::vector<StringId> scope_counter_strs_id_;
   std::unordered_map<uint32_t /*memory_type*/, StringId>
-      memory_type_counter_string_map_;
+      memory_type_allocation_counter_string_map_;
+  std::unordered_map<uint32_t /*memory_type*/, StringId>
+      memory_type_bind_counter_string_map_;
 
   void SetupSourceAndTypeInternedStrings();
 };
diff --git a/src/trace_processor/window_operator_table.cc b/src/trace_processor/window_operator_table.cc
index a7a49e5..1d801f8 100644
--- a/src/trace_processor/window_operator_table.cc
+++ b/src/trace_processor/window_operator_table.cc
@@ -103,7 +103,8 @@
     : SqliteTable::Cursor(table), table_(table) {}
 
 int WindowOperatorTable::Cursor::Filter(const QueryConstraints& qc,
-                                        sqlite3_value** argv) {
+                                        sqlite3_value** argv,
+                                        FilterHistory) {
   *this = Cursor(table_);
   window_start_ = table_->window_start_;
   window_end_ = table_->window_start_ + table_->window_dur_;
diff --git a/src/trace_processor/window_operator_table.h b/src/trace_processor/window_operator_table.h
index 41fbbb7..504ec13 100644
--- a/src/trace_processor/window_operator_table.h
+++ b/src/trace_processor/window_operator_table.h
@@ -43,7 +43,9 @@
     Cursor(WindowOperatorTable*);
 
     // Implementation of SqliteTable::Cursor.
-    int Filter(const QueryConstraints& qc, sqlite3_value**) override;
+    int Filter(const QueryConstraints& qc,
+               sqlite3_value**,
+               FilterHistory) override;
     int Next() override;
     int Eof() override;
     int Column(sqlite3_context*, int N) override;
diff --git a/src/traced/probes/ps/process_stats_data_source.cc b/src/traced/probes/ps/process_stats_data_source.cc
index 6c9d2da..de68e0d 100644
--- a/src/traced/probes/ps/process_stats_data_source.cc
+++ b/src/traced/probes/ps/process_stats_data_source.cc
@@ -171,9 +171,14 @@
 }
 
 void ProcessStatsDataSource::OnPids(const std::vector<int32_t>& pids) {
-  PERFETTO_METATRACE_SCOPED(TAG_PROC_POLLERS, PS_ON_PIDS);
   if (!enable_on_demand_dumps_)
     return;
+  WriteProcessTree(pids);
+}
+
+void ProcessStatsDataSource::WriteProcessTree(
+    const std::vector<int32_t>& pids) {
+  PERFETTO_METATRACE_SCOPED(TAG_PROC_POLLERS, PS_ON_PIDS);
   PERFETTO_DCHECK(!cur_ps_tree_);
   int pids_scanned = 0;
   for (int32_t pid : pids) {
@@ -414,7 +419,7 @@
 
   // Ensure that we write once long-term process info (e.g., name) for new pids
   // that we haven't seen before.
-  OnPids(pids);
+  WriteProcessTree(pids);
 }
 
 // Returns true if the stats for the given |pid| have been written, false it
diff --git a/src/traced/probes/ps/process_stats_data_source.h b/src/traced/probes/ps/process_stats_data_source.h
index b2fa51c..f301e5d 100644
--- a/src/traced/probes/ps/process_stats_data_source.h
+++ b/src/traced/probes/ps/process_stats_data_source.h
@@ -105,6 +105,9 @@
   void WriteAllProcessStats();
   bool WriteMemCounters(int32_t pid, const std::string& proc_status);
 
+  // Scans /proc/pid/status and writes the ProcessTree packet for input pids.
+  void WriteProcessTree(const std::vector<int32_t>& pids);
+
   // Read and "latch" the current procfs scan-start timestamp, which
   // we reset only in FinalizeCurPacket.
   uint64_t CacheProcFsScanStartTimestamp();
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 844da88..7a8ef42 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -22,9 +22,6 @@
   public_deps = [
     ":common",
     "../../include/perfetto/ext/tracing/core",
-    "../../protos/perfetto/common:lite",
-    "../../protos/perfetto/trace:minimal_lite",
-    "../../protos/perfetto/trace:trusted_lite",
     "../../protos/perfetto/trace:zero",
     "../../protos/perfetto/trace/interned_data:zero",
     "../../protos/perfetto/trace/track_event:zero",
@@ -32,7 +29,8 @@
   deps = [
     "../../gn:default_deps",
     "../../include/perfetto/tracing",
-    "../../protos/perfetto/config:lite",
+    "../../protos/perfetto/common:zero",
+    "../../protos/perfetto/config:zero",
     "../../protos/perfetto/trace/perfetto:zero",  # For MetatraceWriter.
     "../base",
     "../protozero",
@@ -61,6 +59,7 @@
     "core/tracing_service_impl.h",
     "core/virtual_destructors.cc",
   ]
+  assert_no_deps = [ "//gn:protobuf_lite" ]
 }
 
 # TODO(primiano): Remove this target as soon as chromium's
@@ -252,7 +251,7 @@
   deps = [
     ":common",
     "../../include/perfetto/tracing/core",
-    "../../protos/perfetto/config:lite",
+    "../../protos/perfetto/config:cpp",
     "../base",
     "../tracing",
   ]
diff --git a/src/tracing/core/trace_packet_unittest.cc b/src/tracing/core/trace_packet_unittest.cc
index 0469ae8..c8fb8f9 100644
--- a/src/tracing/core/trace_packet_unittest.cc
+++ b/src/tracing/core/trace_packet_unittest.cc
@@ -20,36 +20,11 @@
 
 #include "protos/perfetto/trace/trace.pb.h"
 #include "protos/perfetto/trace/trace_packet.pb.h"
-#include "protos/perfetto/trace/trusted_packet.pb.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
 namespace {
 
-static_assert(static_cast<int>(TracePacket::kPacketFieldNumber) ==
-                  static_cast<int>(protos::Trace::kPacketFieldNumber),
-              "packet field id mismatch");
-
-static_assert(
-    static_cast<int>(protos::TracePacket::kTrustedUidFieldNumber) ==
-        static_cast<int>(protos::TrustedPacket::kTrustedUidFieldNumber),
-    "trusted_uid field id mismatch");
-
-static_assert(
-    static_cast<int>(protos::TracePacket::kTraceConfigFieldNumber) ==
-        static_cast<int>(protos::TrustedPacket::kTraceConfigFieldNumber),
-    "trace_config field id mismatch");
-
-static_assert(
-    static_cast<int>(protos::TracePacket::kTraceStatsFieldNumber) ==
-        static_cast<int>(protos::TrustedPacket::kTraceStatsFieldNumber),
-    "trace_stats field id mismatch");
-
-static_assert(
-    static_cast<int>(protos::TracePacket::kClockSnapshotFieldNumber) ==
-        static_cast<int>(protos::TrustedPacket::kClockSnapshotFieldNumber),
-    "clock_snapshot field id mismatch");
-
 TEST(TracePacketTest, Simple) {
   protos::TracePacket proto;
   proto.mutable_for_testing()->set_str("string field");
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 26331d7..0e3b424 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -49,15 +49,20 @@
 #include "perfetto/ext/tracing/core/shared_memory_abi.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
 #include "perfetto/ext/tracing/core/trace_writer.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/protozero/static_buffer.h"
 #include "perfetto/tracing/core/data_source_descriptor.h"
 #include "perfetto/tracing/core/tracing_service_state.h"
 #include "src/tracing/core/packet_stream_validator.h"
 #include "src/tracing/core/shared_memory_arbiter_impl.h"
 #include "src/tracing/core/trace_buffer.h"
 
-#include "protos/perfetto/trace/clock_snapshot.pb.h"
-#include "protos/perfetto/trace/system_info.pb.h"
-#include "protos/perfetto/trace/trusted_packet.pb.h"
+#include "protos/perfetto/common/trace_stats.pbzero.h"
+#include "protos/perfetto/config/trace_config.pbzero.h"
+#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
+#include "protos/perfetto/trace/system_info.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+#include "protos/perfetto/trace/trigger.pbzero.h"
 
 // General note: this class must assume that Producers are malicious and will
 // try to crash / exploit this class. We can trust pointers because they come
@@ -132,6 +137,14 @@
   return static_cast<int32_t>(acc);
 }
 
+void SerializeAndAppendPacket(std::vector<TracePacket>* packets,
+                              std::vector<uint8_t> packet) {
+  Slice slice = Slice::Allocate(packet.size());
+  memcpy(slice.own_data(), packet.data(), packet.size());
+  packets->emplace_back();
+  packets->back().AddSlice(std::move(slice));
+}
+
 }  // namespace
 
 // These constants instead are defined in the header because are used by tests.
@@ -1540,21 +1553,18 @@
       // truncated packets are also rejected, so the producer can't give us a
       // partial packet (e.g., a truncated string) which only becomes valid when
       // the trusted data is appended here.
-      protos::TrustedPacket trusted_packet;
-      trusted_packet.set_trusted_uid(
+      Slice slice = Slice::Allocate(32);
+      protozero::StaticBuffered<protos::pbzero::TracePacket> trusted_packet(
+          slice.own_data(), slice.size);
+      trusted_packet->set_trusted_uid(
           static_cast<int32_t>(sequence_properties.producer_uid_trusted));
-      trusted_packet.set_trusted_packet_sequence_id(
+      trusted_packet->set_trusted_packet_sequence_id(
           tracing_session->GetPacketSequenceID(
               sequence_properties.producer_id_trusted,
               sequence_properties.writer_id));
       if (previous_packet_dropped)
-        trusted_packet.set_previous_packet_dropped(previous_packet_dropped);
-      static constexpr size_t kTrustedBufSize = 16;
-      Slice slice = Slice::Allocate(kTrustedBufSize);
-      PERFETTO_CHECK(
-          trusted_packet.SerializeToArray(slice.own_data(), kTrustedBufSize));
-      slice.size = static_cast<size_t>(trusted_packet.GetCachedSize());
-      PERFETTO_DCHECK(slice.size > 0 && slice.size <= kTrustedBufSize);
+        trusted_packet->set_previous_packet_dropped(previous_packet_dropped);
+      slice.size = trusted_packet.Finalize();
       packet.AddSlice(std::move(slice));
 
       // Append the packet (inclusive of the trusted uid) to |packets|.
@@ -2160,23 +2170,17 @@
   // The sync marks are used to tokenize large traces efficiently.
   // See description in trace_packet.proto.
   if (sync_marker_packet_size_ == 0) {
-    // Serialize the marker and the uid separately to guarantee that the marker
-    // is serialzied at the end and is adjacent to the start of the next packet.
-    int size_left = static_cast<int>(sizeof(sync_marker_packet_));
-    uint8_t* dst = &sync_marker_packet_[0];
-    protos::TrustedPacket packet;
-    packet.set_trusted_uid(static_cast<int32_t>(uid_));
-    packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-    PERFETTO_CHECK(packet.SerializeToArray(dst, size_left));
-    size_left -= packet.ByteSize();
-    sync_marker_packet_size_ += static_cast<size_t>(packet.ByteSize());
-    dst += sync_marker_packet_size_;
+    // The marker ABI expects that the marker is written after the uid.
+    // Protozero guarantees that fields are written in the same order of the
+    // calls. The ResynchronizeTraceStreamUsingSyncMarker test verifies the ABI.
+    protozero::StaticBuffered<protos::pbzero::TracePacket> packet(
+        &sync_marker_packet_[0], sizeof(sync_marker_packet_));
+    packet->set_trusted_uid(static_cast<int32_t>(uid_));
+    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
 
-    packet.Clear();
-    packet.set_synchronization_marker(kSyncMarker, sizeof(kSyncMarker));
-    PERFETTO_CHECK(packet.SerializeToArray(dst, size_left));
-    sync_marker_packet_size_ += static_cast<size_t>(packet.ByteSize());
-    PERFETTO_CHECK(sync_marker_packet_size_ <= sizeof(sync_marker_packet_));
+    // Keep this last.
+    packet->set_synchronization_marker(kSyncMarker, sizeof(kSyncMarker));
+    sync_marker_packet_size_ = packet.Finalize();
   }
   packets->emplace_back();
   packets->back().AddSlice(&sync_marker_packet_[0], sync_marker_packet_size_);
@@ -2184,33 +2188,36 @@
 
 void TracingServiceImpl::SnapshotClocks(std::vector<TracePacket>* packets,
                                         bool set_root_timestamp) {
-  protos::TrustedPacket packet;
-  protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot();
+  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
+  uint64_t root_timestamp_ns = 0;
+  auto* clock_snapshot = packet->set_clock_snapshot();
 
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) && \
     !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
   struct {
     clockid_t id;
-    protos::ClockSnapshot::Clock::BuiltinClocks type;
+    protos::pbzero::ClockSnapshot::Clock::BuiltinClocks type;
     struct timespec ts;
   } clocks[] = {
-      {CLOCK_BOOTTIME, protos::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
+      {CLOCK_BOOTTIME, protos::pbzero::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
       {CLOCK_REALTIME_COARSE,
-       protos::ClockSnapshot::Clock::REALTIME_COARSE,
+       protos::pbzero::ClockSnapshot::Clock::REALTIME_COARSE,
        {0, 0}},
       {CLOCK_MONOTONIC_COARSE,
-       protos::ClockSnapshot::Clock::MONOTONIC_COARSE,
+       protos::pbzero::ClockSnapshot::Clock::MONOTONIC_COARSE,
        {0, 0}},
-      {CLOCK_REALTIME, protos::ClockSnapshot::Clock::REALTIME, {0, 0}},
-      {CLOCK_MONOTONIC, protos::ClockSnapshot::Clock::MONOTONIC, {0, 0}},
+      {CLOCK_REALTIME, protos::pbzero::ClockSnapshot::Clock::REALTIME, {0, 0}},
+      {CLOCK_MONOTONIC,
+       protos::pbzero::ClockSnapshot::Clock::MONOTONIC,
+       {0, 0}},
       {CLOCK_MONOTONIC_RAW,
-       protos::ClockSnapshot::Clock::MONOTONIC_RAW,
+       protos::pbzero::ClockSnapshot::Clock::MONOTONIC_RAW,
        {0, 0}},
       {CLOCK_PROCESS_CPUTIME_ID,
-       protos::ClockSnapshot::Clock::PROCESS_CPUTIME,
+       protos::pbzero::ClockSnapshot::Clock::PROCESS_CPUTIME,
        {0, 0}},
       {CLOCK_THREAD_CPUTIME_ID,
-       protos::ClockSnapshot::Clock::THREAD_CPUTIME,
+       protos::pbzero::ClockSnapshot::Clock::THREAD_CPUTIME,
        {0, 0}},
   };
   // First snapshot all the clocks as atomically as we can.
@@ -2220,11 +2227,11 @@
   }
   for (auto& clock : clocks) {
     if (set_root_timestamp &&
-        clock.type == protos::ClockSnapshot::Clock::BOOTTIME) {
-      packet.set_timestamp(
-          static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count()));
+        clock.type == protos::pbzero::ClockSnapshot::Clock::BOOTTIME) {
+      root_timestamp_ns =
+          static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count());
     }
-    protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks();
+    auto* c = clock_snapshot->add_clocks();
     c->set_clock_id(static_cast<uint32_t>(clock.type));
     c->set_timestamp(
         static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count()));
@@ -2232,32 +2239,27 @@
 #else   // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
   auto wall_time_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
   if (set_root_timestamp)
-    packet.set_timestamp(wall_time_ns);
-  protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks();
-  c->set_clock_id(protos::ClockSnapshot::Clock::MONOTONIC);
+    root_timestamp_ns = wall_time_ns;
+  auto* c = clock_snapshot->add_clocks();
+  c->set_clock_id(protos::pbzero::ClockSnapshot::Clock::MONOTONIC);
   c->set_timestamp(wall_time_ns);
 #endif  // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
 
-  packet.set_trusted_uid(static_cast<int32_t>(uid_));
-  packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-  Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
-  PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
-  packets->emplace_back();
-  packets->back().AddSlice(std::move(slice));
+  if (root_timestamp_ns)
+    packet->set_timestamp(root_timestamp_ns);
+  packet->set_trusted_uid(static_cast<int32_t>(uid_));
+  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+
+  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
 }
 
 void TracingServiceImpl::SnapshotStats(TracingSession* tracing_session,
                                        std::vector<TracePacket>* packets) {
-  protos::TrustedPacket packet;
-  packet.set_trusted_uid(static_cast<int32_t>(uid_));
-  packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-
-  protos::TraceStats* trace_stats = packet.mutable_trace_stats();
-  GetTraceStats(tracing_session).ToProto(trace_stats);
-  Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
-  PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
-  packets->emplace_back();
-  packets->back().AddSlice(std::move(slice));
+  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
+  packet->set_trusted_uid(static_cast<int32_t>(uid_));
+  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+  GetTraceStats(tracing_session).Serialize(packet->set_trace_stats());
+  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
 }
 
 TraceStats TracingServiceImpl::GetTraceStats(TracingSession* tracing_session) {
@@ -2291,14 +2293,11 @@
   if (tracing_session->did_emit_config)
     return;
   tracing_session->did_emit_config = true;
-  protos::TrustedPacket packet;
-  tracing_session->config.ToProto(packet.mutable_trace_config());
-  packet.set_trusted_uid(static_cast<int32_t>(uid_));
-  packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-  Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
-  PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
-  packets->emplace_back();
-  packets->back().AddSlice(std::move(slice));
+  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
+  packet->set_trusted_uid(static_cast<int32_t>(uid_));
+  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+  tracing_session->config.Serialize(packet->set_trace_config());
+  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
 }
 
 void TracingServiceImpl::MaybeEmitSystemInfo(
@@ -2307,24 +2306,21 @@
   if (tracing_session->did_emit_system_info)
     return;
   tracing_session->did_emit_system_info = true;
-  protos::TrustedPacket packet;
+  protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-  protos::SystemInfo* info = packet.mutable_system_info();
+  auto* info = packet->set_system_info();
   struct utsname uname_info;
   if (uname(&uname_info) == 0) {
-    protos::Utsname* utsname_info = info->mutable_utsname();
+    auto* utsname_info = info->set_utsname();
     utsname_info->set_sysname(uname_info.sysname);
     utsname_info->set_version(uname_info.version);
     utsname_info->set_machine(uname_info.machine);
     utsname_info->set_release(uname_info.release);
   }
 #endif
-  packet.set_trusted_uid(static_cast<int32_t>(uid_));
-  packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-  Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
-  PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
-  packets->emplace_back();
-  packets->back().AddSlice(std::move(slice));
+  packet->set_trusted_uid(static_cast<int32_t>(uid_));
+  packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+  SerializeAndAppendPacket(packets, packet.SerializeAsArray());
 }
 
 void TracingServiceImpl::MaybeEmitReceivedTriggers(
@@ -2335,20 +2331,16 @@
   for (size_t i = tracing_session->num_triggers_emitted_into_trace;
        i < tracing_session->received_triggers.size(); ++i) {
     const auto& info = tracing_session->received_triggers[i];
-    protos::TrustedPacket packet;
-
-    protos::Trigger* trigger = packet.mutable_trigger();
+    protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
+    auto* trigger = packet->set_trigger();
     trigger->set_trigger_name(info.trigger_name);
     trigger->set_producer_name(info.producer_name);
     trigger->set_trusted_producer_uid(static_cast<int32_t>(info.producer_uid));
 
-    packet.set_timestamp(info.boot_time_ns);
-    packet.set_trusted_uid(static_cast<int32_t>(uid_));
-    packet.set_trusted_packet_sequence_id(kServicePacketSequenceID);
-    Slice slice = Slice::Allocate(static_cast<size_t>(packet.ByteSize()));
-    PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
-    packets->emplace_back();
-    packets->back().AddSlice(std::move(slice));
+    packet->set_timestamp(info.boot_time_ns);
+    packet->set_trusted_uid(static_cast<int32_t>(uid_));
+    packet->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+    SerializeAndAppendPacket(packets, packet.SerializeAsArray());
     ++tracing_session->num_triggers_emitted_into_trace;
   }
 }
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index 1ce6f93..a185f25 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -37,7 +37,6 @@
 #include "perfetto/tracing/trace_writer_base.h"
 #include "perfetto/tracing/tracing.h"
 #include "perfetto/tracing/tracing_backend.h"
-#include "protos/perfetto/config/trace_config.pb.h"
 #include "src/tracing/internal/in_process_tracing_backend.h"
 #include "src/tracing/internal/system_tracing_backend.h"
 
@@ -59,12 +58,8 @@
 
 uint64_t ComputeConfigHash(const DataSourceConfig& config) {
   base::Hash hasher;
-  perfetto::protos::DataSourceConfig config_proto;
-  config.ToProto(&config_proto);
-  std::string config_bytes;
-  bool serialized = config_proto.SerializeToString(&config_bytes);
-  PERFETTO_DCHECK(serialized);
-  hasher.Update(&config_bytes[0], config_bytes.size());
+  std::string config_bytes = config.SerializeAsString();
+  hasher.Update(config_bytes.data(), config_bytes.size());
   return hasher.digest();
 }
 
diff --git a/test/metrics/android_process_growth.out b/test/metrics/android_process_growth.out
deleted file mode 100644
index e108056..0000000
--- a/test/metrics/android_process_growth.out
+++ /dev/null
@@ -1,14 +0,0 @@
-android_process_growth {
-  instance_metrics {
-    pid: 3
-    process_name: "com.google.android.calendar"
-    anon_and_swap_start_value: 2000
-    anon_and_swap_change_bytes: 4000
-  }
-  instance_metrics {
-    pid: 4
-    process_name: "com.google.android.calendar"
-    anon_and_swap_start_value: 150
-    anon_and_swap_change_bytes: 0
-  }
-}
diff --git a/test/metrics/android_process_growth.py b/test/metrics/android_process_growth.py
deleted file mode 100644
index 75bdece..0000000
--- a/test/metrics/android_process_growth.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/python
-# 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.
-
-from os import sys, path
-
-sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
-import synth_common
-
-anon_member = 1
-swap_member = 2
-
-trace = synth_common.create_trace()
-trace.add_process_tree_packet()
-trace.add_process(1, 0, 'init')
-trace.add_process(2, 1, 'system_server')
-trace.add_process(3, 1, 'com.google.android.calendar')
-trace.add_process(4, 1, 'com.google.android.calendar')
-
-trace.add_ftrace_packet(cpu=0)
-trace.add_rss_stat(100, 3, anon_member, 1000)
-trace.add_rss_stat(100, 3, swap_member, 1000)
-trace.add_rss_stat(100, 4, anon_member, 100)
-trace.add_rss_stat(100, 4, swap_member, 50)
-
-trace.add_rss_stat(200, 3, anon_member, 2000)
-trace.add_rss_stat(200, 3, swap_member, 2000)
-trace.add_rss_stat(200, 4, anon_member, 1000)
-trace.add_rss_stat(200, 4, swap_member, 100)
-
-trace.add_rss_stat(300, 3, anon_member, 3000)
-trace.add_rss_stat(300, 3, swap_member, 3000)
-trace.add_rss_stat(300, 4, anon_member, 50)
-trace.add_rss_stat(300, 4, swap_member, 100)
-
-print(trace.trace.SerializeToString())
diff --git a/test/metrics/heap_profile.textproto b/test/metrics/heap_profile.textproto
index 831b002..d7dcfd7 100644
--- a/test/metrics/heap_profile.textproto
+++ b/test/metrics/heap_profile.textproto
@@ -4,11 +4,13 @@
       pid: 1
       ppid: 0
       cmdline: "init"
+      uid: 0
     }
     processes {
       pid: 2
       ppid: 1
       cmdline: "system_server"
+      uid: 1000
     }
   }
 }
diff --git a/test/metrics/heap_profile_callsites.out b/test/metrics/heap_profile_callsites.out
index 5f8c14c..6079714 100644
--- a/test/metrics/heap_profile_callsites.out
+++ b/test/metrics/heap_profile_callsites.out
@@ -2,6 +2,10 @@
   instance_stats {
     pid: 2
     process_name: "system_server"
+    process {
+      name: "system_server"
+      uid: 1000
+    }
     callsites {
       hash: -2067767828047084124
       parent_hash: 3061552492032359760
diff --git a/test/metrics/index b/test/metrics/index
index 8f29693..0ee6a7f 100644
--- a/test/metrics/index
+++ b/test/metrics/index
@@ -4,7 +4,6 @@
 
 # Synthetic traces
 android_mem_by_priority.py android_mem android_mem_by_priority.out
-android_process_growth.py android_process_growth android_process_growth.out
 android_lmk.py android_lmk android_mem_lmk.out
 android_ion.py android_ion android_ion.out
 
diff --git a/test/metrics/java_heap_stats.out b/test/metrics/java_heap_stats.out
index 64db708..f818457 100644
--- a/test/metrics/java_heap_stats.out
+++ b/test/metrics/java_heap_stats.out
@@ -1,7 +1,10 @@
 java_heap_stats {
   instance_stats {
     upid: 2
-    process_name: "system_server"
+    process {
+      name: "system_server"
+      uid: 1000
+    }
     samples {
       ts: 10
       heap_size: 224
diff --git a/test/synth_common.py b/test/synth_common.py
index 3383b81..142e76e 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -173,11 +173,13 @@
     if ts is not None:
       self.packet.timestamp = ts
 
-  def add_process(self, pid, ppid, cmdline):
+  def add_process(self, pid, ppid, cmdline, uid=None):
     process = self.packet.process_tree.processes.add()
     process.pid = pid
     process.ppid = ppid
     process.cmdline.append(cmdline)
+    if uid is not None:
+      process.uid = uid
     self.proc_map[pid] = cmdline
 
   def add_thread(self, tid, tgid, cmdline):
diff --git a/test/trace_processor/counters_ref_type_null.sql b/test/trace_processor/counters_ref_type_null.sql
index 557b933..36a0b90 100644
--- a/test/trace_processor/counters_ref_type_null.sql
+++ b/test/trace_processor/counters_ref_type_null.sql
@@ -1,3 +1,3 @@
-select id, counter_id, ts, value, arg_set_id, name, ref, ref_type from counters
+select ts, value, name, ref, ref_type from counters
 where name = 'MemAvailable' and ref_type is null
 limit 10
diff --git a/test/trace_processor/counters_ref_type_null_memory_counters.out b/test/trace_processor/counters_ref_type_null_memory_counters.out
index 0457994..d416b76 100644
--- a/test/trace_processor/counters_ref_type_null_memory_counters.out
+++ b/test/trace_processor/counters_ref_type_null_memory_counters.out
@@ -1,11 +1,11 @@
-"id","counter_id","ts","value","arg_set_id","name","ref","ref_type"
-4294968280,984,22240334823167,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294969268,984,22240356169836,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294970256,984,22240468594483,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294971244,984,22240566948190,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294972232,984,22240667383304,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294973220,984,22240766505085,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294974208,984,22240866794106,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294975196,984,22240968271928,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294976184,984,22241065777407,2696392704.000000,0,"MemAvailable",0,"[NULL]"
-4294977172,984,22241165839708,2696392704.000000,0,"MemAvailable",0,"[NULL]"
+"ts","value","name","ref","ref_type"
+22240334823167,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240356169836,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240468594483,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240566948190,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240667383304,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240766505085,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240866794106,2696392704.000000,"MemAvailable",0,"[NULL]"
+22240968271928,2696392704.000000,"MemAvailable",0,"[NULL]"
+22241065777407,2696392704.000000,"MemAvailable",0,"[NULL]"
+22241165839708,2696392704.000000,"MemAvailable",0,"[NULL]"
diff --git a/test/trace_processor/heap_graph.textproto b/test/trace_processor/heap_graph.textproto
index b785578..4001fcf 100644
--- a/test/trace_processor/heap_graph.textproto
+++ b/test/trace_processor/heap_graph.textproto
@@ -4,11 +4,13 @@
       pid: 1
       ppid: 0
       cmdline: "init"
+      uid: 0
     }
     processes {
       pid: 2
       ppid: 1
       cmdline: "system_server"
+      uid: 1000
     }
   }
 }
diff --git a/test/trace_processor/heap_graph_object.out b/test/trace_processor/heap_graph_object.out
index b0f9e43..b3cad4a 100644
--- a/test/trace_processor/heap_graph_object.out
+++ b/test/trace_processor/heap_graph_object.out
@@ -1,4 +1,4 @@
-"id","type","upid","graph_sample_ts","object_id","self_size","retained_size","unique_retained_size","reference_set_id","reachable","type_name","root_type"
-0,"heap_graph_object",2,10,1,64,96,96,0,1,"FactoryProducerDelegateImplActor","ROOT_JAVA_FRAME"
-1,"heap_graph_object",2,10,2,32,32,32,1,1,"Foo","[NULL]"
-2,"heap_graph_object",2,10,3,128,-1,0,1,0,"Foo","[NULL]"
+"id","type","upid","graph_sample_ts","object_id","self_size","retained_size","unique_retained_size","reference_set_id","reachable","type_name","deobfuscated_type_name","root_type"
+0,"heap_graph_object",2,10,1,64,96,96,0,1,"FactoryProducerDelegateImplActor","[NULL]","ROOT_JAVA_FRAME"
+1,"heap_graph_object",2,10,2,32,32,32,1,1,"Foo","[NULL]","[NULL]"
+2,"heap_graph_object",2,10,3,128,-1,-1,1,0,"Foo","[NULL]","[NULL]"
diff --git a/test/trace_processor/heap_graph_reference.out b/test/trace_processor/heap_graph_reference.out
index 3be9676..7cdaad2 100644
--- a/test/trace_processor/heap_graph_reference.out
+++ b/test/trace_processor/heap_graph_reference.out
@@ -1,2 +1,2 @@
-"id","type","reference_set_id","owner_id","owned_id","field_name"
-0,"heap_graph_reference",0,0,1,"FactoryProducerDelegateImplActor.foo"
+"id","type","reference_set_id","owner_id","owned_id","field_name","deobfuscated_field_name"
+0,"heap_graph_reference",0,0,1,"FactoryProducerDelegateImplActor.foo","[NULL]"
diff --git a/test/trace_processor/index b/test/trace_processor/index
index 958b11e..808b2cf 100644
--- a/test/trace_processor/index
+++ b/test/trace_processor/index
@@ -12,6 +12,7 @@
 
 # Test for the process<>thread tracking logic.
 synth_process_tracking.py process_tracking.sql process_tracking.out
+synth_process_tracking.py process_tracking_uid.sql process_tracking_uid.out
 process_tracking_short_lived_1.py process_tracking.sql process_tracking_process_tracking_short_lived_1.out
 process_tracking_short_lived_2.py process_tracking.sql process_tracking_process_tracking_short_lived_2.out
 process_tracking_exec.py process_tracking.sql process_tracking_process_tracking_exec.out
diff --git a/test/trace_processor/mm_event.out b/test/trace_processor/mm_event.out
index a26a895c2..aee7eb1 100644
--- a/test/trace_processor/mm_event.out
+++ b/test/trace_processor/mm_event.out
@@ -1,41 +1,41 @@
-"id","ts","name","value","ref","ref_type","arg_set_id"
-4294967296,1409847208580693,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967297,1409847208580693,"mem.mm.min_flt.max_lat",9.000000,0,"upid",0
-4294967298,1409847208580693,"mem.mm.min_flt.avg_lat",9.000000,0,"upid",0
-4294967299,1409847209537724,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967300,1409847209537724,"mem.mm.min_flt.max_lat",759.000000,0,"upid",0
-4294967301,1409847209537724,"mem.mm.min_flt.avg_lat",759.000000,0,"upid",0
-4294967302,1409847213761006,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967303,1409847213761006,"mem.mm.min_flt.max_lat",10.000000,0,"upid",0
-4294967304,1409847213761006,"mem.mm.min_flt.avg_lat",10.000000,0,"upid",0
-4294967305,1409847214052256,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967306,1409847214052256,"mem.mm.min_flt.max_lat",90.000000,0,"upid",0
-4294967307,1409847214052256,"mem.mm.min_flt.avg_lat",90.000000,0,"upid",0
-4294967308,1409847216341006,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967309,1409847216341006,"mem.mm.min_flt.max_lat",961.000000,0,"upid",0
-4294967310,1409847216341006,"mem.mm.min_flt.avg_lat",961.000000,0,"upid",0
-4294967311,1409847216341944,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967312,1409847216341944,"mem.mm.min_flt.max_lat",889.000000,0,"upid",0
-4294967313,1409847216341944,"mem.mm.min_flt.avg_lat",889.000000,0,"upid",0
-4294967314,1409847218889548,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967315,1409847218889548,"mem.mm.min_flt.max_lat",10.000000,0,"upid",0
-4294967316,1409847218889548,"mem.mm.min_flt.avg_lat",10.000000,0,"upid",0
-4294967317,1409847219001371,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967318,1409847219001371,"mem.mm.min_flt.max_lat",66.000000,0,"upid",0
-4294967319,1409847219001371,"mem.mm.min_flt.avg_lat",66.000000,0,"upid",0
-4294967320,1409847352399457,"mem.mm.min_flt.count",12.000000,0,"upid",0
-4294967321,1409847352399457,"mem.mm.min_flt.max_lat",148.000000,0,"upid",0
-4294967322,1409847352399457,"mem.mm.min_flt.avg_lat",54.000000,0,"upid",0
-4294967323,1409847383618992,"mem.mm.min_flt.count",4.000000,0,"upid",0
-4294967324,1409847383618992,"mem.mm.min_flt.max_lat",34.000000,0,"upid",0
-4294967325,1409847383618992,"mem.mm.min_flt.avg_lat",21.000000,0,"upid",0
-4294967326,1409847431535611,"mem.mm.reclaim.count",1.000000,0,"upid",0
-4294967327,1409847431535611,"mem.mm.reclaim.max_lat",21.000000,0,"upid",0
-4294967328,1409847431535611,"mem.mm.reclaim.avg_lat",21.000000,0,"upid",0
-4294967329,1409847438281133,"mem.mm.compaction.count",1.000000,0,"upid",0
-4294967330,1409847438281133,"mem.mm.compaction.max_lat",6564.000000,0,"upid",0
-4294967331,1409847438281133,"mem.mm.compaction.avg_lat",6564.000000,0,"upid",0
-4294967332,1409847446501654,"mem.mm.min_flt.count",1.000000,0,"upid",0
-4294967333,1409847446501654,"mem.mm.min_flt.max_lat",12.000000,0,"upid",0
-4294967334,1409847446501654,"mem.mm.min_flt.avg_lat",12.000000,0,"upid",0
-4294967335,1409847447831498,"mem.mm.min_flt.count",1.000000,0,"upid",0
+"ts","name","value","ref","ref_type"
+1409847208580693,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847208580693,"mem.mm.min_flt.max_lat",9.000000,0,"upid"
+1409847208580693,"mem.mm.min_flt.avg_lat",9.000000,0,"upid"
+1409847209537724,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847209537724,"mem.mm.min_flt.max_lat",759.000000,0,"upid"
+1409847209537724,"mem.mm.min_flt.avg_lat",759.000000,0,"upid"
+1409847213761006,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847213761006,"mem.mm.min_flt.max_lat",10.000000,0,"upid"
+1409847213761006,"mem.mm.min_flt.avg_lat",10.000000,0,"upid"
+1409847214052256,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847214052256,"mem.mm.min_flt.max_lat",90.000000,0,"upid"
+1409847214052256,"mem.mm.min_flt.avg_lat",90.000000,0,"upid"
+1409847216341006,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847216341006,"mem.mm.min_flt.max_lat",961.000000,0,"upid"
+1409847216341006,"mem.mm.min_flt.avg_lat",961.000000,0,"upid"
+1409847216341944,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847216341944,"mem.mm.min_flt.max_lat",889.000000,0,"upid"
+1409847216341944,"mem.mm.min_flt.avg_lat",889.000000,0,"upid"
+1409847218889548,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847218889548,"mem.mm.min_flt.max_lat",10.000000,0,"upid"
+1409847218889548,"mem.mm.min_flt.avg_lat",10.000000,0,"upid"
+1409847219001371,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847219001371,"mem.mm.min_flt.max_lat",66.000000,0,"upid"
+1409847219001371,"mem.mm.min_flt.avg_lat",66.000000,0,"upid"
+1409847352399457,"mem.mm.min_flt.count",12.000000,0,"upid"
+1409847352399457,"mem.mm.min_flt.max_lat",148.000000,0,"upid"
+1409847352399457,"mem.mm.min_flt.avg_lat",54.000000,0,"upid"
+1409847383618992,"mem.mm.min_flt.count",4.000000,0,"upid"
+1409847383618992,"mem.mm.min_flt.max_lat",34.000000,0,"upid"
+1409847383618992,"mem.mm.min_flt.avg_lat",21.000000,0,"upid"
+1409847431535611,"mem.mm.reclaim.count",1.000000,0,"upid"
+1409847431535611,"mem.mm.reclaim.max_lat",21.000000,0,"upid"
+1409847431535611,"mem.mm.reclaim.avg_lat",21.000000,0,"upid"
+1409847438281133,"mem.mm.compaction.count",1.000000,0,"upid"
+1409847438281133,"mem.mm.compaction.max_lat",6564.000000,0,"upid"
+1409847438281133,"mem.mm.compaction.avg_lat",6564.000000,0,"upid"
+1409847446501654,"mem.mm.min_flt.count",1.000000,0,"upid"
+1409847446501654,"mem.mm.min_flt.max_lat",12.000000,0,"upid"
+1409847446501654,"mem.mm.min_flt.avg_lat",12.000000,0,"upid"
+1409847447831498,"mem.mm.min_flt.count",1.000000,0,"upid"
diff --git a/test/trace_processor/mm_event.sql b/test/trace_processor/mm_event.sql
index 187d0ff..e286c68 100644
--- a/test/trace_processor/mm_event.sql
+++ b/test/trace_processor/mm_event.sql
@@ -1,4 +1,4 @@
-select id, ts, name, value, ref, ref_type, arg_set_id
+select ts, name, value, ref, ref_type
 from counters
 where name like 'mem.mm.%'
 order by ts
diff --git a/test/trace_processor/process_tracking_uid.out b/test/trace_processor/process_tracking_uid.out
new file mode 100644
index 0000000..ae90e8d
--- /dev/null
+++ b/test/trace_processor/process_tracking_uid.out
@@ -0,0 +1,6 @@
+"pid","uid"
+0,"[NULL]"
+10,1001
+20,1002
+30,"[NULL]"
+40,"[NULL]"
diff --git a/test/trace_processor/process_tracking_uid.sql b/test/trace_processor/process_tracking_uid.sql
new file mode 100644
index 0000000..de06399
--- /dev/null
+++ b/test/trace_processor/process_tracking_uid.sql
@@ -0,0 +1,3 @@
+select pid, uid
+from process
+order by pid;
diff --git a/test/trace_processor/synth_process_tracking.py b/test/trace_processor/synth_process_tracking.py
index 6686d89..a7a4d2d 100644
--- a/test/trace_processor/synth_process_tracking.py
+++ b/test/trace_processor/synth_process_tracking.py
@@ -40,7 +40,7 @@
 # SQL level we should be able to tell that p1-t0 and p1-t2 belong to 'process1'
 # but p1-t1 should be left unjoinable.
 trace.add_process_tree_packet(ts=5)
-trace.add_process(10, 0, "process1")
+trace.add_process(10, 0, "process1", 1001)
 trace.add_thread(12, 10, "p1-t2")
 
 # Now create another process (pid=20) with three threads(tids=20,21,22).
@@ -58,7 +58,7 @@
 
 # From the process tracker viewpoint we pretend we only scraped tids=20,21.
 trace.add_process_tree_packet(ts=15)
-trace.add_process(20, 0, "process_2")
+trace.add_process(20, 0, "process_2", 1002)
 trace.add_thread(21, 20, "p2-t1")
 
 # Finally the very complex case: a third process (pid=30) which spawns threads
diff --git a/tools/tmux b/tools/tmux
index 035127f..0ab0349 100755
--- a/tools/tmux
+++ b/tools/tmux
@@ -24,7 +24,7 @@
 function get_gn_value() {
   local out=$1
   local key=$2
-  gn args "$out" --list --short | sed -n -e "s/$key = \"\(.*\)\"/\1/p"
+  gn args "$out" --list=$key --short | awk '{print $3}'
 }
 
 function is_monolithic() {
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 276f9d6..2d65f7a 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -241,15 +241,6 @@
       "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
       "dev": true
     },
-    "agent-base": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
-      "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
-      "dev": true,
-      "requires": {
-        "es6-promisify": "^5.0.0"
-      }
-    },
     "ajv": {
       "version": "6.9.1",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz",
@@ -761,16 +752,6 @@
       "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
       "dev": true
     },
-    "axios": {
-      "version": "0.17.1",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz",
-      "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=",
-      "dev": true,
-      "requires": {
-        "follow-redirects": "^1.2.5",
-        "is-buffer": "^1.1.5"
-      }
-    },
     "babel-code-frame": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -1178,13 +1159,13 @@
       }
     },
     "browser-sync": {
-      "version": "2.26.3",
-      "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.3.tgz",
-      "integrity": "sha512-VLzpjCA4uXqfzkwqWtMM6hvPm2PNHp2RcmzBXcbi6C9WpkUhhFb8SVAr4CFrCsFxDg+oY6HalOjn8F+egyvhag==",
+      "version": "2.26.7",
+      "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.7.tgz",
+      "integrity": "sha512-lY3emme0OyvA2ujEMpRmyRy9LY6gHLuTr2/ABxhIm3lADOiRXzP4dgekvnDrQqZ/Ec2Fz19lEjm6kglSG5766w==",
       "dev": true,
       "requires": {
-        "browser-sync-client": "^2.26.2",
-        "browser-sync-ui": "^2.26.2",
+        "browser-sync-client": "^2.26.6",
+        "browser-sync-ui": "^2.26.4",
         "bs-recipes": "1.3.4",
         "bs-snippet-injector": "^2.0.1",
         "chokidar": "^2.0.4",
@@ -1198,8 +1179,8 @@
         "fs-extra": "3.0.1",
         "http-proxy": "1.15.2",
         "immutable": "^3",
-        "localtunnel": "1.9.1",
-        "micromatch": "2.3.11",
+        "localtunnel": "1.9.2",
+        "micromatch": "^3.1.10",
         "opn": "5.3.0",
         "portscanner": "2.1.1",
         "qs": "6.2.3",
@@ -1215,6 +1196,83 @@
         "yargs": "6.4.0"
       },
       "dependencies": {
+        "arr-diff": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+          "dev": true
+        },
+        "array-unique": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+          "dev": true
+        },
+        "axios": {
+          "version": "0.19.0",
+          "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz",
+          "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==",
+          "dev": true,
+          "requires": {
+            "follow-redirects": "1.5.10",
+            "is-buffer": "^2.0.2"
+          }
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "browser-sync-client": {
+          "version": "2.26.6",
+          "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.6.tgz",
+          "integrity": "sha512-mGrkZdNzttKdf/16I+y+2dTQxoMCIpKbVIMJ/uP8ZpnKu9f9qa/2CYVtLtbjZG8nsM14EwiCrjuFTGBEnT3Gjw==",
+          "dev": true,
+          "requires": {
+            "etag": "1.8.1",
+            "fresh": "0.5.2",
+            "mitt": "^1.1.3",
+            "rxjs": "^5.5.6"
+          }
+        },
+        "browser-sync-ui": {
+          "version": "2.26.4",
+          "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.4.tgz",
+          "integrity": "sha512-u20P3EsZoM8Pt+puoi3BU3KlbQAH1lAcV+/O4saF26qokrBqIDotmGonfWwoRbUmdxZkM9MBmA0K39ZTG1h4sA==",
+          "dev": true,
+          "requires": {
+            "async-each-series": "0.1.1",
+            "connect-history-api-fallback": "^1",
+            "immutable": "^3",
+            "server-destroy": "1.0.1",
+            "socket.io-client": "^2.0.4",
+            "stream-throttle": "^0.1.3"
+          }
+        },
         "camelcase": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
@@ -1232,6 +1290,244 @@
             "wrap-ansi": "^2.0.0"
           }
         },
+        "debug": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.1.2",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+              "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+              "dev": true
+            }
+          }
+        },
+        "expand-brackets": {
+          "version": "2.1.4",
+          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+          "dev": true,
+          "requires": {
+            "debug": "^2.3.3",
+            "define-property": "^0.2.5",
+            "extend-shallow": "^2.0.1",
+            "posix-character-classes": "^0.1.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "debug": {
+              "version": "2.6.9",
+              "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+              "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+              "dev": true,
+              "requires": {
+                "ms": "2.0.0"
+              }
+            },
+            "define-property": {
+              "version": "0.2.5",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+              "dev": true,
+              "requires": {
+                "is-descriptor": "^0.1.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "0.1.6",
+              "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+              "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+              "dev": true,
+              "requires": {
+                "kind-of": "^3.0.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "^1.1.5"
+                  }
+                }
+              }
+            },
+            "is-buffer": {
+              "version": "1.1.6",
+              "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+              "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+              "dev": true
+            },
+            "is-data-descriptor": {
+              "version": "0.1.4",
+              "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+              "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+              "dev": true,
+              "requires": {
+                "kind-of": "^3.0.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "^1.1.5"
+                  }
+                }
+              }
+            },
+            "is-descriptor": {
+              "version": "0.1.6",
+              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "^0.1.6",
+                "is-data-descriptor": "^0.1.4",
+                "kind-of": "^5.0.0"
+              }
+            },
+            "kind-of": {
+              "version": "5.1.0",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+              "dev": true
+            }
+          }
+        },
+        "extglob": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+          "dev": true,
+          "requires": {
+            "array-unique": "^0.3.2",
+            "define-property": "^1.0.0",
+            "expand-brackets": "^2.1.4",
+            "extend-shallow": "^2.0.1",
+            "fragment-cache": "^0.2.1",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+              "dev": true,
+              "requires": {
+                "is-descriptor": "^1.0.0"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "follow-redirects": {
+          "version": "1.5.10",
+          "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
+          "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+          "dev": true,
+          "requires": {
+            "debug": "=3.1.0"
+          },
+          "dependencies": {
+            "debug": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+              "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+              "dev": true,
+              "requires": {
+                "ms": "2.0.0"
+              }
+            }
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-buffer": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+          "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+          "dev": true
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
         "is-fullwidth-code-point": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
@@ -1241,6 +1537,100 @@
             "number-is-nan": "^1.0.0"
           }
         },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "is-buffer": {
+              "version": "1.1.6",
+              "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+              "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+              "dev": true
+            },
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+          "dev": true
+        },
+        "kind-of": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+          "dev": true
+        },
+        "localtunnel": {
+          "version": "1.9.2",
+          "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.2.tgz",
+          "integrity": "sha512-NEKF7bDJE9U3xzJu3kbayF0WTvng6Pww7tzqNb/XtEARYwqw7CKEX7BvOMg98FtE9es2CRizl61gkV3hS8dqYg==",
+          "dev": true,
+          "requires": {
+            "axios": "0.19.0",
+            "debug": "4.1.1",
+            "openurl": "1.1.1",
+            "yargs": "6.6.0"
+          },
+          "dependencies": {
+            "yargs": {
+              "version": "6.6.0",
+              "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
+              "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
+              "dev": true,
+              "requires": {
+                "camelcase": "^3.0.0",
+                "cliui": "^3.2.0",
+                "decamelize": "^1.1.1",
+                "get-caller-file": "^1.0.1",
+                "os-locale": "^1.4.0",
+                "read-pkg-up": "^1.0.1",
+                "require-directory": "^2.1.1",
+                "require-main-filename": "^1.0.1",
+                "set-blocking": "^2.0.0",
+                "string-width": "^1.0.2",
+                "which-module": "^1.0.0",
+                "y18n": "^3.2.1",
+                "yargs-parser": "^4.2.0"
+              }
+            }
+          }
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
         "os-locale": {
           "version": "1.4.0",
           "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
@@ -1315,32 +1705,6 @@
         }
       }
     },
-    "browser-sync-client": {
-      "version": "2.26.2",
-      "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.2.tgz",
-      "integrity": "sha512-FEuVJD41fI24HJ30XOT2RyF5WcnEtdJhhTqeyDlnMk/8Ox9MZw109rvk9pdfRWye4soZLe+xcAo9tHSMxvgAdw==",
-      "dev": true,
-      "requires": {
-        "etag": "1.8.1",
-        "fresh": "0.5.2",
-        "mitt": "^1.1.3",
-        "rxjs": "^5.5.6"
-      }
-    },
-    "browser-sync-ui": {
-      "version": "2.26.2",
-      "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.2.tgz",
-      "integrity": "sha512-LF7GMWo8ELOE0eAlxuRCfnGQT1ZxKP9flCfGgZdXFc6BwmoqaJHlYe7MmVvykKkXjolRXTz8ztXAKGVqNwJ3EQ==",
-      "dev": true,
-      "requires": {
-        "async-each-series": "0.1.1",
-        "connect-history-api-fallback": "^1",
-        "immutable": "^3",
-        "server-destroy": "1.0.1",
-        "socket.io-client": "^2.0.4",
-        "stream-throttle": "^0.1.3"
-      }
-    },
     "bs-recipes": {
       "version": "1.3.4",
       "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
@@ -2503,32 +2867,6 @@
         "locate-path": "^2.0.0"
       }
     },
-    "follow-redirects": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
-      "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
-      "dev": true,
-      "requires": {
-        "debug": "^3.2.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true
-        }
-      }
-    },
     "for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -2613,8 +2951,7 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -2657,8 +2994,7 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "concat-map": {
           "version": "0.0.1",
@@ -2669,8 +3005,7 @@
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -2787,8 +3122,7 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "ini": {
           "version": "1.3.5",
@@ -2800,7 +3134,6 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -2830,7 +3163,6 @@
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -2849,7 +3181,6 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -2943,7 +3274,6 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -3029,8 +3359,7 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -3066,7 +3395,6 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -3086,7 +3414,6 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -3130,14 +3457,12 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         }
       }
     },
@@ -3310,12 +3635,12 @@
       "dev": true
     },
     "handlebars": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz",
-      "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==",
+      "version": "4.5.3",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
+      "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
       "dev": true,
       "requires": {
-        "async": "^2.5.0",
+        "neo-async": "^2.6.0",
         "optimist": "^0.6.1",
         "source-map": "^0.6.1",
         "uglify-js": "^3.1.4"
@@ -3529,15 +3854,24 @@
       }
     },
     "https-proxy-agent": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
-      "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
       "dev": true,
       "requires": {
-        "agent-base": "^4.1.0",
+        "agent-base": "^4.3.0",
         "debug": "^3.1.0"
       },
       "dependencies": {
+        "agent-base": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+          "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+          "dev": true,
+          "requires": {
+            "es6-promisify": "^5.0.0"
+          }
+        },
         "debug": {
           "version": "3.2.6",
           "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -3548,9 +3882,9 @@
           }
         },
         "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
           "dev": true
         }
       }
@@ -4445,9 +4779,9 @@
       "dev": true
     },
     "js-yaml": {
-      "version": "3.12.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
-      "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
       "dev": true,
       "requires": {
         "argparse": "^1.0.7",
@@ -4628,111 +4962,6 @@
         "strip-bom": "^2.0.0"
       }
     },
-    "localtunnel": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.1.tgz",
-      "integrity": "sha512-HWrhOslklDvxgOGFLxi6fQVnvpl6XdX4sPscfqMZkzi3gtt9V7LKBWYvNUcpHSVvjwCQ6xzXacVvICNbNcyPnQ==",
-      "dev": true,
-      "requires": {
-        "axios": "0.17.1",
-        "debug": "2.6.9",
-        "openurl": "1.1.1",
-        "yargs": "6.6.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true
-        },
-        "cliui": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-          "dev": true,
-          "requires": {
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1",
-            "wrap-ansi": "^2.0.0"
-          }
-        },
-        "is-fullwidth-code-point": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-          "dev": true,
-          "requires": {
-            "number-is-nan": "^1.0.0"
-          }
-        },
-        "os-locale": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-          "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
-          "dev": true,
-          "requires": {
-            "lcid": "^1.0.0"
-          }
-        },
-        "string-width": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-          "dev": true,
-          "requires": {
-            "code-point-at": "^1.0.0",
-            "is-fullwidth-code-point": "^1.0.0",
-            "strip-ansi": "^3.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "which-module": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-          "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "6.6.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
-          "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0",
-            "cliui": "^3.2.0",
-            "decamelize": "^1.1.1",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^1.4.0",
-            "read-pkg-up": "^1.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^1.0.2",
-            "which-module": "^1.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^4.2.0"
-          }
-        },
-        "yargs-parser": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
-          "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0"
-          }
-        }
-      }
-    },
     "locate-path": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@@ -4744,9 +4973,9 @@
       }
     },
     "lodash": {
-      "version": "4.17.11",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
       "dev": true
     },
     "lodash.isfinite": {
@@ -4959,9 +5188,9 @@
       "dev": true
     },
     "mithril": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/mithril/-/mithril-1.1.6.tgz",
-      "integrity": "sha512-fWcUrQTCqu8M916rj1MFGlHaPh65rznPu6U/N2U9g81H89klDCIptSK5bnkNkC+jyi3sJIXjyGhSQjUnR8jzZA=="
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/mithril/-/mithril-1.1.7.tgz",
+      "integrity": "sha512-1SAkGeVrIVvkUHlPHvR3pXdWzNfTzmS/fBAe+rC2ApEBfZFFc+idi8Qg/M5JoW/sZkIDXSfQYVgvENMIhBIVAg=="
     },
     "mitt": {
       "version": "1.1.3",
@@ -4970,9 +5199,9 @@
       "dev": true
     },
     "mixin-deep": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
-      "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
       "dev": true,
       "requires": {
         "for-in": "^1.0.2",
@@ -5077,6 +5306,12 @@
       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
       "dev": true
     },
+    "neo-async": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+      "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
+      "dev": true
+    },
     "node-gyp": {
       "version": "3.8.0",
       "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
@@ -6542,288 +6777,19 @@
       }
     },
     "rollup-pluginutils": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.7.1.tgz",
-      "integrity": "sha512-3nRf3buQGR9qz/IsSzhZAJyoK663kzseps8itkYHr+Z7ESuaffEPfgRinxbCRA0pf0gzLqkNKkSb8aNVTq75NA==",
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+      "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
       "dev": true,
       "requires": {
-        "estree-walker": "^0.6.0",
-        "micromatch": "^3.1.10"
+        "estree-walker": "^0.6.1"
       },
       "dependencies": {
-        "arr-diff": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+        "estree-walker": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+          "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
           "dev": true
-        },
-        "array-unique": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-          "dev": true
-        },
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "expand-brackets": {
-          "version": "2.1.4",
-          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-          "dev": true,
-          "requires": {
-            "debug": "^2.3.3",
-            "define-property": "^0.2.5",
-            "extend-shallow": "^2.0.1",
-            "posix-character-classes": "^0.1.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "0.2.5",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^0.1.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            },
-            "is-accessor-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-              "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-data-descriptor": {
-              "version": "0.1.4",
-              "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-              "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-              "dev": true,
-              "requires": {
-                "is-accessor-descriptor": "^0.1.6",
-                "is-data-descriptor": "^0.1.4",
-                "kind-of": "^5.0.0"
-              }
-            },
-            "kind-of": {
-              "version": "5.1.0",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-              "dev": true
-            }
-          }
-        },
-        "extglob": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-          "dev": true,
-          "requires": {
-            "array-unique": "^0.3.2",
-            "define-property": "^1.0.0",
-            "expand-brackets": "^2.1.4",
-            "extend-shallow": "^2.0.1",
-            "fragment-cache": "^0.2.1",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^1.0.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
         }
       }
     },
@@ -7380,9 +7346,9 @@
       "dev": true
     },
     "set-value": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
-      "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -8280,38 +8246,15 @@
       "dev": true
     },
     "union-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
-      "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
       "dev": true,
       "requires": {
         "arr-union": "^3.1.0",
         "get-value": "^2.0.6",
         "is-extendable": "^0.1.1",
-        "set-value": "^0.4.3"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "set-value": {
-          "version": "0.4.3",
-          "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
-          "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-extendable": "^0.1.1",
-            "is-plain-object": "^2.0.1",
-            "to-object-path": "^0.3.0"
-          }
-        }
+        "set-value": "^2.0.1"
       }
     },
     "universalify": {
diff --git a/ui/package.json b/ui/package.json
index 7e3b8b5..e960062 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -24,7 +24,7 @@
     "immer": "^1.12.1",
     "jsbn-rsa": "^1.0.3",
     "micromodal": "^0.4.0",
-    "mithril": "^1.1.6",
+    "mithril": "^1.1.7",
     "noice-json-rpc": "^1.2.0",
     "pako": "^1.0.10",
     "protobufjs": "^6.8.8",
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 7edcbba..8c5fb67 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -302,7 +302,8 @@
     //}
     const maxCpuFreq = await engine.query(`
      select max(value)
-     from counters
+     from counter c
+     inner join cpu_counter_track t on c.track_id = t.id
      where name = 'cpufreq';
     `);
 
@@ -325,13 +326,28 @@
       // cpu freq data.
       // TODO(taylori): Find a way to display cpu idle
       // events even if there are no cpu freq events.
-      const freqExists = await engine.query(`
-        select value
-        from counters
-        where name = 'cpufreq' and ref = ${cpu}
+      const cpuFreqIdle = await engine.query(`
+        select
+          id as cpu_freq_id,
+          (
+            select id
+            from cpu_counter_track
+            where name = 'cpuidle'
+            and cpu = ${cpu}
+            limit 1
+          ) as cpu_idle_id
+        from cpu_counter_track
+        where name = 'cpufreq' and cpu = ${cpu}
         limit 1;
       `);
-      if (freqExists.numRecords > 0) {
+      if (cpuFreqIdle.numRecords > 0) {
+        const freqTrackId = +cpuFreqIdle.columns[0].longValues![0];
+
+        const idleTrackExists: boolean = !cpuFreqIdle.columns[1].isNulls![0];
+        const idleTrackId = idleTrackExists ?
+            +cpuFreqIdle.columns[1].longValues![0] :
+            undefined;
+
         tracksToAdd.push({
           engineId: this.engineId,
           kind: CPU_FREQ_TRACK_KIND,
@@ -340,6 +356,8 @@
           config: {
             cpu,
             maximumValue: +maxCpuFreq.columns[0].doubleValues![0],
+            freqTrackId,
+            idleTrackId,
           }
         });
       }
@@ -414,46 +432,69 @@
       }
     }
 
-
-    const counters = await engine.query(`
-      select name, ref, ref_type
-      from counter_definitions
-      where ref is not null
-      group by name, ref, ref_type
-      order by ref_type desc
+    // Add global or GPU counter tracks that are not bound to any pid/tid.
+    const globalCounters = await engine.query(`
+      select name, id
+      from counter_track
+      where type = 'counter_track'
+      union
+      select name, id
+      from gpu_counter_track
+      where name != 'gpufreq'
     `);
-
-    interface CounterMap {
-      [index: number]: string[];
+    for (let i = 0; i < globalCounters.numRecords; i++) {
+      const name = globalCounters.columns[0].stringValues![i];
+      const trackId = +globalCounters.columns[1].longValues![i];
+      tracksToAdd.push({
+        engineId: this.engineId,
+        kind: 'CounterTrack',
+        name,
+        trackGroup: SCROLLING_TRACK_GROUP,
+        config: {
+          name,
+          trackId,
+        }
+      });
     }
 
-    const counterUpids: CounterMap = new Array();
-    const counterUtids: CounterMap = new Array();
-    for (let i = 0; i < counters.numRecords; i++) {
-      const name = counters.columns[0].stringValues![i];
-      const ref = +counters.columns[1].longValues![i];
-      const refType = counters.columns[2].stringValues![i];
-      if (refType === 'upid') {
-        const el = counterUpids[ref];
-        el === undefined ? counterUpids[ref] = [name] :
-                           counterUpids[ref].push(name);
-      } else if (refType === 'utid') {
-        const el = counterUtids[ref];
-        el === undefined ? counterUtids[ref] = [name] :
-                           counterUtids[ref].push(name);
-      } else if (
-          refType === '[NULL]' || (refType === 'gpu' && name !== 'gpufreq')) {
-        // Add global or GPU counter tracks that are not bound to any pid/tid.
-        tracksToAdd.push({
-          engineId: this.engineId,
-          kind: 'CounterTrack',
-          name,
-          trackGroup: SCROLLING_TRACK_GROUP,
-          config: {
-            name,
-            ref: 0,
-          }
-        });
+    interface CounterTrack {
+      name: string;
+      trackId: number;
+    }
+
+    const counterUtids = new Map<number, CounterTrack[]>();
+    const threadCounters = await engine.query(`
+      select name, utid, id
+      from thread_counter_track
+    `);
+    for (let i = 0; i < threadCounters.numRecords; i++) {
+      const name = threadCounters.columns[0].stringValues![i];
+      const utid = +threadCounters.columns[1].longValues![i];
+      const trackId = +threadCounters.columns[2].longValues![i];
+
+      const el = counterUtids.get(utid);
+      if (el === undefined) {
+        counterUtids.set(utid, [{name, trackId}]);
+      } else {
+        el.push({name, trackId});
+      }
+    }
+
+    const counterUpids = new Map<number, CounterTrack[]>();
+    const processCounters = await engine.query(`
+      select name, upid, id
+      from process_counter_track
+    `);
+    for (let i = 0; i < processCounters.numRecords; i++) {
+      const name = processCounters.columns[0].stringValues![i];
+      const upid = +processCounters.columns[1].longValues![i];
+      const trackId = +processCounters.columns[2].longValues![i];
+
+      const el = counterUpids.get(upid);
+      if (el === undefined) {
+        counterUpids.set(upid, [{name, trackId}]);
+      } else {
+        el.push({name, trackId});
       }
     }
 
@@ -526,8 +567,8 @@
       const threadTrack =
           utid === null ? undefined : utidToThreadTrack.get(utid);
       if (threadTrack === undefined &&
-          (upid === null || counterUpids[upid] === undefined) &&
-          counterUtids[utid] === undefined && !threadHasSched &&
+          (upid === null || counterUpids.get(upid) === undefined) &&
+          counterUtids.get(utid) === undefined && !threadHasSched &&
           (upid === null || upid !== null && !heapUpids.has(upid))) {
         continue;
       }
@@ -571,18 +612,15 @@
         }));
 
         if (upid !== null) {
-          const counterNames = counterUpids[upid];
+          const counterNames = counterUpids.get(upid);
           if (counterNames !== undefined) {
             counterNames.forEach(element => {
               tracksToAdd.push({
                 engineId: this.engineId,
                 kind: 'CounterTrack',
-                name: element,
+                name: element.name,
                 trackGroup: pUuid,
-                config: {
-                  name: element,
-                  ref: upid,
-                }
+                config: {name: element.name, trackId: element.trackId}
               });
             });
           }
@@ -612,17 +650,17 @@
           }
         }
       }
-      const counterThreadNames = counterUtids[utid];
+      const counterThreadNames = counterUtids.get(utid);
       if (counterThreadNames !== undefined) {
         counterThreadNames.forEach(element => {
           tracksToAdd.push({
             engineId: this.engineId,
             kind: 'CounterTrack',
-            name: element,
+            name: element.name,
             trackGroup: pUuid,
             config: {
-              name: element,
-              ref: utid,
+              name: element.name,
+              trackId: element.trackId,
             }
           });
         });
diff --git a/ui/src/frontend/flamegraph.ts b/ui/src/frontend/flamegraph.ts
index 5343a25..12b0785 100644
--- a/ui/src/frontend/flamegraph.ts
+++ b/ui/src/frontend/flamegraph.ts
@@ -77,14 +77,14 @@
     return hash & 0xff;
   }
 
-  generateColor(name: string|undefined, isGreyedOut = false): string {
+  generateColor(name: string, isGreyedOut = false): string {
     if (this.isThumbnail) {
       return HEAP_PROFILE_COLOR;
     }
     if (isGreyedOut) {
       return '#d9d9d9';
     }
-    if (name === undefined || name === 'root') {
+    if (name === 'unknown' || name === 'root') {
       return '#c0c0c0';
     }
     const hue = this.hash(name);
@@ -161,7 +161,8 @@
       currentY = nodeHeight * (value.depth + 1);
 
       // Draw node.
-      ctx.fillStyle = this.generateColor(value.name, isGreyedOut);
+      const name = this.getCallsiteName(value);
+      ctx.fillStyle = this.generateColor(name, isGreyedOut);
       ctx.fillRect(currentX, currentY, width, nodeHeight);
 
       // Set current node's data in map for children to use.
@@ -185,7 +186,6 @@
       }
 
       // Draw name.
-      const name = this.getCallsiteName(value);
       ctx.font = `${this.textSize}px Google Sans`;
       const text = cropText(name, charWidth, width - 2);
       ctx.fillStyle = 'black';
@@ -240,7 +240,8 @@
   }
 
   private getCallsiteName(value: CallsiteInfo): string {
-    return value.name === undefined ? 'unknown' : value.name;
+    return value.name === undefined || value.name === '' ? 'unknown' :
+                                                           value.name;
   }
 
   onMouseMove({x, y}: {x: number, y: number}) {
diff --git a/ui/src/tracks/counter/common.ts b/ui/src/tracks/counter/common.ts
index 0eb6dfb..53a603d 100644
--- a/ui/src/tracks/counter/common.ts
+++ b/ui/src/tracks/counter/common.ts
@@ -30,6 +30,6 @@
   name: string;
   maximumValue?: number;
   minimumValue?: number;
-  ref: number;
+  trackId: number;
   scale?: 'DEFAULT'|'RELATIVE';
 }
diff --git a/ui/src/tracks/counter/controller.ts b/ui/src/tracks/counter/controller.ts
index 4085845..0be0371 100644
--- a/ui/src/tracks/counter/controller.ts
+++ b/ui/src/tracks/counter/controller.ts
@@ -39,20 +39,22 @@
 
     if (!this.setup) {
       const result = await this.query(`
-      select max(value), min(value) from
-        counters where name = '${this.config.name}'
-        and ref = ${this.config.ref}`);
+        select max(value), min(value)
+        from counter
+        where track_id = ${this.config.trackId}`);
       this.maximumValueSeen = +result.columns[0].doubleValues![0];
       this.minimumValueSeen = +result.columns[1].doubleValues![0];
       await this.query(
         `create virtual table ${this.tableName('window')} using window;`);
 
-      await this.query(`create view ${this.tableName('counter_view')} as
-        select ts,
-        lead(ts, 1, ts) over (partition by ref_type order by ts) - ts as dur,
-        value, name, ref
-        from counters
-        where name = '${this.config.name}' and ref = ${this.config.ref};`);
+      await this.query(`
+        create view ${this.tableName('counter_view')} as
+        select
+          ts,
+          lead(ts, 1, ts) over (order by ts) - ts as dur,
+          value
+        from counter
+        where track_id = ${this.config.trackId};`);
 
       await this.query(`create virtual table ${this.tableName('span')} using
         span_join(${this.tableName('counter_view')},
@@ -60,13 +62,16 @@
       this.setup = true;
     }
 
-    const result = await this.engine.queryOneRow(`select count(*)
-    from (select
-      ts,
-      lead(ts, 1, ts) over (partition by ref_type order by ts) as ts_end,
-      from counters
-      where name = '${this.config.name}' and ref = ${this.config.ref})
-    where ts <= ${endNs} and ${startNs} <= ts_end`);
+    const result = await this.engine.queryOneRow(`
+      select count(*)
+      from (
+        select
+          ts,
+          lead(ts, 1, ts) over (order by ts) as ts_end,
+        from counter
+        where track_id = ${this.config.trackId}
+      )
+      where ts <= ${endNs} and ${startNs} <= ts_end`);
 
     // Only quantize if we have too much data to draw.
     const isQuantized = result[0] > LIMIT;
@@ -94,18 +99,32 @@
       // Union that with the query that finds all the counters within
       // the current query range.
       query = `
-      select * from (select ts, value, counter_id from counters
-      where name = '${this.config.name}' and ref = ${this.config.ref} and
-      ts <= ${startNs} order by ts desc limit 1)
-      UNION
-      select * from (select ts, value, counter_id
-        from (select
-          ts,
-          lead(ts, 1, ts) over (partition by ref_type order by ts) as ts_end,
-          value, counter_id
-          from counters
-          where name = '${this.config.name}' and ref = ${this.config.ref})
-      where ts <= ${endNs} and ${startNs} <= ts_end limit ${LIMIT});`;
+      select *
+      from (
+        select ts, value, track_id
+        from counter
+        where
+          track_id = ${this.config.trackId} and
+          ts <= ${startNs}
+        order by ts desc
+        limit 1
+      )
+      union
+      select *
+      from (
+        select ts, value, track_id
+        from (
+          select
+            ts,
+            lead(ts, 1, ts) over (order by ts) as ts_end,
+            value,
+            track_id
+          from counter
+          where track_id = ${this.config.trackId}
+        )
+        where ts <= ${endNs} and ${startNs} <= ts_end
+        limit ${LIMIT}
+      );`;
     }
 
     const rawResult = await this.query(query);
diff --git a/ui/src/tracks/cpu_freq/common.ts b/ui/src/tracks/cpu_freq/common.ts
index 8968907..fff0c8f 100644
--- a/ui/src/tracks/cpu_freq/common.ts
+++ b/ui/src/tracks/cpu_freq/common.ts
@@ -28,5 +28,8 @@
 
 export interface Config {
   cpu: number;
+  freqTrackId: number;
+  idleTrackId?: number;
   maximumValue?: number;
-  minimumValue?: number;}
+  minimumValue?: number;
+}
diff --git a/ui/src/tracks/cpu_freq/controller.ts b/ui/src/tracks/cpu_freq/controller.ts
index 190a3d9..bdfbdae 100644
--- a/ui/src/tracks/cpu_freq/controller.ts
+++ b/ui/src/tracks/cpu_freq/controller.ts
@@ -38,9 +38,9 @@
 
     if (!this.setup) {
       const result = await this.query(`
-      select max(value) from
-        counters where name = 'cpufreq'
-        and ref = ${this.config.cpu}`);
+        select max(value)
+        from counter
+        where track_id = ${this.config.freqTrackId}`);
       this.maximumValueSeen = +result.columns[0].doubleValues![0];
 
       await this.query(
@@ -49,36 +49,39 @@
       await this.query(`create view ${this.tableName('freq')}
           as select
             ts,
-            lead(ts) over (order by ts) - ts as dur,
-            ref as cpu,
-            name as freq_name,
+            lead(ts) over () - ts as dur,
             value as freq_value
-          from counters
-          where name = 'cpufreq'
-            and ref = ${this.config.cpu}
-            and ref_type = 'cpu';
+          from counter c
+          where track_id = ${this.config.freqTrackId};
       `);
 
-      await this.query(`create view ${this.tableName('idle')}
-        as select
-          ts,
-          lead(ts) over (order by ts) - ts as dur,
-          ref as cpu,
-          name as idle_name,
-          value as idle_value
-        from counters
-        where name = 'cpuidle'
-          and ref = ${this.config.cpu}
-          and ref_type = 'cpu';
-      `);
+      // If there is no idle track, just make the idle track a single row
+      // which spans the entire time range.
+      if (this.config.idleTrackId === undefined) {
+        await this.query(`create view ${this.tableName('idle')} as
+           select
+             0 as ts,
+             ${Number.MAX_SAFE_INTEGER} as dur,
+             -1 as idle_value;
+          `);
+      } else {
+        await this.query(`create view ${this.tableName('idle')}
+          as select
+            ts,
+            lead(ts) over () - ts as dur,
+            value as idle_value
+          from counter c
+          where track_id = ${this.config.idleTrackId};
+        `);
+      }
 
       await this.query(`create virtual table ${this.tableName('freq_idle')}
-              using span_join(${this.tableName('freq')} PARTITIONED cpu,
-                              ${this.tableName('idle')} PARTITIONED cpu);`);
+              using span_join(${this.tableName('freq')},
+                              ${this.tableName('idle')});`);
 
       await this.query(`create virtual table ${this.tableName('span_activity')}
-      using span_join(${this.tableName('freq_idle')} PARTITIONED cpu,
-                      ${this.tableName('window')});`);
+              using span_join(${this.tableName('freq_idle')},
+                              ${this.tableName('window')});`);
 
       // TODO(taylori): Move the idle value processing to the TP.
       await this.query(`create view ${this.tableName('activity')}
@@ -86,7 +89,6 @@
         ts,
         dur,
         quantum_ts,
-        cpu,
         case idle_value
           when 4294967295 then -1
           else idle_value
diff --git a/ui/src/tracks/heap_profile_flamegraph/controller.ts b/ui/src/tracks/heap_profile_flamegraph/controller.ts
index a0fbf9f..b84c688 100644
--- a/ui/src/tracks/heap_profile_flamegraph/controller.ts
+++ b/ui/src/tracks/heap_profile_flamegraph/controller.ts
@@ -362,24 +362,33 @@
         this.tableName(`callsite_hash_name_size_${ts}`);
     const tableNameGroupedCallsitesForFlamegraph =
         this.tableName(`grouped_callsites_for_flamegraph${ts}`);
-    // const tableNameGroupedCallsitesForFlamegraph =
-    // this.tableNameGroupdCallsitesForFlamegraphAsKey(ts); Joining the callsite
-    // table with frame table then with alloc table to get the size and name for
-    // each callsite.
+    // Joining the callsite table with frame table then with alloc table to get
+    // the size and name for each callsite.
+    // TODO(tneda): Make frame name nullable in the trace processor for
+    // consistency with the other columns.
     await this.query(`create view if not exists ${tableNameCallsiteNameSize} as
-      select cs.id, parent_id, depth, IFNULL(symbols.name, fr.name) as name,
-      SUM(IFNULL(size, 0)) as size,
-      SUM(case when size > 0 then size else 0 end) as alloc_size,
-      SUM(IFNULL(count, 0)) as count,
-      SUM(case when count > 0 then count else 0 end) as alloc_count
-      from stack_profile_callsite cs
-      join stack_profile_frame fr on cs.frame_id = fr.id
-      inner join (SELECT symbol_set_id, FIRST_VALUE(name) OVER(PARTITION BY
-        symbol_set_id) as name
-      FROM stack_profile_symbol GROUP BY symbol_set_id) as symbols
-        using(symbol_set_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`);
+         select id, parent_id, depth, IFNULL(DEMANGLE(name), name) as name,
+            map_name, size, alloc_size, count, alloc_count from (
+         select cs.id as id, parent_id, depth,
+            coalesce(symbols.name,
+                case when fr.name != '' then fr.name else map.name end) as name,
+            map.name as map_name,
+            SUM(IFNULL(size, 0)) as size,
+            SUM(IFNULL(size, 0)) as size,
+            SUM(case when size > 0 then size else 0 end) as alloc_size,
+            SUM(IFNULL(count, 0)) as count,
+            SUM(case when count > 0 then count else 0 end) as alloc_count
+         from stack_profile_callsite cs
+         join stack_profile_frame fr on cs.frame_id = fr.id
+         join stack_profile_mapping map on fr.mapping = map.id
+         inner join (
+              select symbol_set_id, FIRST_VALUE(name) OVER(PARTITION BY
+                symbol_set_id) as name
+              from stack_profile_symbol GROUP BY symbol_set_id
+            ) as symbols using(symbol_set_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
@@ -421,7 +430,8 @@
         tableNameGroupedCallsitesForFlamegraph}
         as with recursive callsite_children(hash, name, parent_hash, depth,
           size, alloc_size, count, alloc_count) AS (
-        select *
+        select hash, name, parent_hash, depth, size, alloc_size,
+          count, alloc_count
         from ${tableNameCallsiteHashNameSize}
         union all
         select chns.hash, chns.name, chns.parent_hash, chns.depth, cc.size,