Proto filter: use "bytes" field w/ checksum for bytecode

This CL makes a minor tweak to the bytecode filter
serialization. It's still a packed sequence of varints
with the only two tweaks:
1. Got rid of the proto_filter.proto definition. That
   was not defining anything other than a packed varint
   array but turned out to be very inconvenient to write
   pbtx trace config. In fact arrays in .pbtx require one
   row per entry (in this case, one row per filter word).
   On top of this, I discovered that our pbtx parser doesn't
   support yet packed arrays. So I switched this to be just
   a bytes field (in the next CLs, where it will be plumbed)
   even though its content it's still a sequence of varints.
2. Added a final word to the bytecode with a checksum. This is
   to make sure that we don't screw up accidentally the filter
   in the various proto->string->proto conversions.

Bug: 181012016
Test: updated unittests and fuzzers.
Change-Id: I9d5c5c23de1b4ec93ed307187fdedcc813623572
diff --git a/Android.bp b/Android.bp
index 7f8b8e0..7f7656a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,8 +47,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -125,8 +123,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -303,8 +299,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -388,8 +382,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -490,8 +482,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -579,8 +569,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -698,8 +686,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -773,8 +759,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -821,8 +805,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -897,8 +879,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -966,8 +946,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -1040,8 +1018,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -1152,8 +1128,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -1214,8 +1188,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -1299,8 +1271,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -1397,8 +1367,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -1459,8 +1427,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -1696,8 +1662,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -1857,8 +1821,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -2419,7 +2381,6 @@
     "protos/perfetto/config/profiling/heapprofd_config.proto",
     "protos/perfetto/config/profiling/java_hprof_config.proto",
     "protos/perfetto/config/profiling/perf_event_config.proto",
-    "protos/perfetto/config/proto_filter.proto",
     "protos/perfetto/config/stress_test_config.proto",
     "protos/perfetto/config/sys_stats/sys_stats_config.proto",
     "protos/perfetto/config/test_config.proto",
@@ -3282,112 +3243,6 @@
   ],
 }
 
-// GN: //protos/perfetto/config:proto_filter_cpp
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=wrapper_namespace=gen:$(genDir)/external/perfetto/ $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/config/proto_filter.gen.cc",
-  ],
-}
-
-// GN: //protos/perfetto/config:proto_filter_cpp
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=wrapper_namespace=gen:$(genDir)/external/perfetto/ $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/config/proto_filter.gen.h",
-  ],
-  export_include_dirs: [
-    ".",
-    "protos",
-  ],
-}
-
-// GN: //protos/perfetto/config:proto_filter_lite
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_lite_gen",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/config/proto_filter.pb.cc",
-  ],
-}
-
-// GN: //protos/perfetto/config:proto_filter_lite
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_lite_gen_headers",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
-  out: [
-    "external/perfetto/protos/perfetto/config/proto_filter.pb.h",
-  ],
-  export_include_dirs: [
-    ".",
-    "protos",
-  ],
-}
-
-// GN: //protos/perfetto/config:proto_filter_zero
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_zero_gen",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-    "protozero_plugin",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --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/config/proto_filter.pbzero.cc",
-  ],
-}
-
-// GN: //protos/perfetto/config:proto_filter_zero
-genrule {
-  name: "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
-  srcs: [
-    "protos/perfetto/config/proto_filter.proto",
-  ],
-  tools: [
-    "aprotoc",
-    "protozero_plugin",
-  ],
-  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --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/config/proto_filter.pbzero.h",
-  ],
-  export_include_dirs: [
-    ".",
-    "protos",
-  ],
-}
-
 // GN: //protos/perfetto/config/sys_stats:cpp
 genrule {
   name: "perfetto_protos_perfetto_config_sys_stats_cpp_gen",
@@ -7414,6 +7269,11 @@
   ],
 }
 
+// GN: //src/protozero/filtering:bytecode_common
+filegroup {
+  name: "perfetto_src_protozero_filtering_bytecode_common",
+}
+
 // GN: //src/protozero/filtering:bytecode_generator
 filegroup {
   name: "perfetto_src_protozero_filtering_bytecode_generator",
@@ -8922,7 +8782,6 @@
     ":perfetto_protos_perfetto_config_power_lite_gen",
     ":perfetto_protos_perfetto_config_process_stats_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_track_event_lite_gen",
     ":perfetto_protos_perfetto_trace_android_lite_gen",
@@ -8956,7 +8815,6 @@
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_track_event_lite_gen_headers",
     "perfetto_protos_perfetto_trace_android_lite_gen_headers",
@@ -8986,7 +8844,6 @@
     "perfetto_protos_perfetto_config_power_lite_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_track_event_lite_gen_headers",
     "perfetto_protos_perfetto_trace_android_lite_gen_headers",
@@ -9071,9 +8928,6 @@
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_lite_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_lite_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_lite_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
@@ -9176,6 +9030,7 @@
     ":perfetto_src_profiling_symbolizer_symbolizer",
     ":perfetto_src_profiling_symbolizer_unittests",
     ":perfetto_src_profiling_unittests",
+    ":perfetto_src_protozero_filtering_bytecode_common",
     ":perfetto_src_protozero_filtering_bytecode_generator",
     ":perfetto_src_protozero_filtering_bytecode_parser",
     ":perfetto_src_protozero_filtering_unittests",
@@ -9314,9 +9169,6 @@
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_lite_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_lite_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
@@ -9459,7 +9311,6 @@
     ":perfetto_protos_perfetto_config_power_zero_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -9519,7 +9370,6 @@
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -9609,7 +9459,6 @@
     ":perfetto_protos_perfetto_config_power_zero_gen",
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_zero_gen",
     ":perfetto_protos_perfetto_config_zero_gen",
@@ -9676,7 +9525,6 @@
     "perfetto_protos_perfetto_config_power_zero_gen_headers",
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_zero_gen_headers",
     "perfetto_protos_perfetto_config_zero_gen_headers",
@@ -9768,8 +9616,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -9855,8 +9701,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
@@ -9950,8 +9794,6 @@
     ":perfetto_protos_perfetto_config_process_stats_zero_gen",
     ":perfetto_protos_perfetto_config_profiling_cpp_gen",
     ":perfetto_protos_perfetto_config_profiling_zero_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_cpp_gen",
-    ":perfetto_protos_perfetto_config_proto_filter_zero_gen",
     ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
     ":perfetto_protos_perfetto_config_track_event_cpp_gen",
@@ -10017,8 +9859,6 @@
     "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
     "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_cpp_gen_headers",
-    "perfetto_protos_perfetto_config_proto_filter_zero_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_config_track_event_cpp_gen_headers",
diff --git a/BUILD b/BUILD
index 87fff6a..03c9be8 100644
--- a/BUILD
+++ b/BUILD
@@ -146,7 +146,6 @@
         ":protos_perfetto_config_power_zero",
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_cpp",
         ":protos_perfetto_config_track_event_zero",
@@ -241,8 +240,6 @@
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_cpp",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_cpp",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_cpp",
@@ -1858,7 +1855,6 @@
         ":protos_perfetto_config_power_cpp",
         ":protos_perfetto_config_process_stats_cpp",
         ":protos_perfetto_config_profiling_cpp",
-        ":protos_perfetto_config_proto_filter_cpp",
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_track_event_cpp",
@@ -2181,41 +2177,6 @@
     ],
 )
 
-# GN target: //protos/perfetto/config:proto_filter_cpp
-perfetto_cc_protocpp_library(
-    name = "protos_perfetto_config_proto_filter_cpp",
-    deps = [
-        ":protos_perfetto_config_proto_filter_protos",
-    ],
-)
-
-# GN target: //protos/perfetto/config:proto_filter_lite
-perfetto_cc_proto_library(
-    name = "protos_perfetto_config_proto_filter_lite",
-    deps = [
-        ":protos_perfetto_config_proto_filter_protos",
-    ],
-)
-
-# GN target: //protos/perfetto/config:proto_filter_zero
-perfetto_proto_library(
-    name = "protos_perfetto_config_proto_filter_protos",
-    srcs = [
-        "protos/perfetto/config/proto_filter.proto",
-    ],
-    visibility = [
-        PERFETTO_CONFIG.proto_library_visibility,
-    ],
-)
-
-# GN target: //protos/perfetto/config:proto_filter_zero
-perfetto_cc_protozero_library(
-    name = "protos_perfetto_config_proto_filter_zero",
-    deps = [
-        ":protos_perfetto_config_proto_filter_protos",
-    ],
-)
-
 # GN target: //protos/perfetto/config:zero
 perfetto_proto_library(
     name = "protos_perfetto_config_protos",
@@ -2238,7 +2199,6 @@
         ":protos_perfetto_config_power_protos",
         ":protos_perfetto_config_process_stats_protos",
         ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_proto_filter_protos",
         ":protos_perfetto_config_sys_stats_protos",
         ":protos_perfetto_config_track_event_protos",
     ],
@@ -2332,7 +2292,6 @@
         ":protos_perfetto_config_power_zero",
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_zero",
@@ -2353,7 +2312,6 @@
         ":protos_perfetto_config_power_cpp",
         ":protos_perfetto_config_process_stats_cpp",
         ":protos_perfetto_config_profiling_cpp",
-        ":protos_perfetto_config_proto_filter_cpp",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_track_event_cpp",
         ":protos_perfetto_ipc_protos",
@@ -2374,7 +2332,6 @@
         ":protos_perfetto_config_power_cpp",
         ":protos_perfetto_config_process_stats_cpp",
         ":protos_perfetto_config_profiling_cpp",
-        ":protos_perfetto_config_proto_filter_cpp",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_track_event_cpp",
         ":protos_perfetto_ipc_cpp",
@@ -2402,7 +2359,6 @@
         ":protos_perfetto_config_power_protos",
         ":protos_perfetto_config_process_stats_protos",
         ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_proto_filter_protos",
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_protos",
         ":protos_perfetto_config_track_event_protos",
@@ -2827,7 +2783,6 @@
         ":protos_perfetto_config_power_protos",
         ":protos_perfetto_config_process_stats_protos",
         ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_proto_filter_protos",
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_protos",
         ":protos_perfetto_config_track_event_protos",
@@ -2847,7 +2802,6 @@
         ":protos_perfetto_config_power_zero",
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_zero",
         ":protos_perfetto_config_zero",
@@ -2887,7 +2841,6 @@
         ":protos_perfetto_config_power_protos",
         ":protos_perfetto_config_process_stats_protos",
         ":protos_perfetto_config_profiling_protos",
-        ":protos_perfetto_config_proto_filter_protos",
         ":protos_perfetto_config_protos",
         ":protos_perfetto_config_sys_stats_protos",
         ":protos_perfetto_config_track_event_protos",
@@ -2921,7 +2874,6 @@
         ":protos_perfetto_config_power_zero",
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_zero",
         ":protos_perfetto_config_zero",
@@ -3371,8 +3323,6 @@
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_cpp",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_cpp",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_cpp",
@@ -3451,8 +3401,6 @@
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_cpp",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_cpp",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_cpp",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_cpp",
@@ -3530,7 +3478,6 @@
                ":protos_perfetto_config_power_zero",
                ":protos_perfetto_config_process_stats_zero",
                ":protos_perfetto_config_profiling_zero",
-               ":protos_perfetto_config_proto_filter_zero",
                ":protos_perfetto_config_sys_stats_zero",
                ":protos_perfetto_config_track_event_zero",
                ":protos_perfetto_config_zero",
@@ -3622,7 +3569,6 @@
                ":protos_perfetto_config_power_zero",
                ":protos_perfetto_config_process_stats_zero",
                ":protos_perfetto_config_profiling_zero",
-               ":protos_perfetto_config_proto_filter_zero",
                ":protos_perfetto_config_sys_stats_zero",
                ":protos_perfetto_config_track_event_zero",
                ":protos_perfetto_config_zero",
@@ -3724,7 +3670,6 @@
         ":protos_perfetto_config_power_zero",
         ":protos_perfetto_config_process_stats_zero",
         ":protos_perfetto_config_profiling_zero",
-        ":protos_perfetto_config_proto_filter_zero",
         ":protos_perfetto_config_sys_stats_zero",
         ":protos_perfetto_config_track_event_zero",
         ":protos_perfetto_config_zero",
@@ -3804,7 +3749,6 @@
                ":protos_perfetto_config_power_zero",
                ":protos_perfetto_config_process_stats_zero",
                ":protos_perfetto_config_profiling_zero",
-               ":protos_perfetto_config_proto_filter_zero",
                ":protos_perfetto_config_sys_stats_zero",
                ":protos_perfetto_config_track_event_zero",
                ":protos_perfetto_config_zero",
diff --git a/protos/perfetto/config/BUILD.gn b/protos/perfetto/config/BUILD.gn
index 60bcaf6..de9c1f5 100644
--- a/protos/perfetto/config/BUILD.gn
+++ b/protos/perfetto/config/BUILD.gn
@@ -20,7 +20,6 @@
 
 perfetto_proto_library("@TYPE@") {
   deps = [
-    ":proto_filter_@TYPE@",
     "../common:@TYPE@",
     "android:@TYPE@",
     "ftrace:@TYPE@",
@@ -63,7 +62,3 @@
   generate_descriptor = "perfetto_config.descriptor"
   sources = [ "perfetto_config.proto" ]
 }
-
-perfetto_proto_library("proto_filter_@TYPE@") {
-  sources = [ "proto_filter.proto" ]
-}
diff --git a/protos/perfetto/config/proto_filter.proto b/protos/perfetto/config/proto_filter.proto
deleted file mode 100644
index deec693..0000000
--- a/protos/perfetto/config/proto_filter.proto
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package perfetto.protos;
-
-// This proto wraps a bytecode that describes how to filter proto messages.
-// For the full specs of the filter bytecode see go/trace-filtering.
-// In short:
-// - A filter is a sequence of uint32 words.
-// - Each word is (immediate value << 3) | (3-bit OPCODE)
-// - Each group of words (until END_OF_MESSAGE) defines field filters for a
-//   message. The first message is the root message where the filtering starts
-//   (typically perfetto.protos.Trace).
-message ProtoFilter {
-  enum Opcode {
-    // The immediate value is 0 in this case.
-    FILTER_OPCODE_END_OF_MESSAGE = 0;
-
-    // The immediate value is the id of the allowed field.
-    FILTER_OPCODE_SIMPLE_FIELD = 1;
-
-    // The immediate value is the start of the range. The next word (without
-    // any shifting) is the length of the range.
-    FILTER_OPCODE_SIMPLE_FIELD_RANGE = 2;
-
-    // The immediate value is the id of the allowed field. The next word
-    // (without any shifting) is the index of the filter that should be used to
-    // recurse into the nested message.
-    FILTER_OPCODE_NESTED_FIELD = 3;
-  }
-  repeated uint32 bytecode = 1 [packed = true];
-}
diff --git a/src/protozero/filtering/BUILD.gn b/src/protozero/filtering/BUILD.gn
index 0ddfc3e..3afdaab 100644
--- a/src/protozero/filtering/BUILD.gn
+++ b/src/protozero/filtering/BUILD.gn
@@ -17,15 +17,20 @@
 import("../../../gn/proto_library.gni")
 import("../../../gn/test.gni")
 
+source_set("bytecode_common") {
+  sources = [ "filter_bytecode_common.h" ]
+  deps = [ "../../../gn:default_deps" ]
+}
+
 source_set("bytecode_parser") {
   sources = [
     "filter_bytecode_parser.cc",
     "filter_bytecode_parser.h",
   ]
   deps = [
+    ":bytecode_common",
     "..:protozero",
     "../../../gn:default_deps",
-    "../../../protos/perfetto/config:proto_filter_zero",
     "../../base",
   ]
 }
@@ -36,9 +41,9 @@
     "filter_bytecode_generator.h",
   ]
   deps = [
+    ":bytecode_common",
     "..:protozero",
     "../../../gn:default_deps",
-    "../../../protos/perfetto/config:proto_filter_zero",
     "../../base",
   ]
 }
@@ -46,12 +51,12 @@
 perfetto_unittest_source_set("unittests") {
   testonly = true
   deps = [
+    ":bytecode_common",
     ":bytecode_generator",
     ":bytecode_parser",
     "..:protozero",
     "../../../gn:default_deps",
     "../../../gn:gtest_and_gmock",
-    "../../../protos/perfetto/config:proto_filter_zero",
     "../../base",
     "../../base:test_support",
   ]
@@ -66,6 +71,8 @@
   sources = [ "filter_bytecode_parser_fuzzer.cc" ]
   deps = [
     ":bytecode_parser",
+    "..:protozero",
     "../../../gn:default_deps",
+    "../../base",
   ]
 }
diff --git a/src/protozero/filtering/filter_bytecode_common.h b/src/protozero/filtering/filter_bytecode_common.h
new file mode 100644
index 0000000..9c0e6f2
--- /dev/null
+++ b/src/protozero/filtering/filter_bytecode_common.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
+#define SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
+
+#include <stdint.h>
+
+namespace protozero {
+
+enum FilterOpcode : uint32_t {
+  // The immediate value is 0 in this case.
+  kFilterOpcode_EndOfMessage = 0,
+
+  // The immediate value is the id of the allowed field.
+  kFilterOpcode_SimpleField = 1,
+
+  // The immediate value is the start of the range. The next word (without
+  // any shifting) is the length of the range.
+  kFilterOpcode_SimpleFieldRange = 2,
+
+  // The immediate value is the id of the allowed field. The next word
+  // (without any shifting) is the index of the filter that should be used to
+  // recurse into the nested message.
+  kFilterOpcode_NestedField = 3,
+};
+}  // namespace protozero
+
+#endif  // SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
diff --git a/src/protozero/filtering/filter_bytecode_generator.cc b/src/protozero/filtering/filter_bytecode_generator.cc
index df3a80e..9362869 100644
--- a/src/protozero/filtering/filter_bytecode_generator.cc
+++ b/src/protozero/filtering/filter_bytecode_generator.cc
@@ -17,22 +17,20 @@
 #include "src/protozero/filtering/filter_bytecode_generator.h"
 
 #include "perfetto/base/logging.h"
+#include "perfetto/ext/base/hash.h"
 #include "perfetto/protozero/packed_repeated_fields.h"
 #include "perfetto/protozero/proto_utils.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
-
-#include "protos/perfetto/config/proto_filter.pbzero.h"
+#include "src/protozero/filtering/filter_bytecode_common.h"
 
 namespace protozero {
 
-using ProtoFilter = perfetto::protos::pbzero::ProtoFilter;
-
 FilterBytecodeGenerator::FilterBytecodeGenerator() = default;
 FilterBytecodeGenerator::~FilterBytecodeGenerator() = default;
 
 void FilterBytecodeGenerator::EndMessage() {
   endmessage_called_ = true;
-  bytecode_.push_back(ProtoFilter::FILTER_OPCODE_END_OF_MESSAGE);
+  bytecode_.push_back(kFilterOpcode_EndOfMessage);
   last_field_id_ = 0;
   ++num_messages_;
 }
@@ -40,7 +38,7 @@
 // Allows a simple field (varint, fixed32/64, string or bytes).
 void FilterBytecodeGenerator::AddSimpleField(uint32_t field_id) {
   PERFETTO_CHECK(field_id > last_field_id_);
-  bytecode_.push_back(field_id << 3 | ProtoFilter::FILTER_OPCODE_SIMPLE_FIELD);
+  bytecode_.push_back(field_id << 3 | kFilterOpcode_SimpleField);
   last_field_id_ = field_id;
   endmessage_called_ = false;
 }
@@ -52,8 +50,7 @@
                                                   uint32_t range_len) {
   PERFETTO_CHECK(range_start > last_field_id_);
   PERFETTO_CHECK(range_len > 0);
-  bytecode_.push_back(range_start << 3 |
-                      ProtoFilter::FILTER_OPCODE_SIMPLE_FIELD_RANGE);
+  bytecode_.push_back(range_start << 3 | kFilterOpcode_SimpleFieldRange);
   bytecode_.push_back(range_len);
   last_field_id_ = range_start + range_len - 1;
   endmessage_called_ = false;
@@ -67,26 +64,28 @@
 void FilterBytecodeGenerator::AddNestedField(uint32_t field_id,
                                              uint32_t message_index) {
   PERFETTO_CHECK(field_id > last_field_id_);
-  bytecode_.push_back(field_id << 3 | ProtoFilter::FILTER_OPCODE_NESTED_FIELD);
+  bytecode_.push_back(field_id << 3 | kFilterOpcode_NestedField);
   bytecode_.push_back(message_index);
   last_field_id_ = field_id;
   max_msg_index_ = std::max(max_msg_index_, message_index);
   endmessage_called_ = false;
 }
 
-// Returns the proto-encoded bytes for a perfetto.protos.ProtoFilter message
-// (see proto_filter.proto). The returned string can be passed to
-// FilterBytecodeParser.Load().
+// Returns the bytes that can be used into TraceConfig.trace_filter.bytecode.
+// The returned bytecode is a binary buffer which consists of a sequence of
+// varints (the opcodes) and a checksum.
+// The returned string can be passed as-is to FilterBytecodeParser.Load().
 std::string FilterBytecodeGenerator::Serialize() {
   PERFETTO_CHECK(endmessage_called_);
   PERFETTO_CHECK(max_msg_index_ < num_messages_);
   protozero::PackedVarInt words;
-  for (uint32_t word : bytecode_)
+  perfetto::base::Hash hasher;
+  for (uint32_t word : bytecode_) {
     words.Append(word);
-
-  protozero::HeapBuffered<ProtoFilter> filter;
-  filter->set_bytecode(words);
-  return filter.SerializeAsString();
+    hasher.Update(word);
+  }
+  words.Append(static_cast<uint32_t>(hasher.digest()));
+  return std::string(reinterpret_cast<const char*>(words.data()), words.size());
 }
 
 }  // namespace protozero
diff --git a/src/protozero/filtering/filter_bytecode_generator.h b/src/protozero/filtering/filter_bytecode_generator.h
index 481d39f..809799c 100644
--- a/src/protozero/filtering/filter_bytecode_generator.h
+++ b/src/protozero/filtering/filter_bytecode_generator.h
@@ -57,8 +57,8 @@
   // made).
   void AddNestedField(uint32_t field_id, uint32_t message_index);
 
-  // Returns the proto-encoded bytes for a perfetto.protos.ProtoFilter message
-  // (see proto_filter.proto). The returned string can be passed to
+  // Returns the filter bytecode, which is a buffer containing a sequence of
+  // varints and a checksum. The returned string can be passed to
   // FilterBytecodeParser.Load().
   std::string Serialize();
 
diff --git a/src/protozero/filtering/filter_bytecode_generator_unittest.cc b/src/protozero/filtering/filter_bytecode_generator_unittest.cc
index 95181f5..650120b 100644
--- a/src/protozero/filtering/filter_bytecode_generator_unittest.cc
+++ b/src/protozero/filtering/filter_bytecode_generator_unittest.cc
@@ -21,8 +21,6 @@
 #include "src/protozero/filtering/filter_bytecode_generator.h"
 #include "src/protozero/filtering/filter_bytecode_parser.h"
 
-#include "protos/perfetto/config/proto_filter.pbzero.h"
-
 // This file tests the generator, assuming the parser is good.
 // The parser is tested separately (without the generator) in
 // filter_bytecode_parser_unittest.cc
diff --git a/src/protozero/filtering/filter_bytecode_parser.cc b/src/protozero/filtering/filter_bytecode_parser.cc
index 1a1d32f..c585b5c 100644
--- a/src/protozero/filtering/filter_bytecode_parser.cc
+++ b/src/protozero/filtering/filter_bytecode_parser.cc
@@ -17,15 +17,18 @@
 #include "src/protozero/filtering/filter_bytecode_parser.h"
 
 #include "perfetto/base/logging.h"
+#include "perfetto/ext/base/hash.h"
 #include "perfetto/protozero/packed_repeated_fields.h"
+#include "perfetto/protozero/proto_decoder.h"
 #include "perfetto/protozero/proto_utils.h"
-
-#include "protos/perfetto/config/proto_filter.pbzero.h"
+#include "src/protozero/filtering/filter_bytecode_common.h"
 
 namespace protozero {
 
 void FilterBytecodeParser::Reset() {
+  bool suppress = suppress_logs_for_fuzzer_;
   *this = FilterBytecodeParser();
+  suppress_logs_for_fuzzer_ = suppress;
 }
 
 bool FilterBytecodeParser::Load(const void* filter_data, size_t len) {
@@ -37,22 +40,37 @@
   return res;
 }
 
-bool FilterBytecodeParser::LoadInternal(const uint8_t* filter_data,
+bool FilterBytecodeParser::LoadInternal(const uint8_t* bytecode_data,
                                         size_t len) {
-  using ProtoFilter = perfetto::protos::pbzero::ProtoFilter;
   // First unpack the varints into a plain uint32 vector, so it's easy to
   // iterate through them and look ahead.
-  std::vector<uint32_t> bytecode;
-  {
-    ProtoFilter::Decoder dec(filter_data, len);
-    bool packed_parse_err = false;
-    bytecode.reserve(len);  // An overestimation, but avoids reallocations.
-    for (auto it = dec.bytecode(&packed_parse_err); it; ++it)
-      bytecode.emplace_back(*it);
-    if (packed_parse_err)
-      return false;
+  std::vector<uint32_t> words;
+  bool packed_parse_err = false;
+  words.reserve(len);  // An overestimation, but avoids reallocations.
+  using BytecodeDecoder =
+      PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
+                                  uint32_t>;
+  for (BytecodeDecoder it(bytecode_data, len, &packed_parse_err); it; ++it)
+    words.emplace_back(*it);
+
+  if (packed_parse_err || words.empty())
+    return false;
+
+  perfetto::base::Hash hasher;
+  for (size_t i = 0; i < words.size() - 1; ++i)
+    hasher.Update(words[i]);
+
+  uint32_t expected_csum = static_cast<uint32_t>(hasher.digest());
+  if (expected_csum != words.back()) {
+    if (!suppress_logs_for_fuzzer_) {
+      PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
+                    expected_csum, words.back());
+    }
+    return false;
   }
 
+  words.pop_back();  // Pop the checksum.
+
   // Temporay storage for each message. Cleared on every END_OF_MESSAGE.
   std::vector<uint32_t> direct_indexed_fields;
   std::vector<uint32_t> ranges;
@@ -73,26 +91,26 @@
     ranges.emplace_back(kAllowed | msg_id);
   };
 
-  for (size_t i = 0; i < bytecode.size(); ++i) {
-    const uint32_t word = bytecode[i];
-    const bool has_next_word = i < bytecode.size() - 1;
+  for (size_t i = 0; i < words.size(); ++i) {
+    const uint32_t word = words[i];
+    const bool has_next_word = i < words.size() - 1;
     const uint32_t opcode = word & 0x7u;
     const uint32_t field_id = word >> 3;
 
-    if (opcode == ProtoFilter::FILTER_OPCODE_SIMPLE_FIELD ||
-        opcode == ProtoFilter::FILTER_OPCODE_NESTED_FIELD) {
-      if (field_id == 0) {
-        PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
-        return false;
-      }
+    if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
+      PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
+      return false;
+    }
 
+    if (opcode == kFilterOpcode_SimpleField ||
+        opcode == kFilterOpcode_NestedField) {
       // Field words are organized as follow:
       // MSB: 1 if allowed, 0 if not allowed.
       // Remaining bits:
       //   Message index in the case of nested (non-simple) messages.
       //   0x7f..f in the case of simple messages.
       uint32_t msg_id;
-      if (opcode == ProtoFilter::FILTER_OPCODE_SIMPLE_FIELD) {
+      if (opcode == kFilterOpcode_SimpleField) {
         msg_id = kSimpleField;
       } else {  // FILTER_OPCODE_NESTED_FIELD
         // The next word in the bytecode contains the message index.
@@ -101,7 +119,7 @@
                         i);
           return false;
         }
-        msg_id = bytecode[++i];
+        msg_id = words[++i];
         max_msg_index = std::max(max_msg_index, msg_id);
       }
 
@@ -113,12 +131,12 @@
         // complexity to deal with rare cases like this.
         add_range(field_id, field_id + 1, msg_id);
       }
-    } else if (opcode == ProtoFilter::FILTER_OPCODE_SIMPLE_FIELD_RANGE) {
+    } else if (opcode == kFilterOpcode_SimpleFieldRange) {
       if (!has_next_word) {
         PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
         return false;
       }
-      const uint32_t range_len = bytecode[++i];
+      const uint32_t range_len = words[++i];
       const uint32_t range_end = field_id + range_len;  // STL-style, excl.
       uint32_t id = field_id;
 
@@ -132,7 +150,7 @@
       PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
       if (id < range_end)
         add_range(id, range_end, kSimpleField);
-    } else if (opcode == ProtoFilter::FILTER_OPCODE_END_OF_MESSAGE) {
+    } else if (opcode == kFilterOpcode_EndOfMessage) {
       // For each message append:
       // 1. The "header" word telling how many directly indexed fields there
       //    are.
diff --git a/src/protozero/filtering/filter_bytecode_parser.h b/src/protozero/filtering/filter_bytecode_parser.h
index c71ec30..b2378ca 100644
--- a/src/protozero/filtering/filter_bytecode_parser.h
+++ b/src/protozero/filtering/filter_bytecode_parser.h
@@ -24,10 +24,9 @@
 
 namespace protozero {
 
-// Loads the proto-encoded bytecode (see proto_filter.proto) in memory and
-// allows fast lookups for tuples (msg_index, field_id) to tell if a given field
-// should be allowed or not and, in the case of nested fields, what is the next
-// message index to recurse into.
+// Loads the proto-encoded bytecode in memory and allows fast lookups for tuples
+// (msg_index, field_id) to tell if a given field should be allowed or not and,
+// in the case of nested fields, what is the next message index to recurse into.
 // This class does two things:
 // 1. Expands the array of varint from the proto into a vector<uint32_t>. This
 //    is to avoid performing varint decoding on every lookup, at the cost of
@@ -58,8 +57,8 @@
     bool simple_field() const { return nested_msg_index == kSimpleField; }
   };
 
-  // Loads a filter. The passed data must be proto-encoded bytes for a
-  // perfetto.protos.ProtoFilter message.
+  // Loads a filter. The filter data consists of a sequence of varints which
+  // contains the filter opcodes and a final checksum.
   bool Load(const void* filter_data, size_t len);
 
   // Checks wheter a given field is allowed or not.
@@ -68,6 +67,7 @@
   QueryResult Query(uint32_t msg_index, uint32_t field_id);
 
   void Reset();
+  void set_suppress_logs_for_fuzzer(bool x) { suppress_logs_for_fuzzer_ = x; }
 
  private:
   static constexpr uint32_t kDirectlyIndexLimit = 128;
@@ -115,6 +115,8 @@
   // Nth message start.
   // message_offset_.size() - 2 == the max message id that can be parsed.
   std::vector<uint32_t> message_offset_;
+
+  bool suppress_logs_for_fuzzer_ = false;
 };
 
 }  // namespace protozero
diff --git a/src/protozero/filtering/filter_bytecode_parser_fuzzer.cc b/src/protozero/filtering/filter_bytecode_parser_fuzzer.cc
index 33dc5c9..578f6c9 100644
--- a/src/protozero/filtering/filter_bytecode_parser_fuzzer.cc
+++ b/src/protozero/filtering/filter_bytecode_parser_fuzzer.cc
@@ -18,14 +18,46 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "perfetto/ext/base/hash.h"
+
+#include "perfetto/protozero/packed_repeated_fields.h"
 #include "src/protozero/filtering/filter_bytecode_parser.h"
 
 namespace protozero {
 namespace {
 
+// This function gives a little help to the fuzzer. The bytecode is really a
+// sequence of varint-encoded uint32 words, with a FNV1a checksum at the end.
+// It's very unlikely that the fuzzer on its own can work out the checksum, so
+// most fuzzer inputs are doomed to fail the checksum verification.
+// This takes the fuzzer input and builds a more plausible bytecode.
+void LoadBytecodeWithChecksum(FilterBytecodeParser* parser,
+                              const uint8_t* data,
+                              size_t size) {
+  protozero::PackedVarInt words;
+  perfetto::base::Hash hasher;
+  for (size_t i = 0; i < size; i += sizeof(uint32_t)) {
+    uint32_t word = 0;
+    memcpy(&word, data, sizeof(uint32_t));
+    words.Append(word);
+    hasher.Update(word);
+  }
+  words.Append(static_cast<uint32_t>(hasher.digest()));
+  parser->Load(words.data(), words.size());
+}
+
 int FuzzBytecodeParser(const uint8_t* data, size_t size) {
   FilterBytecodeParser parser;
-  parser.Load(data, size > 8 ? size - 8 : size);
+  parser.set_suppress_logs_for_fuzzer(true);
+
+  if (size > 4 && data[0] < 192) {
+    // 75% of the times use the LoadBytecodeWithChecksum() which helps the
+    // fuzzer passing the checksum verification.
+    LoadBytecodeWithChecksum(&parser, data + 1, size - 1);
+  } else {
+    // In the remaining 25%, pass completely arbitrary inputs.
+    parser.Load(data, size);
+  }
 
   // Smoke testing with known problematic values
   for (uint32_t msg_index = 0; msg_index < 3; ++msg_index) {
diff --git a/src/protozero/filtering/filter_bytecode_parser_unittest.cc b/src/protozero/filtering/filter_bytecode_parser_unittest.cc
index 28e4e4b..5b67ded 100644
--- a/src/protozero/filtering/filter_bytecode_parser_unittest.cc
+++ b/src/protozero/filtering/filter_bytecode_parser_unittest.cc
@@ -16,33 +16,32 @@
 
 #include "test/gtest_and_gmock.h"
 
+#include "perfetto/ext/base/hash.h"
 #include "perfetto/protozero/packed_repeated_fields.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
+#include "src/protozero/filtering/filter_bytecode_common.h"
 #include "src/protozero/filtering/filter_bytecode_parser.h"
 
-#include "protos/perfetto/config/proto_filter.pbzero.h"
-
 namespace protozero {
 
 namespace {
 
-using PF = perfetto::protos::pbzero::ProtoFilter;
 
 bool LoadBytecode(FilterBytecodeParser* parser,
                   std::initializer_list<uint32_t> bytecode) {
+  perfetto::base::Hash hasher;
   protozero::PackedVarInt words;
-  for (uint32_t w : bytecode)
+  for (uint32_t w : bytecode) {
     words.Append(w);
-
-  HeapBuffered<PF> filter;
-  filter->set_bytecode(words);
-  auto filter_msg = filter.SerializeAsArray();
-  return parser->Load(filter_msg.data(), filter_msg.size());
+    hasher.Update(w);
+  }
+  words.Append(static_cast<uint32_t>(hasher.digest()));
+  return parser->Load(words.data(), words.size());
 }
 
 TEST(FilterBytecodeParserTest, ParserSimpleFields) {
   FilterBytecodeParser parser;
-  EXPECT_TRUE(parser.Load(nullptr, 0));
+  EXPECT_FALSE(parser.Load(nullptr, 0));
   EXPECT_FALSE(parser.Query(42, 42).allowed);
 
   EXPECT_TRUE(LoadBytecode(&parser, {}));
@@ -54,12 +53,12 @@
   EXPECT_FALSE(parser.Query(42, 42).allowed);
 
   // An invalid field_id (0) in bytecode should cause a parse failure.
-  EXPECT_FALSE(LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD | 0,
-                                      PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_FALSE(LoadBytecode(
+      &parser, {kFilterOpcode_SimpleField | 0, kFilterOpcode_EndOfMessage}));
 
   // A valid bytecode that has only one field.
-  EXPECT_TRUE(LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD | (2u << 3),
-                                     PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_TRUE(LoadBytecode(&parser, {kFilterOpcode_SimpleField | (2u << 3),
+                                     kFilterOpcode_EndOfMessage}));
   EXPECT_FALSE(parser.Query(0, 0).allowed);
   EXPECT_FALSE(parser.Query(0, 1).allowed);
   EXPECT_TRUE(parser.Query(0, 2).allowed);
@@ -71,12 +70,11 @@
   EXPECT_FALSE(parser.Query(1, 3).allowed);
 
   // A valid bytecode that has few sparse fields < 128.
-  EXPECT_TRUE(
-      LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD | (1u << 3),
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (7u << 3),
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (8u << 3),
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (127u << 3),
-                             PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_TRUE(LoadBytecode(&parser, {kFilterOpcode_SimpleField | (1u << 3),
+                                     kFilterOpcode_SimpleField | (7u << 3),
+                                     kFilterOpcode_SimpleField | (8u << 3),
+                                     kFilterOpcode_SimpleField | (127u << 3),
+                                     kFilterOpcode_EndOfMessage}));
   EXPECT_FALSE(parser.Query(0, 0).allowed);
   EXPECT_TRUE(parser.Query(0, 1).allowed);
   EXPECT_FALSE(parser.Query(0, 2).allowed);
@@ -90,11 +88,10 @@
   EXPECT_FALSE(parser.Query(0, 128).allowed);
 
   // A valid bytecode that has only fields > 128.
-  EXPECT_TRUE(
-      LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD | (1000u << 3),
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (1001u << 3),
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (2000u << 3),
-                             PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_TRUE(LoadBytecode(&parser, {kFilterOpcode_SimpleField | (1000u << 3),
+                                     kFilterOpcode_SimpleField | (1001u << 3),
+                                     kFilterOpcode_SimpleField | (2000u << 3),
+                                     kFilterOpcode_EndOfMessage}));
   for (uint32_t i = 0; i < 1000; ++i)
     EXPECT_FALSE(parser.Query(0, i).allowed);
   EXPECT_TRUE(parser.Query(0, 1000).allowed);
@@ -109,28 +106,28 @@
   FilterBytecodeParser parser;
 
   // Invalid, range length missing.
-  EXPECT_FALSE(LoadBytecode(
-      &parser, {
-                   PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (2u << 3),
-               }));
+  EXPECT_FALSE(
+      LoadBytecode(&parser, {
+                                kFilterOpcode_SimpleFieldRange | (2u << 3),
+                            }));
 
   // Borderline valid: range length = 0.
-  EXPECT_TRUE(LoadBytecode(
-      &parser, {PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (2u << 3), 0u,
-                PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (127u << 3), 0u,
-                PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (128u << 3), 0u,
-                PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (128u << 3), 0u,
-                PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_TRUE(
+      LoadBytecode(&parser, {kFilterOpcode_SimpleFieldRange | (2u << 3), 0u,
+                             kFilterOpcode_SimpleFieldRange | (127u << 3), 0u,
+                             kFilterOpcode_SimpleFieldRange | (128u << 3), 0u,
+                             kFilterOpcode_SimpleFieldRange | (128u << 3), 0u,
+                             kFilterOpcode_EndOfMessage}));
   for (uint32_t i = 0; i < 130; ++i)
     EXPECT_FALSE(parser.Query(0, i).allowed) << i;
 
   // A valid bytecode with two ranges [2,2], [10, 14].
   EXPECT_TRUE(
-      LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (2u << 3),
+      LoadBytecode(&parser, {kFilterOpcode_SimpleFieldRange | (2u << 3),
                              1u,  // length of the range,
-                             PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (10u << 3),
+                             kFilterOpcode_SimpleFieldRange | (10u << 3),
                              5u,  // length of the range,
-                             PF::FILTER_OPCODE_END_OF_MESSAGE}));
+                             kFilterOpcode_EndOfMessage}));
   EXPECT_FALSE(parser.Query(0, 0).allowed);
   EXPECT_FALSE(parser.Query(0, 1).allowed);
   EXPECT_TRUE(parser.Query(0, 2).allowed);
@@ -147,17 +144,17 @@
 
   // Borderline valid: range length = 0.
   EXPECT_TRUE(
-      LoadBytecode(&parser, {PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (1u << 3),
+      LoadBytecode(&parser, {kFilterOpcode_SimpleFieldRange | (1u << 3),
                              2u,  // [1,2]
 
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (4u << 3),
+                             kFilterOpcode_SimpleField | (4u << 3),
 
-                             PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (126u << 3),
+                             kFilterOpcode_SimpleFieldRange | (126u << 3),
                              4u,  // [126, 129]
 
-                             PF::FILTER_OPCODE_SIMPLE_FIELD | (150u << 3),
+                             kFilterOpcode_SimpleField | (150u << 3),
 
-                             PF::FILTER_OPCODE_END_OF_MESSAGE}));
+                             kFilterOpcode_EndOfMessage}));
   EXPECT_TRUE(parser.Query(0, 1).allowed);
   EXPECT_TRUE(parser.Query(0, 2).allowed);
   EXPECT_FALSE(parser.Query(0, 3).allowed);
@@ -175,42 +172,41 @@
 
   // Invalid because there are 1 messages in total, and message index 1 is
   // out of range.
-  EXPECT_FALSE(
-      LoadBytecode(&parser, {PF::FILTER_OPCODE_NESTED_FIELD | (4u << 3),
-                             1u,  // message index
-                             PF::FILTER_OPCODE_END_OF_MESSAGE}));
+  EXPECT_FALSE(LoadBytecode(&parser, {kFilterOpcode_NestedField | (4u << 3),
+                                      1u,  // message index
+                                      kFilterOpcode_EndOfMessage}));
 
   // A valid bytecode consisting of 4 message, with recursive / cylical
   // dependencies between them.
   EXPECT_TRUE(LoadBytecode(
       &parser, {
                    // Message 0 (root).
-                   PF::FILTER_OPCODE_SIMPLE_FIELD_RANGE | (1u << 3),
+                   kFilterOpcode_SimpleFieldRange | (1u << 3),
                    2u,  // [1,2]
-                   PF::FILTER_OPCODE_NESTED_FIELD | (4u << 3),
+                   kFilterOpcode_NestedField | (4u << 3),
                    3u,  // message index
-                   PF::FILTER_OPCODE_SIMPLE_FIELD | (10u << 3),
-                   PF::FILTER_OPCODE_NESTED_FIELD | (127u << 3),
+                   kFilterOpcode_SimpleField | (10u << 3),
+                   kFilterOpcode_NestedField | (127u << 3),
                    1u,  // message index
-                   PF::FILTER_OPCODE_NESTED_FIELD | (128u << 3),
+                   kFilterOpcode_NestedField | (128u << 3),
                    2u,  // message index
-                   PF::FILTER_OPCODE_END_OF_MESSAGE,
+                   kFilterOpcode_EndOfMessage,
 
                    // Message 1.
-                   PF::FILTER_OPCODE_NESTED_FIELD | (2u << 3),
+                   kFilterOpcode_NestedField | (2u << 3),
                    1u,  // message index (recurse onto itself),
-                   PF::FILTER_OPCODE_SIMPLE_FIELD | (11u << 3),
-                   PF::FILTER_OPCODE_END_OF_MESSAGE,
+                   kFilterOpcode_SimpleField | (11u << 3),
+                   kFilterOpcode_EndOfMessage,
 
                    // Message 2.
-                   PF::FILTER_OPCODE_NESTED_FIELD | (2u << 3),
+                   kFilterOpcode_NestedField | (2u << 3),
                    3u,  // message index.
-                   PF::FILTER_OPCODE_END_OF_MESSAGE,
+                   kFilterOpcode_EndOfMessage,
 
                    // Message 3.
-                   PF::FILTER_OPCODE_NESTED_FIELD | (2u << 3),
+                   kFilterOpcode_NestedField | (2u << 3),
                    2u,  // message index (create a cycle, 2->3, 3->2).
-                   PF::FILTER_OPCODE_END_OF_MESSAGE,
+                   kFilterOpcode_EndOfMessage,
                }));
 
   // Query message 0 fields.
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index 2670372..b5e2561 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/tools/install-build-deps b/tools/install-build-deps
index bc7765e..878f1f6 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -234,8 +234,8 @@
     # Example traces for regression tests.
     Dependency(
         'test/data.zip',
-        'https://storage.googleapis.com/perfetto/test-data-20210416-122153.zip',
-        '0c3a7b353c1100b783873009949596e75db5ecc4a5cf114f24ccf3f1b08570d3',
+        'https://storage.googleapis.com/perfetto/test-data-20210513-224349.zip',
+        '3dcc146f4ce38d17fd1f8c4c65af07e7cf7c5c4cb8aa4c7bf73ec3a095d997d1',
         'all', 'all',
     ),
 
diff --git a/tools/test_data.txt b/tools/test_data.txt
index abcb65d..55ee848 100644
--- a/tools/test_data.txt
+++ b/tools/test_data.txt
@@ -1,5 +1,8 @@
 # List of test deps that should be pushed on the device. Paths are relative
 # to the root.
-src/traced/probes/ftrace/test/data/
 src/traced/probes/filesystem/testdata/
+src/traced/probes/ftrace/test/data/
+test/data/android_log_ring_buffer_mode.pb
+test/data/example_android_trace_30s.pb
+test/data/full_trace_filter.bytecode
 test/data/kallsyms.txt