Merge "Project import generated by Copybara."
diff --git a/Android.bp b/Android.bp
index 2de8862..687d3f5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6744,6 +6744,7 @@
 genrule {
     name: "perfetto_protos_perfetto_trace_processor_zero_gen",
     srcs: [
+        "protos/perfetto/trace_processor/cloud_trace_processor.proto",
         "protos/perfetto/trace_processor/metatrace_categories.proto",
         "protos/perfetto/trace_processor/trace_processor.proto",
     ],
@@ -6753,6 +6754,7 @@
     ],
     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/trace_processor/cloud_trace_processor.pbzero.cc",
         "external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.cc",
         "external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.cc",
     ],
@@ -6762,6 +6764,7 @@
 genrule {
     name: "perfetto_protos_perfetto_trace_processor_zero_gen_headers",
     srcs: [
+        "protos/perfetto/trace_processor/cloud_trace_processor.proto",
         "protos/perfetto/trace_processor/metatrace_categories.proto",
         "protos/perfetto/trace_processor/trace_processor.proto",
     ],
@@ -6771,6 +6774,7 @@
     ],
     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/trace_processor/cloud_trace_processor.pbzero.h",
         "external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.h",
         "external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.h",
     ],
@@ -8139,6 +8143,7 @@
 filegroup {
     name: "perfetto_src_base_threading_unittests",
     srcs: [
+        "src/base/threading/channel_unittest.cc",
         "src/base/threading/thread_pool_unittest.cc",
     ],
 }
diff --git a/BUILD b/BUILD
index 05a8baf..2232f30 100644
--- a/BUILD
+++ b/BUILD
@@ -4035,6 +4035,7 @@
 perfetto_proto_library(
     name = "protos_perfetto_trace_processor_protos",
     srcs = [
+        "protos/perfetto/trace_processor/cloud_trace_processor.proto",
         "protos/perfetto/trace_processor/metatrace_categories.proto",
         "protos/perfetto/trace_processor/trace_processor.proto",
     ],
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index be78fcf..d1dc6c8 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -1473,6 +1473,11 @@
     ]
   }
 
+  config("grpc_re2_config") {
+    visibility = _buildtools_visibility
+    include_dirs = [ "grpc/src/third_party/re2" ]
+  }
+
   config("grpc_internal_config") {
     visibility = _buildtools_visibility
     include_dirs = [
@@ -1487,10 +1492,24 @@
     cflags = [ "-DGRPC_ARES=0" ]
   }
 
-  source_set("grpc") {
-    deps = [
-      "grpc:grpc++",
-      "//gn:default_deps",
+  config("grpc_gen_config") {
+    cflags = [
+      # Using -isystem instead of include_dirs (-I), so we don't need to
+      # suppress warnings coming from libprotobuf headers. Doing so would mask
+      # warnings in our own code.
+      perfetto_isystem_cflag,
+      rebase_path("grpc/src/include", root_build_dir),
+      perfetto_isystem_cflag,
+      rebase_path("grpc/src/third_party/abseil-cpp", root_build_dir),
     ]
+
+    # This issues appear in .grpc.pb.h files so we unfortunately need to leak
+    # the cflags outside of just compiling this code.
+    if (is_clang && !is_win) {
+      cflags += [
+        "-Wno-weak-vtables",
+        "-Wno-suggest-destructor-override",
+      ]
+    }
   }
 }
diff --git a/buildtools/grpc/BUILD.gn b/buildtools/grpc/BUILD.gn
index 4702dab..16ca941 100644
--- a/buildtools/grpc/BUILD.gn
+++ b/buildtools/grpc/BUILD.gn
@@ -5,9 +5,15 @@
 # tools/gen_grpc_build_gn.py > buildtools/grpc/BUILD.gn
 #
 
+import("../../gn/perfetto.gni")
+
 # Prevent the gRPC from being depended upon without explicitly being opted in.
 assert(enable_perfetto_grpc)
 
+# BoringSSL has assembly code which is tied to platform-specific. For now, we
+# only care about Linux x64 so assert this as the case.
+assert(is_linux && current_cpu == "x64")
+
 source_set("absl_algorithm_algorithm") {
   sources = [ "src/third_party/abseil-cpp/absl/algorithm/algorithm.h" ]
   public_deps = [ ":absl_base_config" ]
@@ -2659,7 +2665,7 @@
   configs -= [ "//gn/standalone:extra_warnings" ]
 }
 
-source_set("upb") {
+static_library("upb") {
   sources = [
     "src/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c",
     "src/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h",
@@ -2722,9 +2728,85 @@
   configs -= [ "//gn/standalone:extra_warnings" ]
 }
 
-source_set("boringssl") {
+static_library("re2") {
+  sources = [
+    "src/third_party/re2/re2/bitmap256.h",
+    "src/third_party/re2/re2/bitstate.cc",
+    "src/third_party/re2/re2/compile.cc",
+    "src/third_party/re2/re2/dfa.cc",
+    "src/third_party/re2/re2/filtered_re2.cc",
+    "src/third_party/re2/re2/filtered_re2.h",
+    "src/third_party/re2/re2/mimics_pcre.cc",
+    "src/third_party/re2/re2/nfa.cc",
+    "src/third_party/re2/re2/onepass.cc",
+    "src/third_party/re2/re2/parse.cc",
+    "src/third_party/re2/re2/perl_groups.cc",
+    "src/third_party/re2/re2/pod_array.h",
+    "src/third_party/re2/re2/prefilter.cc",
+    "src/third_party/re2/re2/prefilter.h",
+    "src/third_party/re2/re2/prefilter_tree.cc",
+    "src/third_party/re2/re2/prefilter_tree.h",
+    "src/third_party/re2/re2/prog.cc",
+    "src/third_party/re2/re2/prog.h",
+    "src/third_party/re2/re2/re2.cc",
+    "src/third_party/re2/re2/re2.h",
+    "src/third_party/re2/re2/regexp.cc",
+    "src/third_party/re2/re2/regexp.h",
+    "src/third_party/re2/re2/set.cc",
+    "src/third_party/re2/re2/set.h",
+    "src/third_party/re2/re2/simplify.cc",
+    "src/third_party/re2/re2/sparse_array.h",
+    "src/third_party/re2/re2/sparse_set.h",
+    "src/third_party/re2/re2/stringpiece.cc",
+    "src/third_party/re2/re2/stringpiece.h",
+    "src/third_party/re2/re2/tostring.cc",
+    "src/third_party/re2/re2/unicode_casefold.cc",
+    "src/third_party/re2/re2/unicode_casefold.h",
+    "src/third_party/re2/re2/unicode_groups.cc",
+    "src/third_party/re2/re2/unicode_groups.h",
+    "src/third_party/re2/re2/walker-inl.h",
+    "src/third_party/re2/util/benchmark.h",
+    "src/third_party/re2/util/flags.h",
+    "src/third_party/re2/util/logging.h",
+    "src/third_party/re2/util/malloc_counter.h",
+    "src/third_party/re2/util/mix.h",
+    "src/third_party/re2/util/mutex.h",
+    "src/third_party/re2/util/pcre.cc",
+    "src/third_party/re2/util/pcre.h",
+    "src/third_party/re2/util/rune.cc",
+    "src/third_party/re2/util/strutil.cc",
+    "src/third_party/re2/util/strutil.h",
+    "src/third_party/re2/util/test.h",
+    "src/third_party/re2/util/utf.h",
+    "src/third_party/re2/util/util.h",
+  ]
+  public_deps = []
+  public_configs = [ "..:grpc_re2_config" ]
+  configs -= [ "//gn/standalone:extra_warnings" ]
+}
+
+static_library("boringssl") {
   sources = [
     "src/third_party/boringssl-with-bazel/err_data.c",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/chacha/chacha-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/cipher_extra/aes128gcmsiv-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/cipher_extra/chacha20_poly1305_x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/aesni-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/ghash-ssse3-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/md5-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/p256-x86_64-asm.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/p256_beeu-x86_64-asm.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha1-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha256-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha512-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/x86_64-mont.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/x86_64-mont5.S",
+    "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/test/trampoline-x86_64.S",
     "src/third_party/boringssl-with-bazel/src/crypto/asn1/a_bitstr.c",
     "src/third_party/boringssl-with-bazel/src/crypto/asn1/a_bool.c",
     "src/third_party/boringssl-with-bazel/src/crypto/asn1/a_d2i_fp.c",
@@ -2943,6 +3025,7 @@
     "src/third_party/boringssl-with-bazel/src/crypto/fipsmodule/tls/kdf.c",
     "src/third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c",
     "src/third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c",
+    "src/third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S",
     "src/third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c",
     "src/third_party/boringssl-with-bazel/src/crypto/hrss/internal.h",
     "src/third_party/boringssl-with-bazel/src/crypto/internal.h",
@@ -5611,7 +5694,7 @@
   configs -= [ "//gn/standalone:extra_warnings" ]
 }
 
-source_set("grpc++") {
+static_library("grpc++") {
   sources = [
     "src/src/core/ext/transport/binder/client/binder_connector.cc",
     "src/src/core/ext/transport/binder/client/binder_connector.h",
@@ -6318,3 +6401,48 @@
   public_configs = [ "..:grpc_internal_config" ]
   configs -= [ "//gn/standalone:extra_warnings" ]
 }
+
+source_set("grpc_plugin_support") {
+  sources = [
+    "src/src/compiler/config.h",
+    "src/src/compiler/config_protobuf.h",
+    "src/src/compiler/cpp_generator.cc",
+    "src/src/compiler/cpp_generator.h",
+    "src/src/compiler/cpp_generator_helpers.h",
+    "src/src/compiler/cpp_plugin.h",
+    "src/src/compiler/csharp_generator.cc",
+    "src/src/compiler/csharp_generator.h",
+    "src/src/compiler/csharp_generator_helpers.h",
+    "src/src/compiler/generator_helpers.h",
+    "src/src/compiler/node_generator.cc",
+    "src/src/compiler/node_generator.h",
+    "src/src/compiler/node_generator_helpers.h",
+    "src/src/compiler/objective_c_generator.cc",
+    "src/src/compiler/objective_c_generator.h",
+    "src/src/compiler/objective_c_generator_helpers.h",
+    "src/src/compiler/php_generator.cc",
+    "src/src/compiler/php_generator.h",
+    "src/src/compiler/php_generator_helpers.h",
+    "src/src/compiler/protobuf_plugin.h",
+    "src/src/compiler/python_generator.cc",
+    "src/src/compiler/python_generator.h",
+    "src/src/compiler/python_generator_helpers.h",
+    "src/src/compiler/python_private_generator.h",
+    "src/src/compiler/ruby_generator.cc",
+    "src/src/compiler/ruby_generator.h",
+    "src/src/compiler/ruby_generator_helpers-inl.h",
+    "src/src/compiler/ruby_generator_map-inl.h",
+    "src/src/compiler/ruby_generator_string-inl.h",
+    "src/src/compiler/schema_interface.h",
+  ]
+  public_deps = [ "..:protoc_lib" ]
+  public_configs = [ "..:grpc_internal_config" ]
+  configs -= [ "//gn/standalone:extra_warnings" ]
+}
+
+executable("grpc_cpp_plugin") {
+  sources = [ "src/src/compiler/cpp_plugin.cc" ]
+  public_deps = [ ":grpc_plugin_support" ]
+  public_configs = [ "..:grpc_internal_config" ]
+  configs -= [ "//gn/standalone:extra_warnings" ]
+}
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index f41e959..b778d88 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -308,9 +308,10 @@
   enable_perfetto_llvm_demangle =
       enable_perfetto_trace_processor && perfetto_build_standalone
 
-  # Enables gRPC support. This is used as the RPC framework for cloud trace
-  # processor in open source but is disabled by default because of how
-  # heavyweight gRPC is.
+  # Enables gRPC in the Perfetto codebase. gRPC significantly increases build
+  # times and the general footprint of Perfetto. As it only required for
+  # cloud trace processor and even then only to build the final ready-to-ship
+  # binary, don't enable this by default.
   enable_perfetto_grpc = false
 }
 
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index d1794d5..f69d3ce 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -204,6 +204,40 @@
   }
 }
 
+# Generates .grpc.{h,cc} stubs for services defined in .proto files.
+# We require explicit opt-in as gRPC is very heavyweight so we do not
+# want accidental dependencies on this.
+if (enable_perfetto_grpc) {
+  template("perfetto_grpc_library") {
+    proto_library(target_name) {
+      proto_in_dir = perfetto_root_path
+      proto_out_dir = perfetto_root_path
+      propagate_imports_configs = false
+
+      perfetto_root_path = perfetto_root_path
+      generate_cc = false
+      generate_python = false
+      generator_plugin_label =
+          "$perfetto_root_path/buildtools/grpc:grpc_cpp_plugin"
+      generator_plugin_suffix = ".grpc.pb"
+      deps = [ "$perfetto_root_path/buildtools/grpc:grpc++" ]
+      public_configs = [ "$perfetto_root_path/buildtools:grpc_gen_config" ]
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
+      forward_variables_from(invoker,
+                             [
+                               "defines",
+                               "extra_configs",
+                               "include_dirs",
+                               "sources",
+                               "testonly",
+                               "visibility",
+                             ])
+    }
+  }
+}
+
 # The template used everywhere in the codebase.
 template("perfetto_proto_library") {
   if (defined(invoker.proto_generators)) {
diff --git a/include/perfetto/ext/base/threading/BUILD.gn b/include/perfetto/ext/base/threading/BUILD.gn
index ab12670..cb11115 100644
--- a/include/perfetto/ext/base/threading/BUILD.gn
+++ b/include/perfetto/ext/base/threading/BUILD.gn
@@ -15,7 +15,10 @@
 import("../../../../../gn/perfetto.gni")
 
 source_set("threading") {
-  sources = [ "thread_pool.h" ]
+  sources = [
+    "channel.h",
+    "thread_pool.h",
+  ]
   deps = [
     "..:base",
     "../../../../../gn:default_deps",
diff --git a/include/perfetto/ext/base/threading/channel.h b/include/perfetto/ext/base/threading/channel.h
new file mode 100644
index 0000000..d117ff0
--- /dev/null
+++ b/include/perfetto/ext/base/threading/channel.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 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_EXT_BASE_THREADING_CHANNEL_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREADING_CHANNEL_H_
+
+#include <mutex>
+
+#include "perfetto/base/compiler.h"
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/ext/base/circular_queue.h"
+#include "perfetto/ext/base/event_fd.h"
+#include "perfetto/ext/base/optional.h"
+
+namespace perfetto {
+namespace base {
+
+// Unidirectional conduit used to send values between threads with a fixed-sized
+// buffer in-between.
+//
+// When a channel is read from when empty or written to when full, the operation
+// will not succeed and the caller can choose to a) abandon the operation,
+// or b) use |read_fd| or |write_fd| (as appropriate) which will be become
+// "ready" (i.e. base::TaskRunner watches will fire) when the operation would
+// succeed.
+//
+// A channel is very similar to a Unix pipe except with the values being sent
+// a) not needing to be serializable b) data does not go through the kernel.
+template <typename T>
+class Channel {
+ public:
+  struct ReadResult {
+    ReadResult(base::Optional<T> _item, bool _is_closed)
+        : item(std::move(_item)), is_closed(_is_closed) {}
+
+    bool operator==(const ReadResult& res) const {
+      return item == res.item && is_closed == res.is_closed;
+    }
+
+    // The item read from the channel or base::nullopt if the channel is empty.
+    // If so, callers can use |read_fd| to be notified when a read operation
+    // would succeed.
+    base::Optional<T> item;
+
+    // Indicates the channel is closed. Readers can continue to read from the
+    // channel and any buffered elements will be correctly returned. Moreover,
+    // any future reads will also have |is_closed| == true and |read_fd| will be
+    // ready forever.
+    //
+    // Once a ReadResult is returned with |item| == base::nullopt and
+    // |is_closed| == true, no further values will ever be returned.
+    bool is_closed;
+  };
+  struct WriteResult {
+    WriteResult(bool _success, bool _is_closed)
+        : success(std::move(_success)), is_closed(_is_closed) {}
+
+    bool operator==(const WriteResult& res) const {
+      return success == res.success && is_closed == res.is_closed;
+    }
+
+    // Returns whether the write to the channel was successful. If this is
+    // false, callers can use |write_fd| to be notified when future writes
+    // would succeed. Note that callers should also check |is_closed| as another
+    // writer may have closed the channel.
+    bool success;
+
+    // Indicates that the channel is closed. If this value is true, |success|
+    // will be |false| Moreover, any further writes will continue to return
+    // |success| == false, |is_closed| == true and |write_fd| will be ready
+    // forever.
+    bool is_closed;
+  };
+
+  // Creates a channel with a capacity at least as large as |capacity_hint|. The
+  // capacity *must* be greater than zero.
+  //
+  // Note that it's possible that a capacity > |capacity_hint| will be chosen:
+  // it is implementation defined when this might happen.
+  explicit Channel(uint32_t capacity_hint) : elements_(capacity_hint) {
+    PERFETTO_DCHECK(capacity_hint > 0);
+
+    // It's very important that we make sure |write_fd| is ready to avoid
+    // deadlocks.
+    write_fd_.Notify();
+  }
+
+  // Attempts to read from the channel and returns the result of the attempt.
+  // See |ReadResult| for more information on the result.
+  PERFETTO_WARN_UNUSED_RESULT ReadResult ReadNonBlocking() {
+    std::lock_guard<std::mutex> lock(mutex_);
+    if (elements_.empty()) {
+      return ReadResult(base::nullopt, is_closed_);
+    }
+    if (elements_.capacity() == elements_.size()) {
+      write_fd_.Notify();
+    }
+    T value = std::move(elements_.front());
+    elements_.pop_front();
+    if (!is_closed_ && elements_.empty()) {
+      read_fd_.Clear();
+    }
+    return ReadResult(std::move(value), is_closed_);
+  }
+
+  // Attempts to write to the channel and returns the result of the attempt.
+  // See |WriteResult| for more information on the result.
+  //
+  // IMPORTANT: if this function returns |success| == false, |element| *will
+  // not* be modified. This allows the caller to try again with the same value.
+  PERFETTO_WARN_UNUSED_RESULT WriteResult WriteNonBlocking(T&& element) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    if (is_closed_) {
+      return WriteResult{false, true};
+    }
+    if (elements_.size() == elements_.capacity()) {
+      return WriteResult{false, false};
+    }
+    if (elements_.empty()) {
+      read_fd_.Notify();
+    }
+    elements_.emplace_back(std::move(element));
+    if (elements_.size() == elements_.capacity()) {
+      write_fd_.Clear();
+    }
+    return WriteResult{true, false};
+  }
+
+  // Closes the channel for to any further writes.
+  //
+  // Note: this function will make both |read_fd| and |write_fd| ready to
+  // avoid deadlocks. Callers should correctly handle |is_closed| being
+  // false from |ReadNonBlocking| and |WriteNonBlocking| to stop watching the
+  // fds to avoid poll returning immediately.
+  //
+  // We prefer this behaviour as it's a lot more obvious something is wrong when
+  // it spins and takes 100% CPU rather than silently deadlocking.
+  void Close() {
+    std::lock_guard<std::mutex> lock(mutex_);
+    is_closed_ = true;
+
+    // Make both fds ready to avoid deadlocks.
+    read_fd_.Notify();
+    write_fd_.Notify();
+  }
+
+  // Notification FD for when |ReadNonBlocking| would succeed. Can be useful to
+  // pass to AddFileDescriptorWatch to read data from the channel.
+  base::PlatformHandle read_fd() const { return read_fd_.fd(); }
+
+  // Notification FD for when |WriteNonBlocking| would succeed. Can be useful to
+  // pass to AddFileDescriptorWatch to send data through the channel.
+  base::PlatformHandle write_fd() const { return write_fd_.fd(); }
+
+ private:
+  std::mutex mutex_;
+  base::CircularQueue<T> elements_;
+  bool is_closed_ = false;
+
+  base::EventFd read_fd_;
+  base::EventFd write_fd_;
+};
+
+}  // namespace base
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_EXT_BASE_THREADING_CHANNEL_H_
diff --git a/protos/perfetto/common/BUILD.gn b/protos/perfetto/common/BUILD.gn
index 5ecc0de..31d4842 100644
--- a/protos/perfetto/common/BUILD.gn
+++ b/protos/perfetto/common/BUILD.gn
@@ -36,4 +36,10 @@
     "tracing_service_state.proto",
     "track_event_descriptor.proto",
   ]
+  proto_generators = [
+    "lite",
+    "zero",
+    "cpp",
+    "source_set",
+  ]
 }
diff --git a/protos/perfetto/trace_processor/BUILD.gn b/protos/perfetto/trace_processor/BUILD.gn
index c8671b1..4ba70c7 100644
--- a/protos/perfetto/trace_processor/BUILD.gn
+++ b/protos/perfetto/trace_processor/BUILD.gn
@@ -17,10 +17,11 @@
 
 perfetto_proto_library("@TYPE@") {
   proto_generators = [
+    "lite",
     "zero",
     "source_set",
   ]
-  deps = [ "../common:zero" ]  # ../common:zero needed for descriptor.proto.
+  deps = [ "../common:@TYPE@" ]  # needed for descriptor.proto.
   sources = []
   foreach(source, trace_processor_protos) {
     sources += [ "$source.proto" ]
@@ -34,3 +35,10 @@
   ]
   sources = [ "metrics_impl.proto" ]
 }
+
+if (enable_perfetto_grpc) {
+  perfetto_grpc_library("cloud_trace_processor_grpc") {
+    deps = [ ":lite" ]
+    sources = [ "cloud_trace_processor.proto" ]
+  }
+}
diff --git a/protos/perfetto/trace_processor/cloud_trace_processor.proto b/protos/perfetto/trace_processor/cloud_trace_processor.proto
new file mode 100644
index 0000000..b009fe3
--- /dev/null
+++ b/protos/perfetto/trace_processor/cloud_trace_processor.proto
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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;
+
+service CloudTraceProcessorWorkerService {}
\ No newline at end of file
diff --git a/protos/perfetto/trace_processor/proto_files.gni b/protos/perfetto/trace_processor/proto_files.gni
index b46da47..4c9ae21 100644
--- a/protos/perfetto/trace_processor/proto_files.gni
+++ b/protos/perfetto/trace_processor/proto_files.gni
@@ -15,6 +15,7 @@
 # This variable is used both by ./BUILD.gn (for the C++ proto codegen) and by
 # //ui/BUIlD.gn (for the TypeScript/JS proto codegen).
 trace_processor_protos = [
+  "cloud_trace_processor",
   "trace_processor",
   "metatrace_categories",
 ]
diff --git a/src/base/threading/BUILD.gn b/src/base/threading/BUILD.gn
index ba709e7..b1e01e3 100644
--- a/src/base/threading/BUILD.gn
+++ b/src/base/threading/BUILD.gn
@@ -28,6 +28,8 @@
     "../../../gn:default_deps",
     "../../../gn:gtest_and_gmock",
   ]
-
-  sources = [ "thread_pool_unittest.cc" ]
+  sources = [
+    "channel_unittest.cc",
+    "thread_pool_unittest.cc",
+  ]
 }
diff --git a/src/base/threading/channel_unittest.cc b/src/base/threading/channel_unittest.cc
new file mode 100644
index 0000000..21c5ce7
--- /dev/null
+++ b/src/base/threading/channel_unittest.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2023 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/ext/base/threading/channel.h"
+#include <sys/poll.h>
+#include <memory>
+
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/utils.h"
+#include "test/gtest_and_gmock.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <Windows.h>
+#include <synchapi.h>
+#else
+#include <poll.h>
+#endif
+
+namespace perfetto {
+namespace base {
+namespace {
+
+using ReadResult = Channel<int>::ReadResult;
+using WriteResult = Channel<int>::WriteResult;
+
+bool IsReady(base::PlatformHandle fd) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+  std::array<base::PlatformHandle, 1> poll_fds{fd};
+  DWORD ret =
+      WaitForMultipleObjects(static_cast<DWORD>(poll_fds.size()), &poll_fds[0],
+                             /*bWaitAll=*/false, 0);
+  PERFETTO_CHECK(ret == WAIT_TIMEOUT || ret == 0);
+  return ret == 0;
+#else
+  std::array<struct pollfd, 1> poll_fds;
+  poll_fds[0].fd = fd;
+  poll_fds[0].events = POLLIN | POLLHUP;
+  poll_fds[0].revents = 0;
+
+  int ret = PERFETTO_EINTR(
+      poll(&poll_fds[0], static_cast<nfds_t>(poll_fds.size()), 0));
+  PERFETTO_CHECK(ret == 0 || ret == 1);
+  return ret == 1;
+#endif
+}
+
+TEST(ChannelUnittest, SingleElementBuffer) {
+  Channel<int> channel(1);
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+  ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
+
+  ASSERT_FALSE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, MultiElementBuffer) {
+  Channel<int> channel(2);
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(true, false));
+  ASSERT_FALSE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(101, false));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, CloseEmptyChannel) {
+  Channel<int> channel(1);
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+
+  channel.Close();
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, WriteDoesNotMoveIfFalse) {
+  Channel<std::unique_ptr<int>> channel(1);
+
+  std::unique_ptr<int> first(new int(100));
+  int* first_ptr = first.get();
+  ASSERT_EQ(channel.WriteNonBlocking(std::move(first)),
+            Channel<std::unique_ptr<int>>::WriteResult(true, false));
+  ASSERT_EQ(first.get(), nullptr);
+
+  std::unique_ptr<int> second(new int(101));
+  ASSERT_EQ(channel.WriteNonBlocking(std::move(second)),
+            Channel<std::unique_ptr<int>>::WriteResult(false, false));
+  ASSERT_NE(second.get(), nullptr);
+  ASSERT_EQ(*second, 101);
+
+  auto res = channel.ReadNonBlocking();
+  ASSERT_EQ(res.item->get(), first_ptr);
+}
+
+TEST(ChannelUnittest, ReadAfterClose) {
+  Channel<int> channel(1);
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+  ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+  channel.Close();
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+}
+
+TEST(ChannelUnittest, WriteAfterClose) {
+  Channel<int> channel(1);
+  ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+  ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+  channel.Close();
+
+  ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, true));
+}
+
+TEST(ChannelUnittest, EmptyClosedChannel) {
+  Channel<int> channel(1);
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  channel.Close();
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, FullClosedChannel) {
+  Channel<int> channel(1);
+  ASSERT_FALSE(IsReady(channel.read_fd()));
+  ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+  ASSERT_FALSE(IsReady(channel.write_fd()));
+  channel.Close();
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+
+  ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
+  ASSERT_TRUE(IsReady(channel.write_fd()));
+  ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+}  // namespace
+}  // namespace base
+}  // namespace perfetto
diff --git a/tools/gen_grpc_build_gn.py b/tools/gen_grpc_build_gn.py
index 706e062..48993ca 100755
--- a/tools/gen_grpc_build_gn.py
+++ b/tools/gen_grpc_build_gn.py
@@ -1,4 +1,18 @@
 #!/usr/bin/env python3
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 import json
 import os
 import subprocess
@@ -8,27 +22,6 @@
 
 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
-IGNORE_LIST = set([
-    'grpcpp_channelz',
-    'grpc++_reflection',
-    'benchmark_helpers',
-    'boringssl_test_util',
-])
-
-SOURCE_SET_TARGET = """
-source_set("{name}") {{
-  sources = {srcs}
-  public_deps = {deps}
-  public_configs = ["..:{config_name}"]
-  configs -= [ "//gn/standalone:extra_warnings" ]
-}}"""
-
-
-def grpc_relpath(*segments: str) -> str:
-  '''From path segments to GRPC root, returns the absolute path.'''
-  return os.path.join(ROOT_DIR, 'buildtools', 'grpc', 'src', *segments)
-
-
 GRPC_GN_HEADER = '''
 #
 # DO NOT EDIT. AUTOGENERATED file
@@ -37,45 +30,117 @@
 # tools/gen_grpc_build_gn.py > buildtools/grpc/BUILD.gn
 #
 
+import("../../gn/perfetto.gni")
+
 # Prevent the gRPC from being depended upon without explicitly being opted in.
 assert(enable_perfetto_grpc)
+
+# BoringSSL has assembly code which is tied to platform-specific. For now, we
+# only care about Linux x64 so assert this as the case.
+assert(is_linux && current_cpu == "x64")
 '''
 
+TARGET_TEMPLATE = """
+{target_type}("{name}") {{
+  sources = {srcs}
+  public_deps = {deps}
+  public_configs = ["..:{config_name}"]
+  configs -= [ "//gn/standalone:extra_warnings" ]
+}}"""
+
+LIBRARY_IGNORE_LIST = set([
+    'grpcpp_channelz',
+    'grpc++_reflection',
+    'benchmark_helpers',
+    'boringssl_test_util',
+])
+
+TARGET_ALLOW_LIST = set([
+    'grpc_cpp_plugin',
+])
+
+STATIC_LIBRARY_TARGETS = set([
+    'upb',
+    're2',
+    'boringssl',
+    'grpc++',
+])
+
+
+def grpc_relpath(*segments: str) -> str:
+  '''From path segments to GRPC root, returns the absolute path.'''
+  return os.path.join(ROOT_DIR, 'buildtools', 'grpc', 'src', *segments)
+
+
 GRPC_BUILD_YAML = grpc_relpath('build_autogenerated.yaml')
 ABSL_GEN_BUILD_YAML = grpc_relpath('src', 'abseil-cpp', 'gen_build_yaml.py')
 UPB_GEN_BUILD_YAML = grpc_relpath('src', 'upb', 'gen_build_yaml.py')
+RE2_GEN_BUILD_YAML = grpc_relpath('src', 're2', 'gen_build_yaml.py')
 BSSL_GEN_BUILD_YAML = grpc_relpath('src', 'boringssl', 'gen_build_yaml.py')
 
 
-def bazel_label_to_gn_target(dep: str):
-  '''Converts a Bazel label name into a gn target name.'''
-  if dep == 'libssl':
-    return 'boringssl'
-  return dep.replace('/', '_').replace(':', '_')
-
-
 def gen_grpc_dep_yaml(gen_path: str) -> Dict[str, Any]:
   '''Invokes a gen_build_yaml.py file for creating YAML for gRPC deps.'''
   return yaml.safe_load(subprocess.check_output(['python3', gen_path]))
 
 
-def yaml_to_gn_targets(desc: Dict[str, Any], build_type: str, config_name: str,
-                       out: List[str]):
+def bazel_label_to_gn_target(dep: str) -> str:
+  '''Converts a Bazel label name into a gn target name.'''
+  if dep == 'libssl':
+    return 'boringssl'
+  return dep.replace('/', '_').replace(':', '_')
+
+
+def get_deps_for_target(target: str) -> List[str]:
+  if target == 'grpc_plugin_support':
+    return ['..:protoc_lib']
+  return []
+
+
+def get_library_target_type(target: str) -> str:
+  if target in STATIC_LIBRARY_TARGETS:
+    return 'static_library'
+  return 'source_set'
+
+
+def yaml_to_gn_targets(desc: Dict[str, Any], build_types: list[str],
+                       config_name: str) -> List[str]:
   '''Given a gRPC YAML description of the build graph, generates GN targets.'''
+  out = []
   for lib in desc['libs']:
-    if lib['build'] != build_type:
+    if lib['build'] not in build_types:
       continue
-    if lib['name'] in IGNORE_LIST:
+    if lib['name'] in LIBRARY_IGNORE_LIST:
       continue
-    srcs = json.dumps([f'src/{file}' for file in lib['src'] + lib['headers']])
-    deps = json.dumps(
-        [f':{bazel_label_to_gn_target(dep)}' for dep in lib.get('deps', [])])
-    source_set_target = SOURCE_SET_TARGET.format(
+    srcs = [f'src/{file}' for file in lib['src'] + lib['headers']]
+    if 'asm_src' in lib:
+      srcs += [f'src/{file}' for file in lib['asm_src']['crypto_linux_x86_64']]
+    deps = [f':{bazel_label_to_gn_target(dep)}' for dep in lib.get('deps', [])
+           ] + get_deps_for_target(lib['name'])
+    library_target = TARGET_TEMPLATE.format(
         name=bazel_label_to_gn_target(lib['name']),
         config_name=config_name,
+        srcs=json.dumps(srcs),
+        deps=json.dumps(deps),
+        target_type=get_library_target_type(lib['name']))
+    out.append(library_target)
+
+  for bin in desc.get('targets', []):
+    if bin['build'] not in build_types:
+      continue
+    if bin['name'] not in TARGET_ALLOW_LIST:
+      continue
+    srcs = json.dumps([f'src/{file}' for file in bin['src'] + bin['headers']])
+    deps = [f':{bazel_label_to_gn_target(dep)}' for dep in bin.get('deps', [])
+           ] + get_deps_for_target(bin['name'])
+    binary_target = TARGET_TEMPLATE.format(
+        name=bazel_label_to_gn_target(bin['name']),
+        config_name=config_name,
         srcs=srcs,
-        deps=deps)
-    out.append(source_set_target)
+        deps=json.dumps(deps),
+        target_type='executable')
+    out.append(binary_target)
+  return out
 
 
 def main():
@@ -83,20 +148,26 @@
 
   # Generate absl rules
   absl_yaml = gen_grpc_dep_yaml(ABSL_GEN_BUILD_YAML)
-  yaml_to_gn_targets(absl_yaml, 'private', 'grpc_absl_config', out)
+  out.extend(yaml_to_gn_targets(absl_yaml, ['private'], 'grpc_absl_config'))
 
   # Generate upb rules
   upb_yaml = gen_grpc_dep_yaml(UPB_GEN_BUILD_YAML)
-  yaml_to_gn_targets(upb_yaml, 'all', 'grpc_upb_config', out)
+  out.extend(yaml_to_gn_targets(upb_yaml, ['all'], 'grpc_upb_config'))
+
+  # Generate re2 rules
+  re2_yaml = gen_grpc_dep_yaml(RE2_GEN_BUILD_YAML)
+  out.extend(yaml_to_gn_targets(re2_yaml, ['private'], 'grpc_re2_config'))
 
   # Generate boringssl rules
   boringssl_yaml = gen_grpc_dep_yaml(BSSL_GEN_BUILD_YAML)
-  yaml_to_gn_targets(boringssl_yaml, 'private', 'grpc_boringssl_config', out)
+  out.extend(
+      yaml_to_gn_targets(boringssl_yaml, ['private'], 'grpc_boringssl_config'))
 
   # Generate grpc rules
   with open(GRPC_BUILD_YAML, 'r', encoding='utf-8') as f:
     grpc_yaml = yaml.safe_load(f.read())
-  yaml_to_gn_targets(grpc_yaml, 'all', 'grpc_internal_config', out)
+  out.extend(
+      yaml_to_gn_targets(grpc_yaml, ['all', 'protoc'], 'grpc_internal_config'))
 
   print(GRPC_GN_HEADER)
   print('\n'.join(out))
diff --git a/tools/java_heap_dump b/tools/java_heap_dump
index eebf074..c14dde4 100755
--- a/tools/java_heap_dump
+++ b/tools/java_heap_dump
@@ -35,7 +35,7 @@
 }
 '''
 
-CFG_IDENT = '      '
+CFG_INDENT = '      '
 CFG = '''buffers {{
   size_kb: {size_kb}
   fill_policy: DISCARD
@@ -63,6 +63,9 @@
 data_sources: {{
     config {{
         name: "android.java_hprof.oom"
+        java_hprof_config {{
+{process_cfg}
+        }}
     }}
 }}
 
@@ -133,12 +136,12 @@
       except ValueError:
         print("FATAL: invalid PID %s" % pid, file=sys.stderr)
         fail = True
-      target_cfg += '{}pid: {}\n'.format(CFG_IDENT, pid)
+      target_cfg += '{}pid: {}\n'.format(CFG_INDENT, pid)
   if args.name:
     for name in args.name.split(','):
-      target_cfg += '{}process_cmdline: "{}"\n'.format(CFG_IDENT, name)
+      target_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name)
   if args.dump_smaps:
-    target_cfg += '{}dump_smaps: true\n'.format(CFG_IDENT)
+    target_cfg += '{}dump_smaps: true\n'.format(CFG_INDENT)
 
   if fail:
     return None
@@ -168,8 +171,13 @@
         file=sys.stderr)
     return None
 
-  if args.pid or args.name:
-    print("FATAL: Specifying process not supported in OOM mode",
+  if args.pid:
+    print("FATAL: Specifying pid not supported in OOM mode",
+        file=sys.stderr)
+    return None
+
+  if not args.name:
+    print("FATAL: Must specify process in OOM mode (use --name '*' to match all)",
         file=sys.stderr)
     return None
 
@@ -183,9 +191,14 @@
         file=sys.stderr)
     return None
 
+  process_cfg = ''
+  for name in args.name.split(','):
+    process_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name)
+
   return OOM_CFG.format(
       size_kb=convert_size_to_kb(args.buffer_size),
-      wait_duration_ms=args.oom_wait_seconds * 1000)
+      wait_duration_ms=args.oom_wait_seconds * 1000,
+      process_cfg=process_cfg)
 
 
 def main(argv):